[
  {
    "path": ".github/FUNDING.yml",
    "content": "custom: http://doc.ruoyi.vip/ruoyi/other/donate.html\n"
  },
  {
    "path": ".gitignore",
    "content": "######################################################################\n# Build Tools\n\n.gradle\n/build/\n!gradle/wrapper/gradle-wrapper.jar\n\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n\n######################################################################\n# IDE\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### JRebel ###\nrebel.xml\n### NetBeans ###\nnbproject/private/\nbuild/*\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/\n\n######################################################################\n# Others\n*.log\n*.xml.versionsBackup\n*.swp\n\n!*/build/*.java\n!*/build/*.html\n!*/build/*.xml"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\r\n\r\nCopyright (c) 2018 RuoYi\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of\r\nthis software and associated documentation files (the \"Software\"), to deal in\r\nthe Software without restriction, including without limitation the rights to\r\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\nthe Software, and to permit persons to whom the Software is furnished to do so,\r\nsubject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\r\n\t<img alt=\"logo\" src=\"https://oscimg.oschina.net/oscnet/up-dd77653d7c9f197dd9d93684f3c8dcfbab6.png\">\r\n</p>\r\n<h1 align=\"center\" style=\"margin: 30px 0 30px; font-weight: bold;\">RuoYi v4.8.2</h1>\r\n<h4 align=\"center\">基于SpringBoot开发的轻量级Java快速开发框架</h4>\r\n<p align=\"center\">\r\n\t<a href=\"https://gitee.com/y_project/RuoYi/stargazers\"><img src=\"https://gitee.com/y_project/RuoYi/badge/star.svg?theme=gvp\"></a>\r\n\t<a href=\"https://gitee.com/y_project/RuoYi\"><img src=\"https://img.shields.io/badge/RuoYi-v4.8.2-brightgreen.svg\"></a>\r\n\t<a href=\"https://gitee.com/y_project/RuoYi/blob/master/LICENSE\"><img src=\"https://img.shields.io/github/license/mashape/apistatus.svg\"></a>\r\n</p>\r\n\r\n## 平台简介\r\n\r\n一直想做一款后台管理系统，看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了若依。她可以用于所有的Web应用程序，如网站管理后台，网站会员中心，CMS，CRM，OA。所有前端后台代码封装过后十分精简易上手，出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。\r\n\r\n性别男，若依是给女儿取的名字（寓意：你若不离不弃，我必生死相依）\r\n\r\n若依是一套全部开源的快速开发平台，毫无保留给个人及企业免费使用。\r\n\r\n* 前端基于 [Hplus(H+)](https://gitee.com/hplus_admin/hplus) 后台主题 UI 框架。\r\n* 前后端分离版本，请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)，微服务版本，请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)\r\n* 阿里云折扣场：[点我进入](http://aly.ruoyi.vip)，腾讯云秒杀场：[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;\r\n\r\n## 版本分支\r\n\r\nRuoYi 框架提供 Spring Boot 2.x / 3.x / 4.x 多版本分支的并行维护。\r\n\r\n| 名称              | 说明                      | 地址                                                |\r\n| :---------------- | :------------------------ | :-------------------------------------------------- |\r\n| master 默认分支   | Spring Boot 4.x (JDK 17+) | https://gitee.com/y_project/RuoYi                   |\r\n| springboot3 分支  | Spring Boot 3.x (JDK 17+) | https://gitee.com/y_project/RuoYi/tree/springboot3  |\r\n| springboot2 分支  | Spring Boot 2.x (JDK 8+)  | https://gitee.com/y_project/RuoYi/tree/springboot2  |\r\n\r\n## 内置功能\r\n\r\n1.  用户管理：用户是系统操作者，该功能主要完成系统用户配置。\r\n2.  部门管理：配置系统组织机构（公司、部门、小组），树结构展现支持数据权限。\r\n3.  岗位管理：配置系统用户所属担任职务。\r\n4.  菜单管理：配置系统菜单，操作权限，按钮权限标识等。\r\n5.  角色管理：角色菜单权限分配、设置角色按机构进行数据范围权限划分。\r\n6.  字典管理：对系统中经常使用的一些较为固定的数据进行维护。\r\n7.  参数管理：对系统动态配置常用参数。\r\n8.  通知公告：系统通知公告信息发布维护。\r\n9.  操作日志：系统正常操作日志记录和查询；系统异常信息日志记录和查询。\r\n10. 登录日志：系统登录日志记录查询包含登录异常。\r\n11. 在线用户：当前系统中活跃用户状态监控。\r\n12. 定时任务：在线（添加、修改、删除)任务调度包含执行结果日志。\r\n13. 代码生成：前后端代码的生成（java、html、xml、sql）支持CRUD下载 。\r\n14. 系统接口：根据业务代码自动生成相关的api接口文档。\r\n15. 服务监控：监视当前系统CPU、内存、磁盘、堆栈等相关信息。\r\n16. 缓存监控：对系统的缓存查询，删除、清空等操作。\r\n17. 在线构建器：拖动表单元素生成相应的HTML代码。\r\n18. 连接池监视：监视当前系统数据库连接池状态，可进行分析SQL找出系统性能瓶颈。\r\n\r\n## 在线体验\r\n\r\n- admin/admin123  \r\n- 陆陆续续收到一些打赏，为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。\r\n\r\n演示地址：http://ruoyi.vip  \r\n文档地址：http://doc.ruoyi.vip\r\n\r\n## 演示图\r\n\r\n<table>\r\n    <tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-42e518aa72a24d228427a1261cb3679f395.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-7f20dd0edba25e5187c5c4dd3ec7d3d9797.png\"/></td>\r\n    </tr>\r\n    <tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-2dae3d87f6a8ca05057db059cd9a411d51d.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-ea4d98423471e55fba784694e45d12bd4bb.png\"/></td>\r\n    </tr>\r\n    <tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-7f6c6e9f5873efca09bd2870ee8468b8fce.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-c708b65f2c382a03f69fe1efa8d341e6cff.png\"/></td>\r\n    </tr>\r\n\t<tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-9ab586c47dd5c7b92bca0d727962c90e3b8.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-ef954122a2080e02013112db21754b955c6.png\"/></td>\r\n    </tr>\t \r\n    <tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-088edb4d531e122415a1e2342bccb1a9691.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-f886fe19bd820c0efae82f680223cac196c.png\"/></td>\r\n    </tr>\r\n\t<tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-c7a2eb71fa65d6e660294b4bccca613d638.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-e60137fb0787defe613bd83331dc4755a70.png\"/></td>\r\n    </tr>\r\n\t<tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-7c51c1b5758f0a0f92ed3c60469b7526f9f.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-15181aed45bb2461aa97b594cbf2f86ea5f.png\"/></td>\r\n    </tr>\r\n\t<tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-83326ad52ea63f67233d126226738054d98.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-3bd6d31e913b70df00107db51d64ef81df7.png\"/></td>\r\n    </tr>\r\n\t<tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-70a2225836bc82042a6785edf6299e2586a.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-0184d6ab01fdc6667a14327fcaf8b46345d.png\"/></td>\r\n    </tr>\r\n\t<tr>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-64d8086dc2c02c8f71170290482f7640098.png\"/></td>\r\n        <td><img src=\"https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png\"/></td>\r\n    </tr>\r\n</table>\r\n\r\n\r\n## 若依交流群\r\n\r\nQQ群： [![加入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)  [![加入QQ群](https://img.shields.io/badge/已满-143151071-blue.svg)](https://jq.qq.com/?_wv=1027&k=4NsjKbtU)  [![加入QQ群](https://img.shields.io/badge/已满-158781320-blue.svg)](https://jq.qq.com/?_wv=1027&k=VD2pkz2G)  [![加入QQ群](https://img.shields.io/badge/已满-201531282-blue.svg)](https://jq.qq.com/?_wv=1027&k=HlshFwkJ)  [![加入QQ群](https://img.shields.io/badge/已满-101526938-blue.svg)](https://jq.qq.com/?_wv=1027&k=0ARRrO9V)  [![加入QQ群](https://img.shields.io/badge/已满-264355400-blue.svg)](https://jq.qq.com/?_wv=1027&k=up9k3ZXJ)  [![加入QQ群](https://img.shields.io/badge/已满-298522656-blue.svg)](https://jq.qq.com/?_wv=1027&k=540WfdEr)  [![加入QQ群](https://img.shields.io/badge/已满-139845794-blue.svg)](https://jq.qq.com/?_wv=1027&k=ss91fC4t)  [![加入QQ群](https://img.shields.io/badge/已满-185760789-blue.svg)](https://jq.qq.com/?_wv=1027&k=Cqd66IKe) [![加入QQ群](https://img.shields.io/badge/已满-175104288-blue.svg)](https://jq.qq.com/?_wv=1027&k=7FplYUnR) [![加入QQ群](https://img.shields.io/badge/已满-174942938-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=lqMHu_5Fskm7H2S1vNAQTtzAUokVydwc&authKey=ptw0Fpch5pbNocML3CIJKKqZBaq2DI7cusKuzIgfMNiY3t9Pvd9hP%2BA8WYx3yaY1&noverify=0&group_code=174942938) [![加入QQ群](https://img.shields.io/badge/已满-287843737-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=blYlRDmwZXSXI5pVrPPU7ZJ1stFJ6Q2Q&authKey=ForGBWffHVlPt9NE3d7g4DoOIouBh%2BqvAj2lp1CLReHfZAUaK7SRrdwsChKpRJDJ&noverify=0&group_code=287843737) [![加入QQ群](https://img.shields.io/badge/已满-232896766-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=KTVAIhggR3rR3uZWK9A8kR4yYNREQ4jo&authKey=An4DUV9e7uK8I8VgBbp949z0ypQoDrOoqvVg%2FWOr2vuNNDMZUAMPvqHor6TFMIgz&noverify=0&group_code=232896766) [![加入QQ群](https://img.shields.io/badge/已满-180208928-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XwhV8deuZXt__yteR1clNanVSXzA-ugq&authKey=ezgwKqEZPdP%2FgC9I03OBkJb%2Biii8yvVfwrcQuu0%2FL6ILXcRdHYDBFKCXeoeBT0E6&noverify=0&group_code=180208928) [![加入QQ群](https://img.shields.io/badge/已满-140284548-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=WqsGDxpGkqOPeWGOf3I32f_rXxdhqYNr&authKey=kvdF5df7PO9bzWxmixKhZN6ShsECBiuGUmmzTZBWVr2MVOfJ8%2F4oD0Gws0rbgYfz&noverify=0&group_code=140284548) [![加入QQ群](https://img.shields.io/badge/177203794-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=z9z9jkkkinfAElKZk2FXqlN4XIXlXsMi&authKey=Sm9XMTV%2FFyANBrv9rVpMfMNcX4v1lVah3795O9VclQwU4DNzQcT5BLXTmTBouIkM&noverify=0&group_code=177203794)"
  },
  {
    "path": "bin/clean.bat",
    "content": "@echo off\necho.\necho [Ϣ] target·\necho.\n\n%~d0\ncd %~dp0\n\ncd ..\ncall mvn clean\n\npause"
  },
  {
    "path": "bin/package.bat",
    "content": "@echo off\necho.\necho [Ϣ] Weḅwar/jarļ\necho.\n\n%~d0\ncd %~dp0\n\ncd ..\ncall mvn clean package -Dmaven.test.skip=true\n\npause"
  },
  {
    "path": "bin/run.bat",
    "content": "@echo off\necho.\necho [Ϣ] ʹJarWeb̡\necho.\n\ncd %~dp0\ncd ../ruoyi-admin/target\n\nset JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m\n\njava -jar %JAVA_OPTS% ruoyi-admin.jar\n\ncd bin\npause"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.ruoyi</groupId>\n    <artifactId>ruoyi</artifactId>\n    <version>4.8.2</version>\n\n    <name>ruoyi</name>\n    <url>http://www.ruoyi.vip</url>\n    <description>若依管理系统</description>\n    \n    <properties>\n        <ruoyi.version>4.8.2</ruoyi.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>17</java.version>\n        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>\n        <spring-boot.version>4.0.3</spring-boot.version>\n        <shiro.version>2.1.0</shiro.version>\n        <mybatis-spring-boot.version>4.0.1</mybatis-spring-boot.version>\n        <thymeleaf.extras.shiro.version>2.1.0</thymeleaf.extras.shiro.version>\n        <druid.version>1.2.28</druid.version>\n        <yauaa.version>8.1.0</yauaa.version>\n        <kaptcha.version>2.3.3</kaptcha.version>\n        <pagehelper.boot.version>2.1.1</pagehelper.boot.version>\n        <fastjson.version>1.2.83</fastjson.version>\n        <oshi.version>6.10.0</oshi.version>\n        <commons.io.version>2.21.0</commons.io.version>\n        <poi.version>4.1.2</poi.version>\n        <velocity.version>2.3</velocity.version>\n        <springdoc.version>3.0.2</springdoc.version>\n    </properties>\n\n    <!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n\n            <!-- SpringBoot的依赖配置 -->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n\n            <!-- 阿里数据库连接池 -->\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>druid-spring-boot-4-starter</artifactId>\n                <version>${druid.version}</version>\n            </dependency>\n            \n            <!-- 验证码 -->\n            <dependency>\n                <groupId>pro.fessional</groupId>\n                <artifactId>kaptcha</artifactId>\n                <version>${kaptcha.version}</version>\n            </dependency>\n\n            <!-- Shiro核心框架 -->\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-core</artifactId>\n                <classifier>jakarta</classifier>\n                <version>${shiro.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-web</artifactId>\n                <classifier>jakarta</classifier>\n                <version>${shiro.version}</version>\n            </dependency>\n\n            <!-- Shiro使用Spring框架 -->\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-spring</artifactId>\n                <classifier>jakarta</classifier>\n                <version>${shiro.version}</version>\n                <!-- 排除仍使用了javax.servlet的依赖 -->\n                <exclusions>\n                    <exclusion>\n                        <groupId>org.apache.shiro</groupId>\n                        <artifactId>shiro-web</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n\n            <!-- Shiro使用EhCache缓存框架 -->\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-ehcache</artifactId>\n                <version>${shiro.version}</version>\n            </dependency>\n\n            <!-- thymeleaf模板引擎和shiro框架的整合 -->\n            <dependency>\n                <groupId>com.github.theborakompanioni</groupId>\n                <artifactId>thymeleaf-extras-shiro</artifactId>\n                <version>${thymeleaf.extras.shiro.version}</version>\n            </dependency>\n\n            <!-- mybatis依赖 -->\n            <dependency>\n                <groupId>org.mybatis.spring.boot</groupId>\n                <artifactId>mybatis-spring-boot-starter</artifactId>\n                <version>${mybatis-spring-boot.version}</version>\n            </dependency>\n\n            <!-- 解析客户端操作系统、浏览器等 -->\n            <dependency>\n                <groupId>nl.basjes.parse.useragent</groupId>\n                <artifactId>yauaa</artifactId>\n                <version>${yauaa.version}</version>\n            </dependency>\n\n            <!-- pagehelper 分页插件 -->\n            <dependency>\n                <groupId>com.github.pagehelper</groupId>\n                <artifactId>pagehelper-spring-boot-starter</artifactId>\n                <version>${pagehelper.boot.version}</version>\n            </dependency>\n\n            <!-- 获取系统信息 -->\n            <dependency>\n                <groupId>com.github.oshi</groupId>\n                <artifactId>oshi-core</artifactId>\n                <version>${oshi.version}</version>\n            </dependency>\n\n            <!-- spring-doc -->\n            <dependency>\n                <groupId>org.springdoc</groupId>\n                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>\n                <version>${springdoc.version}</version>\n            </dependency>\n\n            <!-- io常用工具类 -->\n            <dependency>\n                <groupId>commons-io</groupId>\n                <artifactId>commons-io</artifactId>\n                <version>${commons.io.version}</version>\n            </dependency>\n\n            <!-- excel工具 -->\n            <dependency>\n                <groupId>org.apache.poi</groupId>\n                <artifactId>poi-ooxml</artifactId>\n                <version>${poi.version}</version>\n            </dependency>\n\n            <!-- velocity代码生成使用模板 -->\n            <dependency>\n                <groupId>org.apache.velocity</groupId>\n                <artifactId>velocity-engine-core</artifactId>\n                <version>${velocity.version}</version>\n            </dependency>\n\n            <!-- 阿里JSON解析器 -->\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>fastjson</artifactId>\n                <version>${fastjson.version}</version>\n            </dependency>\n\n            <!-- 定时任务-->\n            <dependency>\n                <groupId>com.ruoyi</groupId>\n                <artifactId>ruoyi-quartz</artifactId>\n                <version>${ruoyi.version}</version>\n            </dependency>\n\n            <!-- 代码生成-->\n            <dependency>\n                <groupId>com.ruoyi</groupId>\n                <artifactId>ruoyi-generator</artifactId>\n                <version>${ruoyi.version}</version>\n            </dependency>\n\n            <!-- 核心模块-->\n            <dependency>\n                <groupId>com.ruoyi</groupId>\n                <artifactId>ruoyi-framework</artifactId>\n                <version>${ruoyi.version}</version>\n            </dependency>\n\n            <!-- 系统模块-->\n            <dependency>\n                <groupId>com.ruoyi</groupId>\n                <artifactId>ruoyi-system</artifactId>\n                <version>${ruoyi.version}</version>\n            </dependency>\n\n            <!-- 通用工具-->\n            <dependency>\n                <groupId>com.ruoyi</groupId>\n                <artifactId>ruoyi-common</artifactId>\n                <version>${ruoyi.version}</version>\n            </dependency>\n\n        </dependencies>\n    </dependencyManagement>\n\n    <modules>\n        <module>ruoyi-admin</module>\n        <module>ruoyi-framework</module>\n        <module>ruoyi-system</module>\n        <module>ruoyi-quartz</module>\n        <module>ruoyi-generator</module>\n        <module>ruoyi-common</module>\n    </modules>\n    <packaging>pom</packaging>\n\n\n    <dependencies>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.13.0</version>\n                <configuration>\n                    <parameters>true</parameters>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>${project.build.sourceEncoding}</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>${spring-boot.version}</version>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>public</id>\n            <name>aliyun nexus</name>\n            <url>https://maven.aliyun.com/repository/public</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>public</id>\n            <name>aliyun nexus</name>\n            <url>https://maven.aliyun.com/repository/public</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "ruoyi-admin/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>ruoyi</artifactId>\n        <groupId>com.ruoyi</groupId>\n        <version>4.8.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    <packaging>jar</packaging>\n    <artifactId>ruoyi-admin</artifactId>\n\n    <description>\n        web服务入口\n    </description>\n\n    <dependencies>\n\n        <!-- SpringBoot集成thymeleaf模板 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n        <!-- spring-boot-devtools -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <optional>true</optional> <!-- 表示依赖不会传递 -->\n        </dependency>\n\n        <!-- spring-doc -->\n        <dependency>\n            <groupId>org.springdoc</groupId>\n            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>\n        </dependency>\n\n        <!-- Mysql驱动包 -->\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n        </dependency>\n\n        <!-- 核心模块-->\n        <dependency>\n            <groupId>com.ruoyi</groupId>\n            <artifactId>ruoyi-framework</artifactId>\n        </dependency>\n\n        <!-- 定时任务-->\n        <dependency>\n            <groupId>com.ruoyi</groupId>\n            <artifactId>ruoyi-quartz</artifactId>\n        </dependency>\n\n        <!-- 代码生成-->\n        <dependency>\n            <groupId>com.ruoyi</groupId>\n            <artifactId>ruoyi-generator</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <addResources>true</addResources>\n                </configuration>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>   \n                <groupId>org.apache.maven.plugins</groupId>   \n                <artifactId>maven-war-plugin</artifactId>   \n                <version>3.1.0</version>   \n                <configuration>\n                    <failOnMissingWebXml>false</failOnMissingWebXml>\n                    <warName>${project.artifactId}</warName>\n                </configuration>   \n            </plugin>   \n            <!-- YUI Compressor (CSS/JS压缩) \n            <plugin>\n                <groupId>net.alchim31.maven</groupId>\n                <artifactId>yuicompressor-maven-plugin</artifactId>\n                <version>1.5.1</version>\n                <executions>\n                    <execution>\n                        <phase>prepare-package</phase>\n                        <goals>\n                            <goal>compress</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <encoding>UTF-8</encoding>\n                    <jswarn>false</jswarn>\n                    <nosuffix>true</nosuffix>\n                    <linebreakpos>50000</linebreakpos>\n                    <sourceDirectory>src/main/resources/static</sourceDirectory>\n                    <force>true</force>\n                    <includes>\n                        <include>**/*.js</include>\n                        <include>**/*.css</include>\n                    </includes>\n                    <excludes>\n                        <exclude>**/*.min.js</exclude>\n                        <exclude>**/*.min.css</exclude>\n                        <exclude>**/fileinput.js</exclude>\n                        <exclude>**/validate/**</exclude>\n                        <exclude>**/bootstrap-table/**</exclude>\n                    </excludes>\n                </configuration>\n            </plugin> -->\n        </plugins>\n        <finalName>${project.artifactId}</finalName>\n    </build>\n\n</project>"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java",
    "content": "package com.ruoyi;\r\n\r\nimport org.springframework.boot.SpringApplication;\r\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\r\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\r\n\r\n/**\r\n * 启动程序\r\n * \r\n * @author ruoyi\r\n */\r\n@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })\r\npublic class RuoYiApplication\r\n{\r\n    public static void main(String[] args)\r\n    {\r\n        // System.setProperty(\"spring.devtools.restart.enabled\", \"false\");\r\n        SpringApplication.run(RuoYiApplication.class, args);\r\n        System.out.println(\"(♥◠‿◠)ﾉﾞ  若依启动成功   ლ(´ڡ`ლ)ﾞ  \\n\" +\r\n                \" .-------.       ____     __        \\n\" +\r\n                \" |  _ _   \\\\      \\\\   \\\\   /  /    \\n\" +\r\n                \" | ( ' )  |       \\\\  _. /  '       \\n\" +\r\n                \" |(_ o _) /        _( )_ .'         \\n\" +\r\n                \" | (_,_).' __  ___(_ o _)'          \\n\" +\r\n                \" |  |\\\\ \\\\  |  ||   |(_,_)'         \\n\" +\r\n                \" |  | \\\\ `'   /|   `-'  /           \\n\" +\r\n                \" |  |  \\\\    /  \\\\      /           \\n\" +\r\n                \" ''-'   `'-'    `-..-'              \");\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java",
    "content": "package com.ruoyi;\r\n\r\nimport org.springframework.boot.builder.SpringApplicationBuilder;\r\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\r\n\r\n/**\r\n * web容器中进行部署\r\n * \r\n * @author ruoyi\r\n */\r\npublic class RuoYiServletInitializer extends SpringBootServletInitializer\r\n{\r\n    @Override\r\n    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)\r\n    {\r\n        return application.sources(RuoYiApplication.class);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java",
    "content": "package com.ruoyi.web.controller.common;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.http.MediaType;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport org.springframework.web.multipart.MultipartFile;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.config.ServerConfig;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.file.FileUploadUtils;\r\nimport com.ruoyi.common.utils.file.FileUtils;\r\n\r\n/**\r\n * 通用请求处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/common\")\r\npublic class CommonController\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(CommonController.class);\r\n\r\n    @Autowired\r\n    private ServerConfig serverConfig;\r\n\r\n    private static final String FILE_DELIMETER = \",\";\r\n\r\n    /**\r\n     * 通用下载请求\r\n     * \r\n     * @param fileName 文件名称\r\n     * @param delete 是否删除\r\n     */\r\n    @GetMapping(\"/download\")\r\n    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)\r\n    {\r\n        try\r\n        {\r\n            if (!FileUtils.checkAllowDownload(fileName))\r\n            {\r\n                throw new Exception(StringUtils.format(\"文件名称({})非法，不允许下载。 \", fileName));\r\n            }\r\n            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf(\"_\") + 1);\r\n            String filePath = RuoYiConfig.getDownloadPath() + fileName;\r\n\r\n            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);\r\n            FileUtils.setAttachmentResponseHeader(response, realFileName);\r\n            FileUtils.writeBytes(filePath, response.getOutputStream());\r\n            if (delete)\r\n            {\r\n                FileUtils.deleteFile(filePath);\r\n            }\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"下载文件失败\", e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 通用上传请求（单个）\r\n     */\r\n    @PostMapping(\"/upload\")\r\n    @ResponseBody\r\n    public AjaxResult uploadFile(MultipartFile file) throws Exception\r\n    {\r\n        try\r\n        {\r\n            // 上传文件路径\r\n            String filePath = RuoYiConfig.getUploadPath();\r\n            // 上传并返回新文件名称\r\n            String fileName = FileUploadUtils.upload(filePath, file);\r\n            String url = serverConfig.getUrl() + fileName;\r\n            AjaxResult ajax = AjaxResult.success();\r\n            ajax.put(\"url\", url);\r\n            ajax.put(\"fileName\", fileName);\r\n            ajax.put(\"newFileName\", FileUtils.getName(fileName));\r\n            ajax.put(\"originalFilename\", file.getOriginalFilename());\r\n            return ajax;\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return AjaxResult.error(e.getMessage());\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 通用上传请求（多个）\r\n     */\r\n    @PostMapping(\"/uploads\")\r\n    @ResponseBody\r\n    public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception\r\n    {\r\n        try\r\n        {\r\n            // 上传文件路径\r\n            String filePath = RuoYiConfig.getUploadPath();\r\n            List<String> urls = new ArrayList<String>();\r\n            List<String> fileNames = new ArrayList<String>();\r\n            List<String> newFileNames = new ArrayList<String>();\r\n            List<String> originalFilenames = new ArrayList<String>();\r\n            for (MultipartFile file : files)\r\n            {\r\n                // 上传并返回新文件名称\r\n                String fileName = FileUploadUtils.upload(filePath, file);\r\n                String url = serverConfig.getUrl() + fileName;\r\n                urls.add(url);\r\n                fileNames.add(fileName);\r\n                newFileNames.add(FileUtils.getName(fileName));\r\n                originalFilenames.add(file.getOriginalFilename());\r\n            }\r\n            AjaxResult ajax = AjaxResult.success();\r\n            ajax.put(\"urls\", StringUtils.join(urls, FILE_DELIMETER));\r\n            ajax.put(\"fileNames\", StringUtils.join(fileNames, FILE_DELIMETER));\r\n            ajax.put(\"newFileNames\", StringUtils.join(newFileNames, FILE_DELIMETER));\r\n            ajax.put(\"originalFilenames\", StringUtils.join(originalFilenames, FILE_DELIMETER));\r\n            return ajax;\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return AjaxResult.error(e.getMessage());\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 本地资源通用下载\r\n     */\r\n    @GetMapping(\"/download/resource\")\r\n    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) throws Exception\r\n    {\r\n        try\r\n        {\r\n            if (!FileUtils.checkAllowDownload(resource))\r\n            {\r\n                throw new Exception(StringUtils.format(\"资源文件({})非法，不允许下载。 \", resource));\r\n            }\r\n            // 本地资源路径\r\n            String localPath = RuoYiConfig.getProfile();\r\n            // 数据库资源地址\r\n            String downloadPath = localPath + FileUtils.stripPrefix(resource);\r\n            // 下载名称\r\n            String downloadName = StringUtils.substringAfterLast(downloadPath, \"/\");\r\n            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);\r\n            FileUtils.setAttachmentResponseHeader(response, downloadName);\r\n            FileUtils.writeBytes(downloadPath, response.getOutputStream());\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"下载文件失败\", e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoDialogController.java",
    "content": "package com.ruoyi.web.controller.demo.controller;\r\n\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\n\r\n/**\r\n * 模态窗口\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/demo/modal\")\r\npublic class DemoDialogController\r\n{\r\n    private String prefix = \"demo/modal\";\r\n\r\n    /**\r\n     * 模态窗口\r\n     */\r\n    @GetMapping(\"/dialog\")\r\n    public String dialog()\r\n    {\r\n        return prefix + \"/dialog\";\r\n    }\r\n\r\n    /**\r\n     * 弹层组件\r\n     */\r\n    @GetMapping(\"/layer\")\r\n    public String layer()\r\n    {\r\n        return prefix + \"/layer\";\r\n    }\r\n\r\n    /**\r\n     * 表单\r\n     */\r\n    @GetMapping(\"/form\")\r\n    public String form()\r\n    {\r\n        return prefix + \"/form\";\r\n    }\r\n\r\n    /**\r\n     * 表格\r\n     */\r\n    @GetMapping(\"/table\")\r\n    public String table()\r\n    {\r\n        return prefix + \"/table\";\r\n    }\r\n\r\n    /**\r\n     * 表格check\r\n     */\r\n    @GetMapping(\"/check\")\r\n    public String check()\r\n    {\r\n        return prefix + \"/table/check\";\r\n    }\r\n\r\n    /**\r\n     * 表格radio\r\n     */\r\n    @GetMapping(\"/radio\")\r\n    public String radio()\r\n    {\r\n        return prefix + \"/table/radio\";\r\n    }\r\n\r\n    /**\r\n     * 表格回传父窗体\r\n     */\r\n    @GetMapping(\"/parent\")\r\n    public String parent()\r\n    {\r\n        return prefix + \"/table/parent\";\r\n    }\r\n\r\n    /**\r\n     * 多层窗口frame1\r\n     */\r\n    @GetMapping(\"/frame1\")\r\n    public String frame1()\r\n    {\r\n        return prefix + \"/table/frame1\";\r\n    }\r\n\r\n    /**\r\n     * 多层窗口frame2\r\n     */\r\n    @GetMapping(\"/frame2\")\r\n    public String frame2()\r\n    {\r\n        return prefix + \"/table/frame2\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoFormController.java",
    "content": "package com.ruoyi.web.controller.demo.controller;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.alibaba.fastjson.JSON;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.CxSelect;\r\nimport com.ruoyi.common.json.JSONObject;\r\nimport com.ruoyi.common.json.JSONObject.JSONArray;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 表单相关\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/demo/form\")\r\npublic class DemoFormController\r\n{\r\n    private String prefix = \"demo/form\";\r\n\r\n    private final static List<UserFormModel> users = new ArrayList<UserFormModel>();\r\n    {\r\n        users.add(new UserFormModel(1, \"1000001\", \"测试1\", \"15888888888\"));\r\n        users.add(new UserFormModel(2, \"1000002\", \"测试2\", \"15666666666\"));\r\n        users.add(new UserFormModel(3, \"1000003\", \"测试3\", \"15666666666\"));\r\n        users.add(new UserFormModel(4, \"1000004\", \"测试4\", \"15666666666\"));\r\n        users.add(new UserFormModel(5, \"1000005\", \"测试5\", \"15666666666\"));\r\n    }\r\n\r\n    /**\r\n     * 按钮页\r\n     */\r\n    @GetMapping(\"/button\")\r\n    public String button()\r\n    {\r\n        return prefix + \"/button\";\r\n    }\r\n\r\n    /**\r\n     * 下拉框\r\n     */\r\n    @GetMapping(\"/select\")\r\n    public String select()\r\n    {\r\n        return prefix + \"/select\";\r\n    }\r\n\r\n    /**\r\n     * 时间轴\r\n     */\r\n    @GetMapping(\"/timeline\")\r\n    public String timeline()\r\n    {\r\n        return prefix + \"/timeline\";\r\n    }\r\n\r\n    /**\r\n     * 进度条\r\n     */\r\n    @GetMapping(\"/progress_bars\")\r\n    public String progress_bars()\r\n    {\r\n        return prefix + \"/progress_bars\";\r\n    }\r\n\r\n    /**\r\n     * 表单校验\r\n     */\r\n    @GetMapping(\"/validate\")\r\n    public String validate()\r\n    {\r\n        return prefix + \"/validate\";\r\n    }\r\n\r\n    /**\r\n     * 功能扩展（包含文件上传）\r\n     */\r\n    @GetMapping(\"/jasny\")\r\n    public String jasny()\r\n    {\r\n        return prefix + \"/jasny\";\r\n    }\r\n\r\n    /**\r\n     * 拖动排序\r\n     */\r\n    @GetMapping(\"/sortable\")\r\n    public String sortable()\r\n    {\r\n        return prefix + \"/sortable\";\r\n    }\r\n\r\n    /**\r\n     * 单据打印\r\n     */\r\n    @GetMapping(\"/invoice\")\r\n    public String invoice()\r\n    {\r\n        return prefix + \"/invoice\";\r\n    }\r\n\r\n    /**\r\n     * 标签 & 提示\r\n     */\r\n    @GetMapping(\"/labels_tips\")\r\n    public String labels_tips()\r\n    {\r\n        return prefix + \"/labels_tips\";\r\n    }\r\n\r\n    /**\r\n     * 选项卡 & 面板\r\n     */\r\n    @GetMapping(\"/tabs_panels\")\r\n    public String tabs_panels()\r\n    {\r\n        return prefix + \"/tabs_panels\";\r\n    }\r\n\r\n    /**\r\n     * 栅格\r\n     */\r\n    @GetMapping(\"/grid\")\r\n    public String grid()\r\n    {\r\n        return prefix + \"/grid\";\r\n    }\r\n\r\n    /**\r\n     * 表单向导\r\n     */\r\n    @GetMapping(\"/wizard\")\r\n    public String wizard()\r\n    {\r\n        return prefix + \"/wizard\";\r\n    }\r\n\r\n    /**\r\n     * 文件上传\r\n     */\r\n    @GetMapping(\"/upload\")\r\n    public String upload()\r\n    {\r\n        return prefix + \"/upload\";\r\n    }\r\n\r\n    /**\r\n     * 日期和时间页\r\n     */\r\n    @GetMapping(\"/datetime\")\r\n    public String datetime()\r\n    {\r\n        return prefix + \"/datetime\";\r\n    }\r\n\r\n    /**\r\n     * 左右互选组件\r\n     */\r\n    @GetMapping(\"/duallistbox\")\r\n    public String duallistbox()\r\n    {\r\n        return prefix + \"/duallistbox\";\r\n    }\r\n\r\n    /**\r\n     * 基本表单\r\n     */\r\n    @GetMapping(\"/basic\")\r\n    public String basic()\r\n    {\r\n        return prefix + \"/basic\";\r\n    }\r\n\r\n    /**\r\n     * 卡片列表\r\n     */\r\n    @GetMapping(\"/cards\")\r\n    public String cards()\r\n    {\r\n        return prefix + \"/cards\";\r\n    }\r\n\r\n    /**\r\n     * summernote 富文本编辑器\r\n     */\r\n    @GetMapping(\"/summernote\")\r\n    public String summernote()\r\n    {\r\n        return prefix + \"/summernote\";\r\n    }\r\n\r\n    /**\r\n     * 搜索自动补全\r\n     */\r\n    @GetMapping(\"/autocomplete\")\r\n    public String autocomplete()\r\n    {\r\n        return prefix + \"/autocomplete\";\r\n    }\r\n\r\n    /**\r\n     * 多级联动下拉\r\n     */\r\n    @GetMapping(\"/cxselect\")\r\n    public String cxselect(ModelMap mmap)\r\n    {\r\n        CxSelect cxSelectTB = new CxSelect();\r\n        cxSelectTB.setN(\"淘宝\");\r\n        cxSelectTB.setV(\"taobao\");\r\n        CxSelect cxSelectTm = new CxSelect();\r\n        cxSelectTm.setN(\"天猫\");\r\n        cxSelectTm.setV(\"tm\");\r\n        CxSelect cxSelectJhs = new CxSelect();\r\n        cxSelectJhs.setN(\"聚划算\");\r\n        cxSelectJhs.setV(\"jhs\");\r\n        List<CxSelect> tmList = new ArrayList<CxSelect>();\r\n        tmList.add(cxSelectTm);\r\n        tmList.add(cxSelectJhs);\r\n        cxSelectTB.setS(tmList);\r\n\r\n        CxSelect cxSelectJD = new CxSelect();\r\n        cxSelectJD.setN(\"京东\");\r\n        cxSelectJD.setV(\"jd\");\r\n        CxSelect cxSelectCs = new CxSelect();\r\n        cxSelectCs.setN(\"京东超市\");\r\n        cxSelectCs.setV(\"jdcs\");\r\n        CxSelect cxSelectSx = new CxSelect();\r\n        cxSelectSx.setN(\"京东生鲜\");\r\n        cxSelectSx.setV(\"jdsx\");\r\n        List<CxSelect> jdList = new ArrayList<CxSelect>();\r\n        jdList.add(cxSelectCs);\r\n        jdList.add(cxSelectSx);\r\n        cxSelectJD.setS(jdList);\r\n\r\n        List<CxSelect> cxList = new ArrayList<CxSelect>();\r\n        cxList.add(cxSelectTB);\r\n        cxList.add(cxSelectJD);\r\n\r\n        mmap.put(\"data\", JSON.toJSON(cxList));\r\n        return prefix + \"/cxselect\";\r\n    }\r\n\r\n    /**\r\n     * 局部刷新\r\n     */\r\n    @GetMapping(\"/localrefresh\")\r\n    public String localRefresh(ModelMap mmap)\r\n    {\r\n        JSONArray list = new JSONArray();\r\n        JSONObject item = new JSONObject();\r\n        item.put(\"name\", \"这条任务数据是由ModelMap传递到页面的，点击添加按钮后会将这条数据替换为新数据\");\r\n        item.put(\"type\", \"默认\");\r\n        item.put(\"date\", \"2020.06.10\");\r\n        list.add(item);\r\n        mmap.put(\"tasks\", list);\r\n        mmap.put(\"min\", 2);\r\n        mmap.put(\"max\", 10);\r\n        return prefix + \"/localrefresh\";\r\n    }\r\n\r\n    /**\r\n     * 局部刷新-添加任务\r\n     * \r\n     * @param fragment 页面中的模板名称\r\n     * @param taskName 任务名称\r\n     */\r\n    @PostMapping(\"/localrefresh/task\")\r\n    public String localRefreshTask(String taskName, ModelMap mmap)\r\n    {\r\n        JSONArray list = new JSONArray();\r\n        JSONObject item = new JSONObject();\r\n        item.put(\"name\", StringUtils.defaultIfBlank(taskName, \"通过电话销售过程中了解各盛市的设备仪器使用、采购情况及相关重要追踪人\"));\r\n        item.put(\"type\", \"新增\");\r\n        item.put(\"date\", \"2018.06.10\");\r\n        list.add(item);\r\n        item = new JSONObject();\r\n        item.put(\"name\", \"提高自己电话营销技巧，灵活专业地与客户进行电话交流\");\r\n        item.put(\"type\", \"新增\");\r\n        item.put(\"date\", \"2018.06.12\");\r\n        list.add(item);\r\n        mmap.put(\"tasks\", list);\r\n        return prefix + \"/localrefresh::fragment-tasklist\";\r\n    }\r\n\r\n    /**\r\n     * 模拟数据\r\n     */\r\n    @GetMapping(\"/cityData\")\r\n    @ResponseBody\r\n    public String cityData()\r\n    {\r\n        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\\\":\\\"罗定市\\\"}]}]}]\";\r\n        return data;\r\n    }\r\n\r\n    /**\r\n     * 获取用户数据\r\n     */\r\n    @GetMapping(\"/userModel\")\r\n    @ResponseBody\r\n    public AjaxResult userModel()\r\n    {\r\n        AjaxResult ajax = new AjaxResult();\r\n\r\n        ajax.put(\"code\", 200);\r\n        ajax.put(\"value\", users);\r\n        return ajax;\r\n    }\r\n\r\n    /**\r\n     * 获取数据集合\r\n     */\r\n    @GetMapping(\"/collection\")\r\n    @ResponseBody\r\n    public AjaxResult collection()\r\n    {\r\n        String[] array = { \"ruoyi 1\", \"ruoyi 2\", \"ruoyi 3\", \"ruoyi 4\", \"ruoyi 5\" };\r\n        AjaxResult ajax = new AjaxResult();\r\n        ajax.put(\"value\", array);\r\n        return ajax;\r\n    }\r\n}\r\n\r\nclass UserFormModel\r\n{\r\n    /** 用户ID */\r\n    private int userId;\r\n\r\n    /** 用户编号 */\r\n    private String userCode;\r\n\r\n    /** 用户姓名 */\r\n    private String userName;\r\n\r\n    /** 用户手机 */\r\n    private String userPhone;\r\n\r\n    public UserFormModel()\r\n    {\r\n\r\n    }\r\n\r\n    public UserFormModel(int userId, String userCode, String userName, String userPhone)\r\n    {\r\n        this.userId = userId;\r\n        this.userCode = userCode;\r\n        this.userName = userName;\r\n        this.userPhone = userPhone;\r\n    }\r\n\r\n    public int getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n\r\n    public void setUserId(int userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public String getUserCode()\r\n    {\r\n        return userCode;\r\n    }\r\n\r\n    public void setUserCode(String userCode)\r\n    {\r\n        this.userCode = userCode;\r\n    }\r\n\r\n    public String getUserName()\r\n    {\r\n        return userName;\r\n    }\r\n\r\n    public void setUserName(String userName)\r\n    {\r\n        this.userName = userName;\r\n    }\r\n\r\n    public String getUserPhone()\r\n    {\r\n        return userPhone;\r\n    }\r\n\r\n    public void setUserPhone(String userPhone)\r\n    {\r\n        this.userPhone = userPhone;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoIconController.java",
    "content": "package com.ruoyi.web.controller.demo.controller;\r\n\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\n\r\n/**\r\n * 图标相关\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/demo/icon\")\r\npublic class DemoIconController\r\n{\r\n    private String prefix = \"demo/icon\";\r\n\r\n    /**\r\n     * FontAwesome图标\r\n     */\r\n    @GetMapping(\"/fontawesome\")\r\n    public String fontAwesome()\r\n    {\r\n        return prefix + \"/fontawesome\";\r\n    }\r\n\r\n    /**\r\n     * Glyphicons图标\r\n     */\r\n    @GetMapping(\"/glyphicons\")\r\n    public String glyphicons()\r\n    {\r\n        return prefix + \"/glyphicons\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoOperateController.java",
    "content": "package com.ruoyi.web.controller.demo.controller;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport org.springframework.web.multipart.MultipartFile;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.PageDomain;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.core.page.TableSupport;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.web.controller.demo.domain.CustomerModel;\r\nimport com.ruoyi.web.controller.demo.domain.UserOperateModel;\r\n\r\n/**\r\n * 操作控制\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/demo/operate\")\r\npublic class DemoOperateController extends BaseController\r\n{\r\n    private String prefix = \"demo/operate\";\r\n\r\n    private final static Map<Integer, UserOperateModel> users = new LinkedHashMap<Integer, UserOperateModel>();\r\n    {\r\n        users.put(1, new UserOperateModel(1, \"1000001\", \"测试1\", \"0\", \"15888888888\", \"ry@qq.com\", 150.0, \"0\"));\r\n        users.put(2, new UserOperateModel(2, \"1000002\", \"测试2\", \"1\", \"15666666666\", \"ry@qq.com\", 180.0, \"1\"));\r\n        users.put(3, new UserOperateModel(3, \"1000003\", \"测试3\", \"0\", \"15666666666\", \"ry@qq.com\", 110.0, \"1\"));\r\n        users.put(4, new UserOperateModel(4, \"1000004\", \"测试4\", \"1\", \"15666666666\", \"ry@qq.com\", 220.0, \"1\"));\r\n        users.put(5, new UserOperateModel(5, \"1000005\", \"测试5\", \"0\", \"15666666666\", \"ry@qq.com\", 140.0, \"1\"));\r\n        users.put(6, new UserOperateModel(6, \"1000006\", \"测试6\", \"1\", \"15666666666\", \"ry@qq.com\", 330.0, \"1\"));\r\n        users.put(7, new UserOperateModel(7, \"1000007\", \"测试7\", \"0\", \"15666666666\", \"ry@qq.com\", 160.0, \"1\"));\r\n        users.put(8, new UserOperateModel(8, \"1000008\", \"测试8\", \"1\", \"15666666666\", \"ry@qq.com\", 170.0, \"1\"));\r\n        users.put(9, new UserOperateModel(9, \"1000009\", \"测试9\", \"0\", \"15666666666\", \"ry@qq.com\", 180.0, \"1\"));\r\n        users.put(10, new UserOperateModel(10, \"1000010\", \"测试10\", \"0\", \"15666666666\", \"ry@qq.com\", 210.0, \"1\"));\r\n        users.put(11, new UserOperateModel(11, \"1000011\", \"测试11\", \"1\", \"15666666666\", \"ry@qq.com\", 110.0, \"1\"));\r\n        users.put(12, new UserOperateModel(12, \"1000012\", \"测试12\", \"0\", \"15666666666\", \"ry@qq.com\", 120.0, \"1\"));\r\n        users.put(13, new UserOperateModel(13, \"1000013\", \"测试13\", \"1\", \"15666666666\", \"ry@qq.com\", 380.0, \"1\"));\r\n        users.put(14, new UserOperateModel(14, \"1000014\", \"测试14\", \"0\", \"15666666666\", \"ry@qq.com\", 280.0, \"1\"));\r\n        users.put(15, new UserOperateModel(15, \"1000015\", \"测试15\", \"0\", \"15666666666\", \"ry@qq.com\", 570.0, \"1\"));\r\n        users.put(16, new UserOperateModel(16, \"1000016\", \"测试16\", \"1\", \"15666666666\", \"ry@qq.com\", 260.0, \"1\"));\r\n        users.put(17, new UserOperateModel(17, \"1000017\", \"测试17\", \"1\", \"15666666666\", \"ry@qq.com\", 210.0, \"1\"));\r\n        users.put(18, new UserOperateModel(18, \"1000018\", \"测试18\", \"1\", \"15666666666\", \"ry@qq.com\", 340.0, \"1\"));\r\n        users.put(19, new UserOperateModel(19, \"1000019\", \"测试19\", \"1\", \"15666666666\", \"ry@qq.com\", 160.0, \"1\"));\r\n        users.put(20, new UserOperateModel(20, \"1000020\", \"测试20\", \"1\", \"15666666666\", \"ry@qq.com\", 220.0, \"1\"));\r\n        users.put(21, new UserOperateModel(21, \"1000021\", \"测试21\", \"1\", \"15666666666\", \"ry@qq.com\", 120.0, \"1\"));\r\n        users.put(22, new UserOperateModel(22, \"1000022\", \"测试22\", \"1\", \"15666666666\", \"ry@qq.com\", 130.0, \"1\"));\r\n        users.put(23, new UserOperateModel(23, \"1000023\", \"测试23\", \"1\", \"15666666666\", \"ry@qq.com\", 490.0, \"1\"));\r\n        users.put(24, new UserOperateModel(24, \"1000024\", \"测试24\", \"1\", \"15666666666\", \"ry@qq.com\", 570.0, \"1\"));\r\n        users.put(25, new UserOperateModel(25, \"1000025\", \"测试25\", \"1\", \"15666666666\", \"ry@qq.com\", 250.0, \"1\"));\r\n        users.put(26, new UserOperateModel(26, \"1000026\", \"测试26\", \"1\", \"15666666666\", \"ry@qq.com\", 250.0, \"1\"));\r\n    }\r\n\r\n    /**\r\n     * 表格\r\n     */\r\n    @GetMapping(\"/table\")\r\n    public String table()\r\n    {\r\n        return prefix + \"/table\";\r\n    }\r\n\r\n    /**\r\n     * 其他\r\n     */\r\n    @GetMapping(\"/other\")\r\n    public String other()\r\n    {\r\n        return prefix + \"/other\";\r\n    }\r\n\r\n    /**\r\n     * 查询数据\r\n     */\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(UserOperateModel userModel)\r\n    {\r\n        TableDataInfo rspData = new TableDataInfo();\r\n        List<UserOperateModel> userList = new ArrayList<UserOperateModel>(users.values());\r\n        // 查询条件过滤\r\n        if (StringUtils.isNotEmpty(userModel.getSearchValue()))\r\n        {\r\n            userList.clear();\r\n            for (Map.Entry<Integer, UserOperateModel> entry : users.entrySet())\r\n            {\r\n                if (entry.getValue().getUserName().equals(userModel.getSearchValue()))\r\n                {\r\n                    userList.add(entry.getValue());\r\n                }\r\n            }\r\n        }\r\n        else if (StringUtils.isNotEmpty(userModel.getUserName()))\r\n        {\r\n            userList.clear();\r\n            for (Map.Entry<Integer, UserOperateModel> entry : users.entrySet())\r\n            {\r\n                if (entry.getValue().getUserName().equals(userModel.getUserName()))\r\n                {\r\n                    userList.add(entry.getValue());\r\n                }\r\n            }\r\n        }\r\n        PageDomain pageDomain = TableSupport.buildPageRequest();\r\n        if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize())\r\n        {\r\n            rspData.setRows(userList);\r\n            rspData.setTotal(userList.size());\r\n            return rspData;\r\n        }\r\n        Integer pageNum = (pageDomain.getPageNum() - 1) * 10;\r\n        Integer pageSize = pageDomain.getPageNum() * 10;\r\n        if (pageSize > userList.size())\r\n        {\r\n            pageSize = userList.size();\r\n        }\r\n        rspData.setRows(userList.subList(pageNum, pageSize));\r\n        rspData.setTotal(userList.size());\r\n        return rspData;\r\n    }\r\n\r\n    /**\r\n     * 新增用户\r\n     */\r\n    @GetMapping(\"/add\")\r\n    public String add(ModelMap mmap)\r\n    {\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存用户\r\n     */\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(UserOperateModel user)\r\n    {\r\n        Integer userId = users.size() + 1;\r\n        user.setUserId(userId);\r\n        return AjaxResult.success(users.put(userId, user));\r\n    }\r\n\r\n    /**\r\n     * 新增保存主子表信息\r\n     */\r\n    @PostMapping(\"/customer/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(CustomerModel customerModel)\r\n    {\r\n        System.out.println(customerModel.toString());\r\n        return AjaxResult.success();\r\n    }\r\n\r\n    /**\r\n     * 修改用户\r\n     */\r\n    @GetMapping(\"/edit/{userId}\")\r\n    public String edit(@PathVariable(\"userId\") Integer userId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"user\", users.get(userId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存用户\r\n     */\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(UserOperateModel user)\r\n    {\r\n        return AjaxResult.success(users.put(user.getUserId(), user));\r\n    }\r\n\r\n    /**\r\n     * 导出\r\n     */\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(UserOperateModel user)\r\n    {\r\n        List<UserOperateModel> list = new ArrayList<UserOperateModel>(users.values());\r\n        ExcelUtil<UserOperateModel> util = new ExcelUtil<UserOperateModel>(UserOperateModel.class);\r\n        return util.exportExcel(list, \"用户数据\");\r\n    }\r\n\r\n    /**\r\n     * 下载模板\r\n     */\r\n    @GetMapping(\"/importTemplate\")\r\n    @ResponseBody\r\n    public AjaxResult importTemplate()\r\n    {\r\n        ExcelUtil<UserOperateModel> util = new ExcelUtil<UserOperateModel>(UserOperateModel.class);\r\n        return util.importTemplateExcel(\"用户数据\");\r\n    }\r\n\r\n    /**\r\n     * 导入数据\r\n     */\r\n    @PostMapping(\"/importData\")\r\n    @ResponseBody\r\n    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception\r\n    {\r\n        ExcelUtil<UserOperateModel> util = new ExcelUtil<UserOperateModel>(UserOperateModel.class);\r\n        List<UserOperateModel> userList = util.importExcel(file.getInputStream());\r\n        String message = importUser(userList, updateSupport);\r\n        return AjaxResult.success(message);\r\n    }\r\n\r\n    /**\r\n     * 删除用户\r\n     */\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        Integer[] userIds = Convert.toIntArray(ids);\r\n        for (Integer userId : userIds)\r\n        {\r\n            users.remove(userId);\r\n        }\r\n        return AjaxResult.success();\r\n    }\r\n\r\n    /**\r\n     * 查看详细\r\n     */\r\n    @GetMapping(\"/detail/{userId}\")\r\n    public String detail(@PathVariable(\"userId\") Integer userId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"user\", users.get(userId));\r\n        return prefix + \"/detail\";\r\n    }\r\n\r\n    @PostMapping(\"/clean\")\r\n    @ResponseBody\r\n    public AjaxResult clean()\r\n    {\r\n        users.clear();\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 导入用户数据\r\n     * \r\n     * @param userList 用户数据列表\r\n     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据\r\n     * @return 结果\r\n     */\r\n    public String importUser(List<UserOperateModel> userList, Boolean isUpdateSupport)\r\n    {\r\n        if (StringUtils.isNull(userList) || userList.size() == 0)\r\n        {\r\n            throw new ServiceException(\"导入用户数据不能为空！\");\r\n        }\r\n        int successNum = 0;\r\n        int failureNum = 0;\r\n        StringBuilder successMsg = new StringBuilder();\r\n        StringBuilder failureMsg = new StringBuilder();\r\n        for (UserOperateModel user : userList)\r\n        {\r\n            try\r\n            {\r\n                // 验证是否存在这个用户\r\n                boolean userFlag = false;\r\n                for (Map.Entry<Integer, UserOperateModel> entry : users.entrySet())\r\n                {\r\n                    if (entry.getValue().getUserName().equals(user.getUserName()))\r\n                    {\r\n                        userFlag = true;\r\n                        break;\r\n                    }\r\n                }\r\n                if (!userFlag)\r\n                {\r\n                    Integer userId = users.size() + 1;\r\n                    user.setUserId(userId);\r\n                    users.put(userId, user);\r\n                    successNum++;\r\n                    successMsg.append(\"<br/>\" + successNum + \"、用户 \" + user.getUserName() + \" 导入成功\");\r\n                }\r\n                else if (isUpdateSupport)\r\n                {\r\n                    users.put(user.getUserId(), user);\r\n                    successNum++;\r\n                    successMsg.append(\"<br/>\" + successNum + \"、用户 \" + user.getUserName() + \" 更新成功\");\r\n                }\r\n                else\r\n                {\r\n                    failureNum++;\r\n                    failureMsg.append(\"<br/>\" + failureNum + \"、用户 \" + user.getUserName() + \" 已存在\");\r\n                }\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                failureNum++;\r\n                String msg = \"<br/>\" + failureNum + \"、账号 \" + user.getUserName() + \" 导入失败：\";\r\n                failureMsg.append(msg + e.getMessage());\r\n            }\r\n        }\r\n        if (failureNum > 0)\r\n        {\r\n            failureMsg.insert(0, \"很抱歉，导入失败！共 \" + failureNum + \" 条数据格式不正确，错误如下：\");\r\n            throw new ServiceException(failureMsg.toString());\r\n        }\r\n        else\r\n        {\r\n            successMsg.insert(0, \"恭喜您，数据已全部导入成功！共 \" + successNum + \" 条，数据如下：\");\r\n        }\r\n        return successMsg.toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoReportController.java",
    "content": "package com.ruoyi.web.controller.demo.controller;\r\n\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\n\r\n/**\r\n * 报表\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/demo/report\")\r\npublic class DemoReportController\r\n{\r\n    private String prefix = \"demo/report\";\r\n\r\n    /**\r\n     * 百度ECharts\r\n     */\r\n    @GetMapping(\"/echarts\")\r\n    public String echarts()\r\n    {\r\n        return prefix + \"/echarts\";\r\n    }\r\n\r\n    /**\r\n     * 图表插件\r\n     */\r\n    @GetMapping(\"/peity\")\r\n    public String peity()\r\n    {\r\n        return prefix + \"/peity\";\r\n    }\r\n\r\n    /**\r\n     * 线状图插件\r\n     */\r\n    @GetMapping(\"/sparkline\")\r\n    public String sparkline()\r\n    {\r\n        return prefix + \"/sparkline\";\r\n    }\r\n\r\n    /**\r\n     * 图表组合\r\n     */\r\n    @GetMapping(\"/metrics\")\r\n    public String metrics()\r\n    {\r\n        return prefix + \"/metrics\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoTableController.java",
    "content": "package com.ruoyi.web.controller.demo.controller;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Collections;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.fasterxml.jackson.annotation.JsonFormat;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.core.page.PageDomain;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.core.page.TableSupport;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\n\r\n/**\r\n * 表格相关\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/demo/table\")\r\npublic class DemoTableController extends BaseController\r\n{\r\n    private String prefix = \"demo/table\";\r\n\r\n    private final static List<UserTableModel> users = new ArrayList<UserTableModel>();\r\n    {\r\n        users.add(new UserTableModel(1, \"1000001\", \"测试1\", \"0\", \"15888888888\", \"ry@qq.com\", 150.0, \"0\"));\r\n        users.add(new UserTableModel(2, \"1000002\", \"测试2\", \"1\", \"15666666666\", \"ry@qq.com\", 180.0, \"1\"));\r\n        users.add(new UserTableModel(3, \"1000003\", \"测试3\", \"0\", \"15666666666\", \"ry@qq.com\", 110.0, \"1\"));\r\n        users.add(new UserTableModel(4, \"1000004\", \"测试4\", \"1\", \"15666666666\", \"ry@qq.com\", 220.0, \"1\"));\r\n        users.add(new UserTableModel(5, \"1000005\", \"测试5\", \"0\", \"15666666666\", \"ry@qq.com\", 140.0, \"1\"));\r\n        users.add(new UserTableModel(6, \"1000006\", \"测试6\", \"1\", \"15666666666\", \"ry@qq.com\", 330.0, \"1\"));\r\n        users.add(new UserTableModel(7, \"1000007\", \"测试7\", \"0\", \"15666666666\", \"ry@qq.com\", 160.0, \"1\"));\r\n        users.add(new UserTableModel(8, \"1000008\", \"测试8\", \"1\", \"15666666666\", \"ry@qq.com\", 170.0, \"1\"));\r\n        users.add(new UserTableModel(9, \"1000009\", \"测试9\", \"0\", \"15666666666\", \"ry@qq.com\", 180.0, \"1\"));\r\n        users.add(new UserTableModel(10, \"1000010\", \"测试10\", \"0\", \"15666666666\", \"ry@qq.com\", 210.0, \"1\"));\r\n        users.add(new UserTableModel(11, \"1000011\", \"测试11\", \"1\", \"15666666666\", \"ry@qq.com\", 110.0, \"1\"));\r\n        users.add(new UserTableModel(12, \"1000012\", \"测试12\", \"0\", \"15666666666\", \"ry@qq.com\", 120.0, \"1\"));\r\n        users.add(new UserTableModel(13, \"1000013\", \"测试13\", \"1\", \"15666666666\", \"ry@qq.com\", 380.0, \"1\"));\r\n        users.add(new UserTableModel(14, \"1000014\", \"测试14\", \"0\", \"15666666666\", \"ry@qq.com\", 280.0, \"1\"));\r\n        users.add(new UserTableModel(15, \"1000015\", \"测试15\", \"0\", \"15666666666\", \"ry@qq.com\", 570.0, \"1\"));\r\n        users.add(new UserTableModel(16, \"1000016\", \"测试16\", \"1\", \"15666666666\", \"ry@qq.com\", 260.0, \"1\"));\r\n        users.add(new UserTableModel(17, \"1000017\", \"测试17\", \"1\", \"15666666666\", \"ry@qq.com\", 210.0, \"1\"));\r\n        users.add(new UserTableModel(18, \"1000018\", \"测试18\", \"1\", \"15666666666\", \"ry@qq.com\", 340.0, \"1\"));\r\n        users.add(new UserTableModel(19, \"1000019\", \"测试19\", \"1\", \"15666666666\", \"ry@qq.com\", 160.0, \"1\"));\r\n        users.add(new UserTableModel(20, \"1000020\", \"测试20\", \"1\", \"15666666666\", \"ry@qq.com\", 220.0, \"1\"));\r\n        users.add(new UserTableModel(21, \"1000021\", \"测试21\", \"1\", \"15666666666\", \"ry@qq.com\", 120.0, \"1\"));\r\n        users.add(new UserTableModel(22, \"1000022\", \"测试22\", \"1\", \"15666666666\", \"ry@qq.com\", 130.0, \"1\"));\r\n        users.add(new UserTableModel(23, \"1000023\", \"测试23\", \"1\", \"15666666666\", \"ry@qq.com\", 490.0, \"1\"));\r\n        users.add(new UserTableModel(24, \"1000024\", \"测试24\", \"1\", \"15666666666\", \"ry@qq.com\", 570.0, \"1\"));\r\n        users.add(new UserTableModel(25, \"1000025\", \"测试25\", \"1\", \"15666666666\", \"ry@qq.com\", 250.0, \"1\"));\r\n        users.add(new UserTableModel(26, \"1000026\", \"测试26\", \"1\", \"15666666666\", \"ry@qq.com\", 250.0, \"1\"));\r\n    }\r\n\r\n    private final static List<AreaModel> areas = new ArrayList<AreaModel>();\r\n    {\r\n        areas.add(new AreaModel(1, 0, \"广东省\", \"440000\", \"GDS\", \"GuangDongSheng\", 1));\r\n        areas.add(new AreaModel(2, 0, \"湖南省\", \"430000\", \"HNS\", \"HuNanSheng\", 1));\r\n        areas.add(new AreaModel(3, 0, \"河南省\", \"410000\", \"HNS\", \"HeNanSheng\", 0));\r\n        areas.add(new AreaModel(4, 0, \"湖北省\", \"420000\", \"HBS\", \"HuBeiSheng\", 0));\r\n        areas.add(new AreaModel(5, 0, \"辽宁省\", \"210000\", \"LNS\", \"LiaoNingSheng\", 0));\r\n        areas.add(new AreaModel(6, 0, \"山东省\", \"370000\", \"SDS\", \"ShanDongSheng\", 0));\r\n        areas.add(new AreaModel(7, 0, \"陕西省\", \"610000\", \"SXS\", \"ShanXiSheng\", 0));\r\n        areas.add(new AreaModel(8, 0, \"贵州省\", \"520000\", \"GZS\", \"GuiZhouSheng\", 0));\r\n        areas.add(new AreaModel(9,  0, \"上海市\", \"310000\", \"SHS\", \"ShangHaiShi\", 0));\r\n        areas.add(new AreaModel(10, 0, \"重庆市\", \"500000\", \"CQS\", \"ChongQingShi\", 0));\r\n        areas.add(new AreaModel(11, 0, \"若依省\", \"666666\", \"YYS\", \"RuoYiSheng\", 0));\r\n        areas.add(new AreaModel(12, 0, \"安徽省\", \"340000\", \"AHS\", \"AnHuiSheng\", 0));\r\n        areas.add(new AreaModel(13, 0, \"福建省\", \"350000\", \"FJS\", \"FuJianSheng\", 0));\r\n        areas.add(new AreaModel(14, 0, \"海南省\", \"460000\", \"HNS\", \"HaiNanSheng\", 0));\r\n        areas.add(new AreaModel(15, 0, \"江苏省\", \"320000\", \"JSS\", \"JiangSuSheng\", 0));\r\n        areas.add(new AreaModel(16, 0, \"青海省\", \"630000\", \"QHS\", \"QingHaiSheng\", 0));\r\n        areas.add(new AreaModel(17, 0, \"广西壮族自治区\", \"450000\", \"GXZZZZQ\", \"GuangXiZhuangZuZiZhiQu\", 0));\r\n        areas.add(new AreaModel(18, 0, \"宁夏回族自治区\", \"640000\", \"NXHZZZQ\", \"NingXiaHuiZuZiZhiQu\", 0));\r\n        areas.add(new AreaModel(19, 0, \"内蒙古自治区\", \"150000\", \"NMGZZQ\", \"NeiMengGuZiZhiQu\", 0));\r\n        areas.add(new AreaModel(20, 0, \"新疆维吾尔自治区\", \"650000\", \"XJWWEZZQ\", \"XinJiangWeiWuErZiZhiQu\", 0));\r\n        areas.add(new AreaModel(21, 0, \"江西省\", \"360000\", \"JXS\", \"JiangXiSheng\", 0));\r\n        areas.add(new AreaModel(22, 0, \"浙江省\", \"330000\", \"ZJS\", \"ZheJiangSheng\", 0));\r\n        areas.add(new AreaModel(23, 0, \"河北省\", \"130000\", \"HBS\", \"HeBeiSheng\", 0));\r\n        areas.add(new AreaModel(24, 0, \"天津市\", \"120000\", \"TJS\", \"TianJinShi\", 0));\r\n        areas.add(new AreaModel(25, 0, \"山西省\", \"140000\", \"SXS\", \"ShanXiSheng\", 0));\r\n        areas.add(new AreaModel(26, 0, \"台湾省\", \"710000\", \"TWS\", \"TaiWanSheng\", 0));\r\n        areas.add(new AreaModel(27, 0, \"甘肃省\", \"620000\", \"GSS\", \"GanSuSheng\", 0));\r\n        areas.add(new AreaModel(28, 0, \"四川省\", \"510000\", \"SCS\", \"SiChuanSheng\", 0));\r\n        areas.add(new AreaModel(29, 0, \"云南省\", \"530000\", \"YNS\", \"YunNanSheng\", 0));\r\n        areas.add(new AreaModel(30, 0, \"北京市\", \"110000\", \"BJS\", \"BeiJingShi\", 0));\r\n        areas.add(new AreaModel(31, 0, \"香港特别行政区\", \"810000\", \"XGTBXZQ\", \"XiangGangTeBieXingZhengQu\", 0));\r\n        areas.add(new AreaModel(32, 0, \"澳门特别行政区\", \"820000\", \"AMTBXZQ\", \"AoMenTeBieXingZhengQu\", 0));\r\n        \r\n        areas.add(new AreaModel(100, 1, \"深圳市\", \"440300\", \"SZS\", \"ShenZhenShi\", 1));\r\n        areas.add(new AreaModel(101, 1, \"广州市\", \"440100\", \"GZS\", \"GuangZhouShi\", 0));\r\n        areas.add(new AreaModel(102, 1, \"东莞市\", \"441900\", \"DGS\", \"DongGuanShi\", 0));\r\n        areas.add(new AreaModel(103, 2, \"长沙市\", \"410005\", \"CSS\", \"ChangShaShi\", 1));\r\n        areas.add(new AreaModel(104, 2, \"岳阳市\", \"414000\", \"YYS\", \"YueYangShi\", 0));\r\n        \r\n        areas.add(new AreaModel(1000, 100, \"龙岗区\", \"518172\", \"LGQ\", \"LongGangQu\", 0));\r\n        areas.add(new AreaModel(1001, 100, \"南山区\", \"518051\", \"NSQ\", \"NanShanQu\", 0));\r\n        areas.add(new AreaModel(1002, 100, \"宝安区\", \"518101\", \"BAQ\", \"BaoAnQu\", 0));\r\n        areas.add(new AreaModel(1003, 100, \"福田区\", \"518081\", \"FTQ\", \"FuTianQu\", 0));\r\n        areas.add(new AreaModel(1004, 103, \"天心区\", \"410004\", \"TXQ\", \"TianXinQu\", 0));\r\n        areas.add(new AreaModel(1005, 103, \"开福区\", \"410008\", \"KFQ\", \"KaiFuQu\", 0));\r\n        areas.add(new AreaModel(1006, 103, \"芙蓉区\", \"410011\", \"FRQ\", \"FuRongQu\", 0));\r\n        areas.add(new AreaModel(1007, 103, \"雨花区\", \"410011\", \"YHQ\", \"YuHuaQu\", 0));\r\n    }\r\n\r\n    private final static List<UserTableColumn> columns = new ArrayList<UserTableColumn>();\r\n    {\r\n        columns.add(new UserTableColumn(\"用户ID\", \"userId\"));\r\n        columns.add(new UserTableColumn(\"用户编号\", \"userCode\"));\r\n        columns.add(new UserTableColumn(\"用户姓名\", \"userName\"));\r\n        columns.add(new UserTableColumn(\"用户手机\", \"userPhone\"));\r\n        columns.add(new UserTableColumn(\"用户邮箱\", \"userEmail\"));\r\n        columns.add(new UserTableColumn(\"用户状态\", \"status\"));\r\n    }\r\n    \r\n    private final static List<DocumentModel> documents = new ArrayList<DocumentModel>();\r\n    {\r\n        documents.add(new DocumentModel(1, \"247-XW·2024-D10-0001\", \"新闻热线[2024]000001\", \"索尼射击游戏《Concord》停止运营，玩家将获全额退款\", \"索尼宣布多人射击游戏《Concord》将于9月6日停止运营，玩家将获得全额退款。游戏总监Ryan Ellis在给玩家的信中表示，这款游戏首次发布“并没有像我们预期的那样顺利”。《Concord》的开发历时8年，投资超过1.5亿美元。游戏在Steam平台的售价为40美元，采用买断制销售模式。据SteamDB统计，游戏上市后的最高同时在线人数为697人。\"));\r\n        documents.add(new DocumentModel(2, \"247-XW·2024-D30-0002\", \"新闻热线[2024]000002\", \"网红账号被封，央媒：如此炫富毒瘤早就该拔了\", \"在社交平台上分享自己的生活日常，本来无可厚非。但无底线地展示物欲、宣扬拜金，取笑甚至嘲讽工薪者的烟火生活，就会遮蔽普通人的平凡质朴和坚韧奋斗，在无形中消解芸芸众生脚踏实地、自立自强的社会正气。对这种助长金钱至上、刺激公众焦虑，既污染网络生态，又撕裂社会和谐的炫富“毒瘤”，必须坚决拔除之。在国家有关部门的部署下，近日，多个网络平台开展“不良价值导向内容专项治理”行动，对“奢靡浪费”“炫富拜金”等问题从严打击，倡导理性、文明的消费观和价值观。\"));\r\n        documents.add(new DocumentModel(3, \"CT01-XW·2024-Y-0003\", \"新闻热线[2024]000003\", \"重庆一夫妻被骗至缅甸，家属：两人已被解救，预计很快能回国\", \"5月25日，重庆一对夫妻在前往泰国后失联，疑被诈骗集团骗至缅甸的消息引发广泛关注。警方已对此事立案调查，而这对夫妻的亲属则每天生活在焦急和不安之中。亲属：家都瘫痪了，事情一经曝光，迅速登上了热搜，成为公众热议的话题。据了解，这对夫妻原计划是去泰国谈生意，但不幸的是，他们的泰国之行变成了一场噩梦。亲属李先生透露，4月14日，他们夫妻二人抵达泰国，不久后便疑似被人以10万元的价格卖到缅甸，目前被困在缅甸妙瓦底的一个电信诈骗园区。\"));\r\n        documents.add(new DocumentModel(4, \"CT01-XW·2024-Y-0004\", \"新闻热线[2024]000004\", \"江滨社区联合派出所、金霞消防站开展电动自行车安全隐患夜查活动\", \"近日，长沙市开福区江滨社区联合派出所、金霞消防站深入居民小区、单位场所，以电动车自行车火灾防范为重点，开展消防安全夜查行动。此次夜查紧紧围绕老旧居民区、“三合一”场所、沿街门店、夜间经营使用场所等场所开展监督检查，重点检查电动自行车违规停放充电、堵塞疏散通道和安全出口，架空层违规作为电动自行车停放充电场所，电动自行车违规“进楼入户”“飞线充电”，电动自行车擅自改装等五大类问题。\"));\r\n        documents.add(new DocumentModel(5, \"CT01-XW·2024-Y-0005\", \"新闻热线[2024]000005\", \"《黑神话》让海外玩家迷上“悟空”\", \"备受全球玩家瞩目的首款国产3A游戏《黑神话：悟空》日前正式发布。精美绝伦的东方美学世界、精彩纷呈的中国神话故事、酣畅淋漓的游戏体验，这款游戏为全球玩家带来一场视觉与文化的双重盛宴。从“悟空”成功出海的背后，海外人士看到了中国游戏产业的巨大进步，感受到了中国文化的多元精彩，并对下一个“悟空”的诞生及更多中国文化产品走向世界充满期待。\"));\r\n        documents.add(new DocumentModel(6, \"CT01-XW·2024-Y-0006\", \"新闻热线[2024]000006\", \"市场状况充满挑战！极星宣布裁员全球约15%的员工\", \"据路透社报道，极星周五以“充满挑战的市场状况”为由，宣布计划在全球范围内裁减约450个职位。此次裁员之际，许多人都对电动汽车需求降温表示担忧，而且极星预计汽车业务最早将在2025年开始实现收支平衡。极星发言人表示：“作为该商业计划的一部分，我们需要调整我们的业务和运营规模。” “这涉及减少外部支出，遗憾的是，还包括我们的员工数量。”该公司还表示，希望减少对沃尔沃及其母公司吉利外部融资的依赖，最近还表示希望削减成本并提高电动汽车的利润率。\"));\r\n        documents.add(new DocumentModel(7, \"CT01-XW·2024-Y-0007\", \"新闻热线[2024]000007\", \"浙江隐秘富豪涉百亿非法集资案，部分资金流入新造车公司\", \"5月10日、11日，上海北广投资管理有限公司（下称“北广投”）非法集资案在上海黄浦区人民法院一审公开开庭审理，北广投实控人周敏、法定代表人朱江等30余名中高管被控非法吸收公众存款罪。根据财新报道，这一案件中，非法集资的资金有部分流入了两家新能源车企——爱驰汽车、万象汽车。同时，有多位投资人引述与经侦部门沟通时的说法称，该案事发时未兑付金额有130余亿元，其中去往广微控股45亿元、万象汽车63亿元、爱驰汽车15亿元。\"));\r\n        documents.add(new DocumentModel(8, \"CT01-XW·2024-Y-0008\", \"新闻热线[2024]000008\", \"特斯拉宣布Model Y升级：搭载HW4.0硬件，售价仍25.89万元起\", \"2月1日，特斯拉官方宣布ModelY升级。外观上，新增ModelY专属色“快银车漆”，并采用烈焰红代替中国红、星空灰代替冷光银；性能上，ModelY全系配备全新一代自动辅助驾驶硬件(HW4.0)，通过搭载超远距离双目摄像头，ModelY的最远探测距离达424米。由此，特斯拉全系车型均配备了自动辅助驾驶硬件HW4.0。在售价方面，特斯拉中国官网显示，ModelY车型依然保持原价。ModelY后轮驱动版25.89万元起、ModelY长续航版29.99万元起、ModelY高性能版售价36.39万元起。\"));\r\n        documents.add(new DocumentModel(9, \"CT01-XW·2024-D10-0009\", \"新闻热线[2024]000009\", \"华为手机归来，谁最受伤？\", \"低迷周期下的智能手机市场在2023年下半年迎来了华为的回归，这也给本就竞争激烈的市场环境带来了更大变数。1月29日，有消息称，华为已注册“星耀手机”品牌商标，定位中端手机市场，但上述消息并未获得华为方面确认。“目前星耀的相关信息我们看到了，但是没有获得产品信息以及启动线下铺货的通知。对于和其他品牌的二选一问题，听其他省份的经销商说过，但目前（华为渠道）这边也没有更多动作。”一位广东区域的华为核心经销商对记者说。但华为手机的反扑已经开始。在多家调研机构公布的2023年四季度智能手机出货数据中，华为手机的量正在明显上升，当季增幅在35%到47%之间。不过，从全年数据来看，并未登上前五榜单。\"));\r\n        documents.add(new DocumentModel(10, \"CT01-XW·2024-D10-0010\", \"新闻热线[2024]000010\", \"疯狂裁员的硅谷大厂：除了AI，其它都是将就\", \"放眼望去，近期科技企业财报形势一片大好，裁员浪潮却仍在不断蔓延。国内职场动态看脉脉，那硅谷裁员情况就得看layoff.fyi了。数据显示，2024年，103家科技企业进行了裁员，28963位员工失去了饭碗。其中，电子支付公司PayPal大笔一挥，裁掉2500人，微软则在开年就裁掉1900人。回望2023年，谷歌、Meta、亚马逊、微软均为裁员重灾区，裁员人数在一万左右。具体而言，谷歌近日披露的财报指出，2023年谷歌解雇了12000多名员工，光是在遣散费和其他费用上就花费了21亿美元。而且裁员费用还在不断增加，2024年刚过去一个月，谷歌就已经花费了7亿美元用来裁员。\"));\r\n        documents.add(new DocumentModel(11, \"CT01-XW·2024-D30-0011\", \"新闻热线[2024]000011\", \"国产手机品牌重新崛起背后：市场正在逐步恢复活力，竞争也愈发激烈\", \"2024年伊始，随着全球经济的逐渐复苏，手机消费市场也展现出勃勃生机。中国信通院最新数据显示，2023年中国市场手机出货量实现了6.5%的同比增长，其中5G手机增长势头更为强劲，占比高达82.8%。1月25日，国际数据公司（IDC）发布了最新手机季度跟踪报告，揭示了中国智能手机市场在2023年第四季度的出货量情况。报告显示，该季度中国智能手机市场出货量达到了约7363万台，同比增长1.2%。这是在连续十个季度同比下降后，中国智能手机市场首次实现反弹。这一积极信号表明，市场正在逐步恢复活力，各大品牌之间的竞争也愈发激烈。\"));\r\n        documents.add(new DocumentModel(12, \"CT01-XW·2024-D30-0012\", \"新闻热线[2024]000012\", \"SpaceX将于1月31日向国际空间站发射天鹅号货运飞船\", \"1月29日消息，美国太空探索技术公司SpaceX计划于当地时间1月30日，利用“猎鹰9号”火箭从佛罗里达州肯尼迪航天中心发射诺斯罗普·格鲁曼公司的“天鹅号”货运飞船至国际空间站。此次任务是执行NG-20商业补给，将运送约8200多磅的物资、设备及科学实验器材。\"));\r\n    }\r\n\r\n    /**\r\n     * 搜索相关\r\n     */\r\n    @GetMapping(\"/search\")\r\n    public String search()\r\n    {\r\n        return prefix + \"/search\";\r\n    }\r\n\r\n    /**\r\n     * 数据汇总\r\n     */\r\n    @GetMapping(\"/footer\")\r\n    public String footer()\r\n    {\r\n        return prefix + \"/footer\";\r\n    }\r\n\r\n    /**\r\n     * 组合表头\r\n     */\r\n    @GetMapping(\"/groupHeader\")\r\n    public String groupHeader()\r\n    {\r\n        return prefix + \"/groupHeader\";\r\n    }\r\n\r\n    /**\r\n     * 表格导出\r\n     */\r\n    @GetMapping(\"/export\")\r\n    public String export()\r\n    {\r\n        return prefix + \"/export\";\r\n    }\r\n\r\n    /**\r\n     * 表格导出选择列\r\n     */\r\n    @GetMapping(\"/exportSelected\")\r\n    public String exportSelected()\r\n    {\r\n        return prefix + \"/exportSelected\";\r\n    }\r\n\r\n    /**\r\n     * 导出数据\r\n     */\r\n    @PostMapping(\"/exportData\")\r\n    @ResponseBody\r\n    public AjaxResult exportSelected(UserTableModel userModel, String userIds)\r\n    {\r\n        List<UserTableModel> userList = new ArrayList<UserTableModel>(Arrays.asList(new UserTableModel[users.size()]));\r\n        Collections.copy(userList, users);\r\n\r\n        // 条件过滤\r\n        if (StringUtils.isNotEmpty(userIds))\r\n        {\r\n            userList.clear();\r\n            for (Long userId : Convert.toLongArray(userIds))\r\n            {\r\n                for (UserTableModel user : users)\r\n                {\r\n                    if (user.getUserId() == userId)\r\n                    {\r\n                        userList.add(user);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        ExcelUtil<UserTableModel> util = new ExcelUtil<UserTableModel>(UserTableModel.class);\r\n        return util.exportExcel(userList, \"用户数据\");\r\n    }\r\n\r\n    /**\r\n     * 翻页记住选择\r\n     */\r\n    @GetMapping(\"/remember\")\r\n    public String remember()\r\n    {\r\n        return prefix + \"/remember\";\r\n    }\r\n\r\n    /**\r\n     * 表格保存状态\r\n     */\r\n    @GetMapping(\"/cookie\")\r\n    public String cookie()\r\n    {\r\n        return prefix + \"/cookie\";\r\n    }\r\n\r\n    /**\r\n     * 跳转至指定页\r\n     */\r\n    @GetMapping(\"/pageGo\")\r\n    public String pageGo()\r\n    {\r\n        return prefix + \"/pageGo\";\r\n    }\r\n\r\n    /**\r\n     * 自定义查询参数\r\n     */\r\n    @GetMapping(\"/params\")\r\n    public String params()\r\n    {\r\n        return prefix + \"/params\";\r\n    }\r\n\r\n    /**\r\n     * 多表格\r\n     */\r\n    @GetMapping(\"/multi\")\r\n    public String multi()\r\n    {\r\n        return prefix + \"/multi\";\r\n    }\r\n\r\n    /**\r\n     * 点击按钮加载表格\r\n     */\r\n    @GetMapping(\"/button\")\r\n    public String button()\r\n    {\r\n        return prefix + \"/button\";\r\n    }\r\n\r\n    /**\r\n     * 直接加载表格数据\r\n     */\r\n    @GetMapping(\"/data\")\r\n    public String data(ModelMap mmap)\r\n    {\r\n        mmap.put(\"users\", users);\r\n        return prefix + \"/data\";\r\n    }\r\n\r\n    /**\r\n     * 表格冻结列\r\n     */\r\n    @GetMapping(\"/fixedColumns\")\r\n    public String fixedColumns()\r\n    {\r\n        return prefix + \"/fixedColumns\";\r\n    }\r\n\r\n    /**\r\n     * 自定义触发事件\r\n     */\r\n    @GetMapping(\"/event\")\r\n    public String event()\r\n    {\r\n        return prefix + \"/event\";\r\n    }\r\n\r\n    /**\r\n     * 表格细节视图\r\n     */\r\n    @GetMapping(\"/detail\")\r\n    public String detail()\r\n    {\r\n        return prefix + \"/detail\";\r\n    }\r\n\r\n    /**\r\n     * 表格父子视图\r\n     */\r\n    @GetMapping(\"/child\")\r\n    public String child()\r\n    {\r\n        return prefix + \"/child\";\r\n    }\r\n\r\n    /**\r\n     * 表格图片预览\r\n     */\r\n    @GetMapping(\"/image\")\r\n    public String image()\r\n    {\r\n        return prefix + \"/image\";\r\n    }\r\n\r\n    /**\r\n     * 动态增删改查\r\n     */\r\n    @GetMapping(\"/curd\")\r\n    public String curd()\r\n    {\r\n        return prefix + \"/curd\";\r\n    }\r\n\r\n    /**\r\n     * 表格行拖拽操作\r\n     */\r\n    @GetMapping(\"/reorderRows\")\r\n    public String reorderRows()\r\n    {\r\n        return prefix + \"/reorderRows\";\r\n    }\r\n\r\n    /**\r\n     * 表格列拖拽操作\r\n     */\r\n    @GetMapping(\"/reorderColumns\")\r\n    public String reorderColumns()\r\n    {\r\n        return prefix + \"/reorderColumns\";\r\n    }\r\n\r\n    /**\r\n     * 表格列宽拖动\r\n     */\r\n    @GetMapping(\"/resizable\")\r\n    public String resizable()\r\n    {\r\n        return prefix + \"/resizable\";\r\n    }\r\n\r\n    /**\r\n     * 表格行内编辑操作\r\n     */\r\n    @GetMapping(\"/editable\")\r\n    public String editable()\r\n    {\r\n        return prefix + \"/editable\";\r\n    }\r\n\r\n    /**\r\n     * 主子表提交\r\n     */\r\n    @GetMapping(\"/subdata\")\r\n    public String subdata()\r\n    {\r\n        return prefix + \"/subdata\";\r\n    }\r\n\r\n    /**\r\n     * 表格自动刷新\r\n     */\r\n    @GetMapping(\"/refresh\")\r\n    public String refresh()\r\n    {\r\n        return prefix + \"/refresh\";\r\n    }\r\n\r\n    /**\r\n     * 表格打印配置\r\n     */\r\n    @GetMapping(\"/print\")\r\n    public String print()\r\n    {\r\n        return prefix + \"/print\";\r\n    }\r\n\r\n    /**\r\n     * 表格标题格式化\r\n     */\r\n    @GetMapping(\"/headerStyle\")\r\n    public String headerStyle()\r\n    {\r\n        return prefix + \"/headerStyle\";\r\n    }\r\n\r\n    /**\r\n     * 表格动态列\r\n     */\r\n    @GetMapping(\"/dynamicColumns\")\r\n    public String dynamicColumns()\r\n    {\r\n        return prefix + \"/dynamicColumns\";\r\n    }\r\n\r\n    /**\r\n     * 表格虚拟滚动\r\n     */\r\n    @GetMapping(\"/virtualScroll\")\r\n    public String virtualScroll()\r\n    {\r\n        return prefix + \"/virtualScroll\";\r\n    }\r\n\r\n    /**\r\n     * 自定义视图分页\r\n     */\r\n    @GetMapping(\"/customView\")\r\n    public String customView()\r\n    {\r\n        return prefix + \"/customView\";\r\n    }\r\n\r\n    /**\r\n     * 全文索引\r\n     */\r\n    @GetMapping(\"/textSearch\")\r\n    public String textSearch()\r\n    {\r\n        return prefix + \"/textSearch\";\r\n    }\r\n\r\n    /**\r\n     * 异步加载表格树\r\n     */\r\n    @GetMapping(\"/asynTree\")\r\n    public String asynTree()\r\n    {\r\n        return prefix + \"/asynTree\";\r\n    }\r\n\r\n    /**\r\n     * 表格其他操作\r\n     */\r\n    @GetMapping(\"/other\")\r\n    public String other()\r\n    {\r\n        return prefix + \"/other\";\r\n    }\r\n\r\n    /**\r\n     * 动态获取列\r\n     */\r\n    @PostMapping(\"/ajaxColumns\")\r\n    @ResponseBody\r\n    public AjaxResult ajaxColumns(UserTableColumn userColumn)\r\n    {\r\n        List<UserTableColumn> columnList = new ArrayList<UserTableColumn>(Arrays.asList(new UserTableColumn[columns.size()]));\r\n        Collections.copy(columnList, columns);\r\n        if (userColumn != null && \"userBalance\".equals(userColumn.getField()))\r\n        {\r\n            columnList.add(new UserTableColumn(\"用户余额\", \"userBalance\"));\r\n        }\r\n        return AjaxResult.success(columnList);\r\n    }\r\n\r\n    /**\r\n     * 查询数据\r\n     */\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(UserTableModel userModel)\r\n    {\r\n        TableDataInfo rspData = new TableDataInfo();\r\n        List<UserTableModel> userList = new ArrayList<UserTableModel>(Arrays.asList(new UserTableModel[users.size()]));\r\n        Collections.copy(userList, users);\r\n        // 查询条件过滤\r\n        if (StringUtils.isNotEmpty(userModel.getUserName()))\r\n        {\r\n            userList.clear();\r\n            for (UserTableModel user : users)\r\n            {\r\n                if (user.getUserName().equals(userModel.getUserName()))\r\n                {\r\n                    userList.add(user);\r\n                }\r\n            }\r\n        }\r\n        PageDomain pageDomain = TableSupport.buildPageRequest();\r\n        if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize())\r\n        {\r\n            rspData.setRows(userList);\r\n            rspData.setTotal(userList.size());\r\n            return rspData;\r\n        }\r\n        Integer pageNum = (pageDomain.getPageNum() - 1) * 10;\r\n        Integer pageSize = pageDomain.getPageNum() * 10;\r\n        if (pageSize > userList.size())\r\n        {\r\n            pageSize = userList.size();\r\n        }\r\n        rspData.setRows(userList.subList(pageNum, pageSize));\r\n        rspData.setTotal(userList.size());\r\n        return rspData;\r\n    }\r\n\r\n    /**\r\n     * 查询全文索引数据\r\n     */\r\n    @PostMapping(\"/text/list\")\r\n    @ResponseBody\r\n    public TableDataInfo textList(BaseEntity baseEntity)\r\n    {\r\n        TableDataInfo rspData = new TableDataInfo();\r\n        List<DocumentModel> documentList = new ArrayList<DocumentModel>(Arrays.asList(new DocumentModel[documents.size()]));\r\n        Collections.copy(documentList, documents);\r\n        // 查询条件过滤\r\n        if (StringUtils.isNotEmpty(baseEntity.getSearchValue()))\r\n        {\r\n            documentList.clear();\r\n            for (DocumentModel document : documents)\r\n            {\r\n                boolean indexFlag = false;\r\n                if (document.getTitle().contains(baseEntity.getSearchValue()))\r\n                {\r\n                    indexFlag = true;\r\n                    document.setTitle(document.getTitle().replace(baseEntity.getSearchValue(), \"<font color=\\\"red\\\">\" + baseEntity.getSearchValue() + \"</font>\"));\r\n                }\r\n                if (document.getContent().contains(baseEntity.getSearchValue()))\r\n                {\r\n                    indexFlag = true;\r\n                    document.setContent(document.getContent().replace(baseEntity.getSearchValue(), \"<font color=\\\"red\\\">\" + baseEntity.getSearchValue() + \"</font>\"));\r\n                }\r\n                if (indexFlag)\r\n                {\r\n                    documentList.add(document);\r\n                }\r\n            }\r\n        }\r\n        PageDomain pageDomain = TableSupport.buildPageRequest();\r\n        if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize())\r\n        {\r\n            rspData.setRows(documentList);\r\n            rspData.setTotal(documentList.size());\r\n            return rspData;\r\n        }\r\n        Integer pageNum = (pageDomain.getPageNum() - 1) * 10;\r\n        Integer pageSize = pageDomain.getPageNum() * 10;\r\n        if (pageSize > documentList.size())\r\n        {\r\n            pageSize = documentList.size();\r\n        }\r\n        rspData.setRows(documentList.subList(pageNum, pageSize));\r\n        rspData.setTotal(documentList.size());\r\n        return rspData;\r\n    }\r\n\r\n    /**\r\n     * 查询树表数据\r\n     */\r\n    @PostMapping(\"/tree/list\")\r\n    @ResponseBody\r\n    public TableDataInfo treeList(AreaModel areaModel)\r\n    {\r\n        TableDataInfo rspData = new TableDataInfo();\r\n        List<AreaModel> areaList = new ArrayList<AreaModel>(Arrays.asList(new AreaModel[areas.size()]));\r\n        // 默认查询条件 parentId 0\r\n        Collections.copy(areaList, areas);\r\n        areaList.clear();\r\n        if (StringUtils.isNotEmpty(areaModel.getAreaName()))\r\n        {\r\n            for (AreaModel area : areas)\r\n            {\r\n                if (area.getParentId() == 0 && area.getAreaName().equals(areaModel.getAreaName()))\r\n                {\r\n                    areaList.add(area);\r\n                }\r\n            }\r\n        }\r\n        else\r\n        {\r\n            for (AreaModel area : areas)\r\n            {\r\n                if (area.getParentId() == 0)\r\n                {\r\n                    areaList.add(area);\r\n                }\r\n            }\r\n        }\r\n        PageDomain pageDomain = TableSupport.buildPageRequest();\r\n        Integer pageNum = (pageDomain.getPageNum() - 1) * pageDomain.getPageSize();\r\n        Integer pageSize = pageDomain.getPageNum() * pageDomain.getPageSize();\r\n        if (pageSize > areaList.size())\r\n        {\r\n            pageSize = areaList.size();\r\n        }\r\n        rspData.setRows(areaList.subList(pageNum, pageSize));\r\n        rspData.setTotal(areaList.size());\r\n        return rspData;\r\n    }\r\n\r\n    /**\r\n     * 查询树表子节点数据\r\n     */\r\n    @PostMapping(\"/tree/listChild\")\r\n    @ResponseBody\r\n    public List<AreaModel> listChild(AreaModel areaModel)\r\n    {\r\n        List<AreaModel> areaList = new ArrayList<AreaModel>(Arrays.asList(new AreaModel[areas.size()]));\r\n        // 查询条件 parentId\r\n        Collections.copy(areaList, areas);\r\n        areaList.clear();\r\n        if (StringUtils.isNotEmpty(areaModel.getAreaName()))\r\n        {\r\n            for (AreaModel area : areas)\r\n            {\r\n                if (area.getParentId().intValue() == areaModel.getParentId().intValue() && area.getAreaName().equals(areaModel.getAreaName()))\r\n                {\r\n                    areaList.add(area);\r\n                }\r\n            }\r\n        }\r\n        else\r\n        {\r\n            for (AreaModel area : areas)\r\n            {\r\n                if (area.getParentId().intValue() == areaModel.getParentId().intValue())\r\n                {\r\n                    areaList.add(area);\r\n                }\r\n            }\r\n        }\r\n        return areaList;\r\n    }\r\n}\r\n\r\nclass UserTableColumn\r\n{\r\n    /** 表头 */\r\n    private String title;\r\n    /** 字段 */\r\n    private String field;\r\n\r\n    public UserTableColumn()\r\n    {\r\n\r\n    }\r\n\r\n    public UserTableColumn(String title, String field)\r\n    {\r\n        this.title = title;\r\n        this.field = field;\r\n    }\r\n\r\n    public String getTitle()\r\n    {\r\n        return title;\r\n    }\r\n\r\n    public void setTitle(String title)\r\n    {\r\n        this.title = title;\r\n    }\r\n\r\n    public String getField()\r\n    {\r\n        return field;\r\n    }\r\n\r\n    public void setField(String field)\r\n    {\r\n        this.field = field;\r\n    }\r\n}\r\n\r\nclass UserTableModel\r\n{\r\n    /** 用户ID */\r\n    private int userId;\r\n\r\n    /** 用户编号 */\r\n    @Excel(name = \"用户编号\", cellType = ColumnType.NUMERIC)\r\n    private String userCode;\r\n\r\n    /** 用户姓名 */\r\n    @Excel(name = \"用户姓名\")\r\n    private String userName;\r\n\r\n    /** 用户性别 */\r\n    private String userSex;\r\n\r\n    /** 用户手机 */\r\n    @Excel(name = \"用户手机\")\r\n    private String userPhone;\r\n\r\n    /** 用户邮箱 */\r\n    @Excel(name = \"用户邮箱\")\r\n    private String userEmail;\r\n\r\n    /** 用户余额 */\r\n    @Excel(name = \"用户余额\", cellType = ColumnType.NUMERIC)\r\n    private double userBalance;\r\n\r\n    /** 用户状态（0正常 1停用） */\r\n    private String status;\r\n\r\n    /** 创建时间 */\r\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")\r\n    private Date createTime;\r\n\r\n    public UserTableModel()\r\n    {\r\n\r\n    }\r\n\r\n    public UserTableModel(int userId, String userCode, String userName, String userSex, String userPhone,\r\n            String userEmail, double userBalance, String status)\r\n    {\r\n        this.userId = userId;\r\n        this.userCode = userCode;\r\n        this.userName = userName;\r\n        this.userSex = userSex;\r\n        this.userPhone = userPhone;\r\n        this.userEmail = userEmail;\r\n        this.userBalance = userBalance;\r\n        this.status = status;\r\n        this.createTime = DateUtils.getNowDate();\r\n    }\r\n\r\n    public int getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n\r\n    public void setUserId(int userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public String getUserCode()\r\n    {\r\n        return userCode;\r\n    }\r\n\r\n    public void setUserCode(String userCode)\r\n    {\r\n        this.userCode = userCode;\r\n    }\r\n\r\n    public String getUserName()\r\n    {\r\n        return userName;\r\n    }\r\n\r\n    public void setUserName(String userName)\r\n    {\r\n        this.userName = userName;\r\n    }\r\n\r\n    public String getUserSex()\r\n    {\r\n        return userSex;\r\n    }\r\n\r\n    public void setUserSex(String userSex)\r\n    {\r\n        this.userSex = userSex;\r\n    }\r\n\r\n    public String getUserPhone()\r\n    {\r\n        return userPhone;\r\n    }\r\n\r\n    public void setUserPhone(String userPhone)\r\n    {\r\n        this.userPhone = userPhone;\r\n    }\r\n\r\n    public String getUserEmail()\r\n    {\r\n        return userEmail;\r\n    }\r\n\r\n    public void setUserEmail(String userEmail)\r\n    {\r\n        this.userEmail = userEmail;\r\n    }\r\n\r\n    public double getUserBalance()\r\n    {\r\n        return userBalance;\r\n    }\r\n\r\n    public void setUserBalance(double userBalance)\r\n    {\r\n        this.userBalance = userBalance;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public Date getCreateTime()\r\n    {\r\n        return createTime;\r\n    }\r\n\r\n    public void setCreateTime(Date createTime)\r\n    {\r\n        this.createTime = createTime;\r\n    }\r\n}\r\nclass AreaModel\r\n{\r\n    /** 编号 */\r\n    private Long id;\r\n\r\n    /** 父编号 */\r\n    private Long parentId;\r\n\r\n    /** 区域名称 */\r\n    private String areaName;\r\n\r\n    /** 区域代码 */\r\n    private String areaCode;\r\n\r\n    /** 名称首字母 */\r\n    private String simplePy;\r\n\r\n    /** 名称全拼 */\r\n    private String pinYin;\r\n\r\n    /** 是否有子节点（0无 1有） */\r\n    private Integer isTreeLeaf = 1;\r\n\r\n    public AreaModel()\r\n    {\r\n\r\n    }\r\n\r\n    public AreaModel(int id, int parentId, String areaName, String areaCode, String simplePy, String pinYin, Integer isTreeLeaf)\r\n    {\r\n        this.id = Long.valueOf(id);\r\n        this.parentId = Long.valueOf(parentId);\r\n        this.areaName = areaName;\r\n        this.areaCode = areaCode;\r\n        this.simplePy = simplePy;\r\n        this.pinYin = pinYin;\r\n        this.isTreeLeaf = isTreeLeaf;\r\n    }\r\n\r\n    public Long getId()\r\n    {\r\n        return id;\r\n    }\r\n\r\n    public void setId(Long id)\r\n    {\r\n        this.id = id;\r\n    }\r\n\r\n    public Long getParentId()\r\n    {\r\n        return parentId;\r\n    }\r\n\r\n    public void setParentId(Long parentId)\r\n    {\r\n        this.parentId = parentId;\r\n    }\r\n\r\n    public String getAreaName()\r\n    {\r\n        return areaName;\r\n    }\r\n\r\n    public void setAreaName(String areaName)\r\n    {\r\n        this.areaName = areaName;\r\n    }\r\n\r\n    public String getAreaCode()\r\n    {\r\n        return areaCode;\r\n    }\r\n\r\n    public void setAreaCode(String areaCode)\r\n    {\r\n        this.areaCode = areaCode;\r\n    }\r\n\r\n    public String getSimplePy()\r\n    {\r\n        return simplePy;\r\n    }\r\n\r\n    public void setSimplePy(String simplePy)\r\n    {\r\n        this.simplePy = simplePy;\r\n    }\r\n\r\n    public String getPinYin()\r\n    {\r\n        return pinYin;\r\n    }\r\n\r\n    public void setPinYin(String pinYin)\r\n    {\r\n        this.pinYin = pinYin;\r\n    }\r\n\r\n    public Integer getIsTreeLeaf()\r\n    {\r\n        return isTreeLeaf;\r\n    }\r\n\r\n    public void setIsTreeLeaf(Integer isTreeLeaf)\r\n    {\r\n        this.isTreeLeaf = isTreeLeaf;\r\n    }\r\n}\r\n\r\nclass DocumentModel\r\n{\r\n    /** 编号 */\r\n    private int tableId;\r\n\r\n    /** 档号 */\r\n    private String archiveNo;\r\n\r\n    /** 文件编号 */\r\n    private String docNo;\r\n\r\n    /** 标题 */\r\n    private String title;\r\n\r\n    /** 内容 */\r\n    private String content;\r\n\r\n    public DocumentModel()\r\n    {\r\n\r\n    }\r\n\r\n    public DocumentModel(int tableId, String archiveNo, String docNo, String title, String content)\r\n    {\r\n        this.tableId = tableId;\r\n        this.archiveNo = archiveNo;\r\n        this.docNo = docNo;\r\n        this.title = title;\r\n        this.content = content;\r\n    }\r\n\r\n    public int getTableId()\r\n    {\r\n        return tableId;\r\n    }\r\n\r\n    public String getArchiveNo()\r\n    {\r\n        return archiveNo;\r\n    }\r\n\r\n    public String getDocNo()\r\n    {\r\n        return docNo;\r\n    }\r\n\r\n    public String getTitle()\r\n    {\r\n        return title;\r\n    }\r\n\r\n    public String getContent()\r\n    {\r\n        return content;\r\n    }\r\n\r\n    public void setTableId(int tableId)\r\n    {\r\n        this.tableId = tableId;\r\n    }\r\n\r\n    public void setArchiveNo(String archiveNo)\r\n    {\r\n        this.archiveNo = archiveNo;\r\n    }\r\n\r\n    public void setDocNo(String docNo)\r\n    {\r\n        this.docNo = docNo;\r\n    }\r\n\r\n    public void setTitle(String title)\r\n    {\r\n        this.title = title;\r\n    }\r\n\r\n    public void setContent(String content)\r\n    {\r\n        this.content = content;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/CustomerModel.java",
    "content": "package com.ruoyi.web.controller.demo.domain;\r\n\r\nimport java.util.List;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\n\r\n/**\r\n * 客户测试信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class CustomerModel\r\n{\r\n    /**\r\n     * 客户姓名\r\n     */\r\n    private String name;\r\n\r\n    /**\r\n     * 客户手机\r\n     */\r\n    private String phonenumber;\r\n\r\n    /**\r\n     * 客户性别\r\n     */\r\n    private String sex;\r\n\r\n    /**\r\n     * 客户生日\r\n     */\r\n    private String birthday;\r\n\r\n    /**\r\n     * 客户描述\r\n     */\r\n    private String remark;\r\n\r\n    /**\r\n     * 商品信息\r\n     */\r\n    private List<GoodsModel> goods;\r\n\r\n    public String getName()\r\n    {\r\n        return name;\r\n    }\r\n\r\n    public void setName(String name)\r\n    {\r\n        this.name = name;\r\n    }\r\n\r\n    public String getPhonenumber()\r\n    {\r\n        return phonenumber;\r\n    }\r\n\r\n    public void setPhonenumber(String phonenumber)\r\n    {\r\n        this.phonenumber = phonenumber;\r\n    }\r\n\r\n\r\n    public String getSex()\r\n    {\r\n        return sex;\r\n    }\r\n\r\n    public void setSex(String sex)\r\n    {\r\n        this.sex = sex;\r\n    }\r\n\r\n    public String getBirthday()\r\n    {\r\n        return birthday;\r\n    }\r\n\r\n    public void setBirthday(String birthday)\r\n    {\r\n        this.birthday = birthday;\r\n    }\r\n\r\n    public String getRemark()\r\n    {\r\n        return remark;\r\n    }\r\n\r\n    public void setRemark(String remark)\r\n    {\r\n        this.remark = remark;\r\n    }\r\n\r\n    public List<GoodsModel> getGoods()\r\n    {\r\n        return goods;\r\n    }\r\n\r\n    public void setGoods(List<GoodsModel> goods)\r\n    {\r\n        this.goods = goods;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"name\", getName())\r\n            .append(\"phonenumber\", getPhonenumber())\r\n            .append(\"sex\", getSex())\r\n            .append(\"birthday\", getBirthday())\r\n            .append(\"goods\", getGoods())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/GoodsModel.java",
    "content": "package com.ruoyi.web.controller.demo.domain;\r\n\r\nimport java.util.Date;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\n\r\n/**\r\n * 商品测试信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class GoodsModel\r\n{\r\n    /**\r\n     * 商品名称\r\n     */\r\n    private String name;\r\n\r\n    /**\r\n     * 商品重量\r\n     */\r\n    private Integer weight;\r\n\r\n    /**\r\n     * 商品价格\r\n     */\r\n    private Double price;\r\n    \r\n    /**\r\n     * 商品日期\r\n     */\r\n    private Date date;\r\n\r\n    /**\r\n     * 商品种类\r\n     */\r\n    private String type;\r\n\r\n    public String getName()\r\n    {\r\n        return name;\r\n    }\r\n\r\n    public void setName(String name)\r\n    {\r\n        this.name = name;\r\n    }\r\n\r\n    public Integer getWeight()\r\n    {\r\n        return weight;\r\n    }\r\n\r\n    public void setWeight(Integer weight)\r\n    {\r\n        this.weight = weight;\r\n    }\r\n\r\n    public Double getPrice()\r\n    {\r\n        return price;\r\n    }\r\n\r\n    public void setPrice(Double price)\r\n    {\r\n        this.price = price;\r\n    }\r\n\r\n    public Date getDate()\r\n    {\r\n        return date;\r\n    }\r\n\r\n    public void setDate(Date date)\r\n    {\r\n        this.date = date;\r\n    }\r\n\r\n    public String getType()\r\n    {\r\n        return type;\r\n    }\r\n\r\n    public void setType(String type)\r\n    {\r\n        this.type = type;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"name\", getName())\r\n            .append(\"weight\", getWeight())\r\n            .append(\"price\", getPrice())\r\n            .append(\"date\", getDate())\r\n            .append(\"type\", getType())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/UserOperateModel.java",
    "content": "package com.ruoyi.web.controller.demo.domain;\r\n\r\nimport java.util.Date;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.Type;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.utils.DateUtils;\r\n\r\npublic class UserOperateModel extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private int userId;\r\n\r\n    @Excel(name = \"用户编号\")\r\n    private String userCode;\r\n\r\n    @Excel(name = \"用户姓名\")\r\n    private String userName;\r\n\r\n    @Excel(name = \"用户性别\", readConverterExp = \"0=男,1=女,2=未知\")\r\n    private String userSex;\r\n\r\n    @Excel(name = \"用户手机\")\r\n    private String userPhone;\r\n\r\n    @Excel(name = \"用户邮箱\")\r\n    private String userEmail;\r\n\r\n    @Excel(name = \"用户余额\")\r\n    private double userBalance;\r\n\r\n    @Excel(name = \"用户状态\", readConverterExp = \"0=正常,1=停用\")\r\n    private String status;\r\n\r\n    @Excel(name = \"创建时间\", width = 30, dateFormat = \"yyyy-MM-dd HH:mm:ss\", type = Type.EXPORT)\r\n    private Date createTime;\r\n\r\n    public UserOperateModel()\r\n    {\r\n\r\n    }\r\n\r\n    public UserOperateModel(int userId, String userCode, String userName, String userSex, String userPhone,\r\n            String userEmail, double userBalance, String status)\r\n    {\r\n        this.userId = userId;\r\n        this.userCode = userCode;\r\n        this.userName = userName;\r\n        this.userSex = userSex;\r\n        this.userPhone = userPhone;\r\n        this.userEmail = userEmail;\r\n        this.userBalance = userBalance;\r\n        this.status = status;\r\n        this.createTime = DateUtils.getNowDate();\r\n    }\r\n\r\n    public int getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n\r\n    public void setUserId(int userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public String getUserCode()\r\n    {\r\n        return userCode;\r\n    }\r\n\r\n    public void setUserCode(String userCode)\r\n    {\r\n        this.userCode = userCode;\r\n    }\r\n\r\n    public String getUserName()\r\n    {\r\n        return userName;\r\n    }\r\n\r\n    public void setUserName(String userName)\r\n    {\r\n        this.userName = userName;\r\n    }\r\n\r\n    public String getUserSex()\r\n    {\r\n        return userSex;\r\n    }\r\n\r\n    public void setUserSex(String userSex)\r\n    {\r\n        this.userSex = userSex;\r\n    }\r\n\r\n    public String getUserPhone()\r\n    {\r\n        return userPhone;\r\n    }\r\n\r\n    public void setUserPhone(String userPhone)\r\n    {\r\n        this.userPhone = userPhone;\r\n    }\r\n\r\n    public String getUserEmail()\r\n    {\r\n        return userEmail;\r\n    }\r\n\r\n    public void setUserEmail(String userEmail)\r\n    {\r\n        this.userEmail = userEmail;\r\n    }\r\n\r\n    public double getUserBalance()\r\n    {\r\n        return userBalance;\r\n    }\r\n\r\n    public void setUserBalance(double userBalance)\r\n    {\r\n        this.userBalance = userBalance;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    @Override\r\n    public Date getCreateTime()\r\n    {\r\n        return createTime;\r\n    }\r\n\r\n    @Override\r\n    public void setCreateTime(Date createTime)\r\n    {\r\n        this.createTime = createTime;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java",
    "content": "package com.ruoyi.web.controller.monitor;\r\n\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.framework.web.service.CacheService;\r\n\r\n/**\r\n * 缓存监控\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/cache\")\r\npublic class CacheController extends BaseController\r\n{\r\n    private String prefix = \"monitor/cache\";\r\n\r\n    @Autowired\r\n    private CacheService cacheService;\r\n\r\n    @RequiresPermissions(\"monitor:cache:view\")\r\n    @GetMapping()\r\n    public String cache(ModelMap mmap)\r\n    {\r\n        mmap.put(\"cacheNames\", cacheService.getCacheNames());\r\n        return prefix + \"/cache\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:cache:view\")\r\n    @PostMapping(\"/getNames\")\r\n    public String getCacheNames(ModelMap mmap)\r\n    {\r\n        mmap.put(\"cacheNames\", cacheService.getCacheNames());\r\n        return prefix + \"/cache::fragment-cache-names\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:cache:view\")\r\n    @PostMapping(\"/getKeys\")\r\n    public String getCacheKeys(String cacheName, ModelMap mmap)\r\n    {\r\n        mmap.put(\"cacheName\", cacheName);\r\n        mmap.put(\"cacheKeys\", cacheService.getCacheKeys(cacheName));\r\n        return prefix + \"/cache::fragment-cache-kyes\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:cache:view\")\r\n    @PostMapping(\"/getValue\")\r\n    public String getCacheValue(String cacheName, String cacheKey, ModelMap mmap)\r\n    {\r\n        mmap.put(\"cacheName\", cacheName);\r\n        mmap.put(\"cacheKey\", cacheKey);\r\n        mmap.put(\"cacheValue\", cacheService.getCacheValue(cacheName, cacheKey));\r\n        return prefix + \"/cache::fragment-cache-value\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:cache:view\")\r\n    @PostMapping(\"/clearCacheName\")\r\n    @ResponseBody\r\n    public AjaxResult clearCacheName(String cacheName, ModelMap mmap)\r\n    {\r\n        cacheService.clearCacheName(cacheName);\r\n        return AjaxResult.success();\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:cache:view\")\r\n    @PostMapping(\"/clearCacheKey\")\r\n    @ResponseBody\r\n    public AjaxResult clearCacheKey(String cacheName, String cacheKey, ModelMap mmap)\r\n    {\r\n        cacheService.clearCacheKey(cacheName, cacheKey);\r\n        return AjaxResult.success();\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:cache:view\")\r\n    @GetMapping(\"/clearAll\")\r\n    @ResponseBody\r\n    public AjaxResult clearAll(ModelMap mmap)\r\n    {\r\n        cacheService.clearAll();\r\n        return AjaxResult.success();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/DruidController.java",
    "content": "package com.ruoyi.web.controller.monitor;\r\n\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\n\r\n/**\r\n * druid 监控\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/data\")\r\npublic class DruidController extends BaseController\r\n{\r\n    private String prefix = \"/druid\";\r\n\r\n    @RequiresPermissions(\"monitor:data:view\")\r\n    @GetMapping()\r\n    public String index()\r\n    {\r\n        return redirect(prefix + \"/index.html\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java",
    "content": "package com.ruoyi.web.controller.monitor;\r\n\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.framework.web.domain.Server;\r\n\r\n/**\r\n * 服务器监控\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/server\")\r\npublic class ServerController extends BaseController\r\n{\r\n    private String prefix = \"monitor/server\";\r\n\r\n    @RequiresPermissions(\"monitor:server:view\")\r\n    @GetMapping()\r\n    public String server(ModelMap mmap) throws Exception\r\n    {\r\n        Server server = new Server();\r\n        server.copyTo();\r\n        mmap.put(\"server\", server);\r\n        return prefix + \"/server\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java",
    "content": "package com.ruoyi.web.controller.monitor;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.framework.shiro.service.SysPasswordService;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.system.domain.SysLogininfor;\r\nimport com.ruoyi.system.service.ISysLogininforService;\r\n\r\n/**\r\n * 系统访问记录\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/logininfor\")\r\npublic class SysLogininforController extends BaseController\r\n{\r\n    private String prefix = \"monitor/logininfor\";\r\n\r\n    @Autowired\r\n    private ISysLogininforService logininforService;\r\n\r\n    @Autowired\r\n    private SysPasswordService passwordService;\r\n\r\n    @RequiresPermissions(\"monitor:logininfor:view\")\r\n    @GetMapping()\r\n    public String logininfor()\r\n    {\r\n        return prefix + \"/logininfor\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:logininfor:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysLogininfor logininfor)\r\n    {\r\n        startPage();\r\n        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"登录日志\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"monitor:logininfor:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysLogininfor logininfor)\r\n    {\r\n        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);\r\n        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);\r\n        return util.exportExcel(list, \"登录日志\");\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:logininfor:remove\")\r\n    @Log(title = \"登录日志\", businessType = BusinessType.DELETE)\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        return toAjax(logininforService.deleteLogininforByIds(ids));\r\n    }\r\n    \r\n    @RequiresPermissions(\"monitor:logininfor:remove\")\r\n    @Log(title = \"登录日志\", businessType = BusinessType.CLEAN)\r\n    @PostMapping(\"/clean\")\r\n    @ResponseBody\r\n    public AjaxResult clean()\r\n    {\r\n        logininforService.cleanLogininfor();\r\n        return success();\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:logininfor:unlock\")\r\n    @Log(title = \"账户解锁\", businessType = BusinessType.OTHER)\r\n    @PostMapping(\"/unlock\")\r\n    @ResponseBody\r\n    public AjaxResult unlock(String loginName)\r\n    {\r\n        passwordService.clearLoginRecordCache(loginName);\r\n        return success();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java",
    "content": "package com.ruoyi.web.controller.monitor;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.system.domain.SysOperLog;\r\nimport com.ruoyi.system.service.ISysOperLogService;\r\n\r\n/**\r\n * 操作日志记录\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/operlog\")\r\npublic class SysOperlogController extends BaseController\r\n{\r\n    private String prefix = \"monitor/operlog\";\r\n\r\n    @Autowired\r\n    private ISysOperLogService operLogService;\r\n\r\n    @RequiresPermissions(\"monitor:operlog:view\")\r\n    @GetMapping()\r\n    public String operlog()\r\n    {\r\n        return prefix + \"/operlog\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:operlog:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysOperLog operLog)\r\n    {\r\n        startPage();\r\n        List<SysOperLog> list = operLogService.selectOperLogList(operLog);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"操作日志\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"monitor:operlog:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysOperLog operLog)\r\n    {\r\n        List<SysOperLog> list = operLogService.selectOperLogList(operLog);\r\n        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);\r\n        return util.exportExcel(list, \"操作日志\");\r\n    }\r\n\r\n    @Log(title = \"操作日志\", businessType = BusinessType.DELETE)\r\n    @RequiresPermissions(\"monitor:operlog:remove\")\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        return toAjax(operLogService.deleteOperLogByIds(ids));\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:operlog:detail\")\r\n    @GetMapping(\"/detail/{operId}\")\r\n    public String detail(@PathVariable(\"operId\") Long operId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"operLog\", operLogService.selectOperLogById(operId));\r\n        return prefix + \"/detail\";\r\n    }\r\n    \r\n    @Log(title = \"操作日志\", businessType = BusinessType.CLEAN)\r\n    @RequiresPermissions(\"monitor:operlog:remove\")\r\n    @PostMapping(\"/clean\")\r\n    @ResponseBody\r\n    public AjaxResult clean()\r\n    {\r\n        operLogService.cleanOperLog();\r\n        return success();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java",
    "content": "package com.ruoyi.web.controller.monitor;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.Logical;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.enums.OnlineStatus;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.framework.shiro.session.OnlineSessionDAO;\r\nimport com.ruoyi.system.domain.SysUserOnline;\r\nimport com.ruoyi.system.service.ISysUserOnlineService;\r\n\r\n/**\r\n * 在线用户监控\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/online\")\r\npublic class SysUserOnlineController extends BaseController\r\n{\r\n    private String prefix = \"monitor/online\";\r\n\r\n    @Autowired\r\n    private ISysUserOnlineService userOnlineService;\r\n\r\n    @Autowired\r\n    private OnlineSessionDAO onlineSessionDAO;\r\n\r\n    @RequiresPermissions(\"monitor:online:view\")\r\n    @GetMapping()\r\n    public String online()\r\n    {\r\n        return prefix + \"/online\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:online:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysUserOnline userOnline)\r\n    {\r\n        startPage();\r\n        List<SysUserOnline> list = userOnlineService.selectUserOnlineList(userOnline);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @RequiresPermissions(value = { \"monitor:online:batchForceLogout\", \"monitor:online:forceLogout\" }, logical = Logical.OR)\r\n    @Log(title = \"在线用户\", businessType = BusinessType.FORCE)\r\n    @PostMapping(\"/batchForceLogout\")\r\n    @ResponseBody\r\n    public AjaxResult batchForceLogout(String ids)\r\n    {\r\n        for (String sessionId : Convert.toStrArray(ids))\r\n        {\r\n            SysUserOnline online = userOnlineService.selectOnlineById(sessionId);\r\n            if (online == null)\r\n            {\r\n                return error(\"用户已下线\");\r\n            }\r\n            OnlineSession onlineSession = (OnlineSession) onlineSessionDAO.readSession(online.getSessionId());\r\n            if (onlineSession == null)\r\n            {\r\n                return error(\"用户已下线\");\r\n            }\r\n            if (sessionId.equals(ShiroUtils.getSessionId()))\r\n            {\r\n                return error(\"当前登录用户无法强退\");\r\n            }\r\n            onlineSessionDAO.delete(onlineSession);\r\n            online.setStatus(OnlineStatus.off_line);\r\n            userOnlineService.saveOnline(online);\r\n            userOnlineService.removeUserCache(online.getLoginName(), sessionId);\r\n        }\r\n        return success();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysCaptchaController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.awt.image.BufferedImage;\r\nimport java.io.IOException;\r\nimport jakarta.annotation.Resource;\r\nimport javax.imageio.ImageIO;\r\nimport jakarta.servlet.ServletOutputStream;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport jakarta.servlet.http.HttpSession;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.servlet.ModelAndView;\r\nimport com.google.code.kaptcha.Constants;\r\nimport com.google.code.kaptcha.Producer;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\n\r\n/**\r\n * 图片验证码（支持算术形式）\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/captcha\")\r\npublic class SysCaptchaController extends BaseController\r\n{\r\n    @Resource(name = \"captchaProducer\")\r\n    private Producer captchaProducer;\r\n\r\n    @Resource(name = \"captchaProducerMath\")\r\n    private Producer captchaProducerMath;\r\n\r\n    /**\r\n     * 验证码生成\r\n     */\r\n    @GetMapping(value = \"/captchaImage\")\r\n    public ModelAndView getKaptchaImage(HttpServletRequest request, HttpServletResponse response)\r\n    {\r\n        ServletOutputStream out = null;\r\n        try\r\n        {\r\n            HttpSession session = request.getSession();\r\n            response.setDateHeader(\"Expires\", 0);\r\n            response.setHeader(\"Cache-Control\", \"no-store, no-cache, must-revalidate\");\r\n            response.addHeader(\"Cache-Control\", \"post-check=0, pre-check=0\");\r\n            response.setHeader(\"Pragma\", \"no-cache\");\r\n            response.setContentType(\"image/jpeg\");\r\n\r\n            String type = request.getParameter(\"type\");\r\n            String capStr = null;\r\n            String code = null;\r\n            BufferedImage bi = null;\r\n            if (\"math\".equals(type))\r\n            {\r\n                String capText = captchaProducerMath.createText();\r\n                capStr = capText.substring(0, capText.lastIndexOf(\"@\"));\r\n                code = capText.substring(capText.lastIndexOf(\"@\") + 1);\r\n                bi = captchaProducerMath.createImage(capStr);\r\n            }\r\n            else if (\"char\".equals(type))\r\n            {\r\n                capStr = code = captchaProducer.createText();\r\n                bi = captchaProducer.createImage(capStr);\r\n            }\r\n            session.setAttribute(Constants.KAPTCHA_SESSION_KEY, code);\r\n            out = response.getOutputStream();\r\n            ImageIO.write(bi, \"jpg\", out);\r\n            out.flush();\r\n\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            e.printStackTrace();\r\n        }\r\n        finally\r\n        {\r\n            try\r\n            {\r\n                if (out != null)\r\n                {\r\n                    out.close();\r\n                }\r\n            }\r\n            catch (IOException e)\r\n            {\r\n                e.printStackTrace();\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.system.domain.SysConfig;\r\nimport com.ruoyi.system.service.ISysConfigService;\r\n\r\n/**\r\n * 参数配置 信息操作处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/config\")\r\npublic class SysConfigController extends BaseController\r\n{\r\n    private String prefix = \"system/config\";\r\n\r\n    @Autowired\r\n    private ISysConfigService configService;\r\n\r\n    @RequiresPermissions(\"system:config:view\")\r\n    @GetMapping()\r\n    public String config()\r\n    {\r\n        return prefix + \"/config\";\r\n    }\r\n\r\n    /**\r\n     * 查询参数配置列表\r\n     */\r\n    @RequiresPermissions(\"system:config:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysConfig config)\r\n    {\r\n        startPage();\r\n        List<SysConfig> list = configService.selectConfigList(config);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"参数管理\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"system:config:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysConfig config)\r\n    {\r\n        List<SysConfig> list = configService.selectConfigList(config);\r\n        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);\r\n        return util.exportExcel(list, \"参数数据\");\r\n    }\r\n\r\n    /**\r\n     * 新增参数配置\r\n     */\r\n    @RequiresPermissions(\"system:config:add\")\r\n    @GetMapping(\"/add\")\r\n    public String add()\r\n    {\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存参数配置\r\n     */\r\n    @RequiresPermissions(\"system:config:add\")\r\n    @Log(title = \"参数管理\", businessType = BusinessType.INSERT)\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysConfig config)\r\n    {\r\n        if (!configService.checkConfigKeyUnique(config))\r\n        {\r\n            return error(\"新增参数'\" + config.getConfigName() + \"'失败，参数键名已存在\");\r\n        }\r\n        config.setCreateBy(getLoginName());\r\n        return toAjax(configService.insertConfig(config));\r\n    }\r\n\r\n    /**\r\n     * 修改参数配置\r\n     */\r\n    @RequiresPermissions(\"system:config:edit\")\r\n    @GetMapping(\"/edit/{configId}\")\r\n    public String edit(@PathVariable(\"configId\") Long configId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"config\", configService.selectConfigById(configId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存参数配置\r\n     */\r\n    @RequiresPermissions(\"system:config:edit\")\r\n    @Log(title = \"参数管理\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysConfig config)\r\n    {\r\n        if (!configService.checkConfigKeyUnique(config))\r\n        {\r\n            return error(\"修改参数'\" + config.getConfigName() + \"'失败，参数键名已存在\");\r\n        }\r\n        config.setUpdateBy(getLoginName());\r\n        return toAjax(configService.updateConfig(config));\r\n    }\r\n\r\n    /**\r\n     * 删除参数配置\r\n     */\r\n    @RequiresPermissions(\"system:config:remove\")\r\n    @Log(title = \"参数管理\", businessType = BusinessType.DELETE)\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        configService.deleteConfigByIds(ids);\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 刷新参数缓存\r\n     */\r\n    @RequiresPermissions(\"system:config:remove\")\r\n    @Log(title = \"参数管理\", businessType = BusinessType.CLEAN)\r\n    @GetMapping(\"/refreshCache\")\r\n    @ResponseBody\r\n    public AjaxResult refreshCache()\r\n    {\r\n        configService.resetConfigCache();\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 校验参数键名\r\n     */\r\n    @PostMapping(\"/checkConfigKeyUnique\")\r\n    @ResponseBody\r\n    public boolean checkConfigKeyUnique(SysConfig config)\r\n    {\r\n        return configService.checkConfigKeyUnique(config);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.RequestParam;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysDept;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.system.service.ISysDeptService;\r\n\r\n/**\r\n * 部门信息\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/dept\")\r\npublic class SysDeptController extends BaseController\r\n{\r\n    private String prefix = \"system/dept\";\r\n\r\n    @Autowired\r\n    private ISysDeptService deptService;\r\n\r\n    @RequiresPermissions(\"system:dept:view\")\r\n    @GetMapping()\r\n    public String dept()\r\n    {\r\n        return prefix + \"/dept\";\r\n    }\r\n\r\n    @RequiresPermissions(\"system:dept:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public List<SysDept> list(SysDept dept)\r\n    {\r\n        List<SysDept> deptList = deptService.selectDeptList(dept);\r\n        return deptList;\r\n    }\r\n\r\n    /**\r\n     * 新增部门\r\n     */\r\n    @RequiresPermissions(\"system:dept:add\")\r\n    @GetMapping(\"/add/{parentId}\")\r\n    public String add(@PathVariable(\"parentId\") Long parentId, ModelMap mmap)\r\n    {\r\n        if (!getSysUser().isAdmin())\r\n        {\r\n            parentId = getSysUser().getDeptId();\r\n        }\r\n        mmap.put(\"dept\", deptService.selectDeptById(parentId));\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存部门\r\n     */\r\n    @Log(title = \"部门管理\", businessType = BusinessType.INSERT)\r\n    @RequiresPermissions(\"system:dept:add\")\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysDept dept)\r\n    {\r\n        if (!deptService.checkDeptNameUnique(dept))\r\n        {\r\n            return error(\"新增部门'\" + dept.getDeptName() + \"'失败，部门名称已存在\");\r\n        }\r\n        dept.setCreateBy(getLoginName());\r\n        return toAjax(deptService.insertDept(dept));\r\n    }\r\n\r\n    /**\r\n     * 修改部门\r\n     */\r\n    @RequiresPermissions(\"system:dept:edit\")\r\n    @GetMapping(\"/edit/{deptId}\")\r\n    public String edit(@PathVariable(\"deptId\") Long deptId, ModelMap mmap)\r\n    {\r\n        deptService.checkDeptDataScope(deptId);\r\n        SysDept dept = deptService.selectDeptById(deptId);\r\n        if (StringUtils.isNotNull(dept) && 100L == deptId)\r\n        {\r\n            dept.setParentName(\"无\");\r\n        }\r\n        mmap.put(\"dept\", dept);\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存部门\r\n     */\r\n    @Log(title = \"部门管理\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"system:dept:edit\")\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysDept dept)\r\n    {\r\n        Long deptId = dept.getDeptId();\r\n        deptService.checkDeptDataScope(deptId);\r\n        if (!deptService.checkDeptNameUnique(dept))\r\n        {\r\n            return error(\"修改部门'\" + dept.getDeptName() + \"'失败，部门名称已存在\");\r\n        }\r\n        else if (dept.getParentId().equals(deptId))\r\n        {\r\n            return error(\"修改部门'\" + dept.getDeptName() + \"'失败，上级部门不能是自己\");\r\n        }\r\n        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)\r\n        {\r\n            return AjaxResult.error(\"该部门包含未停用的子部门！\");\r\n        }\r\n        dept.setUpdateBy(getLoginName());\r\n        return toAjax(deptService.updateDept(dept));\r\n    }\r\n\r\n    /**\r\n     * 删除\r\n     */\r\n    @Log(title = \"部门管理\", businessType = BusinessType.DELETE)\r\n    @RequiresPermissions(\"system:dept:remove\")\r\n    @GetMapping(\"/remove/{deptId}\")\r\n    @ResponseBody\r\n    public AjaxResult remove(@PathVariable(\"deptId\") Long deptId)\r\n    {\r\n        if (deptService.selectDeptCount(deptId) > 0)\r\n        {\r\n            return AjaxResult.warn(\"存在下级部门,不允许删除\");\r\n        }\r\n        if (deptService.checkDeptExistUser(deptId))\r\n        {\r\n            return AjaxResult.warn(\"部门存在用户,不允许删除\");\r\n        }\r\n        deptService.checkDeptDataScope(deptId);\r\n        return toAjax(deptService.deleteDeptById(deptId));\r\n    }\r\n\r\n    /**\r\n     * 校验部门名称\r\n     */\r\n    @PostMapping(\"/checkDeptNameUnique\")\r\n    @ResponseBody\r\n    public boolean checkDeptNameUnique(SysDept dept)\r\n    {\r\n        return deptService.checkDeptNameUnique(dept);\r\n    }\r\n\r\n    /**\r\n     * 选择部门树\r\n     * \r\n     * @param deptId 部门ID\r\n     * @param excludeId 排除ID\r\n     */\r\n    @RequiresPermissions(\"system:dept:list\")\r\n    @GetMapping(value = { \"/selectDeptTree/{deptId}\", \"/selectDeptTree/{deptId}/{excludeId}\" })\r\n    public String selectDeptTree(@PathVariable(\"deptId\") Long deptId, @PathVariable(value = \"excludeId\", required = false) Long excludeId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"dept\", deptService.selectDeptById(deptId));\r\n        mmap.put(\"excludeId\", excludeId);\r\n        return prefix + \"/tree\";\r\n    }\r\n\r\n    /**\r\n     * 加载部门列表树（排除下级）\r\n     */\r\n    @RequiresPermissions(\"system:dept:list\")\r\n    @GetMapping(\"/treeData/{excludeId}\")\r\n    @ResponseBody\r\n    public List<Ztree> treeDataExcludeChild(@PathVariable(value = \"excludeId\", required = false) Long excludeId)\r\n    {\r\n        SysDept dept = new SysDept();\r\n        dept.setExcludeId(excludeId);\r\n        List<Ztree> ztrees = deptService.selectDeptTreeExcludeChild(dept);\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 保存部门排序\r\n     */\r\n    @PostMapping(\"/updateSort\")\r\n    @ResponseBody\r\n    public AjaxResult updateSort(@RequestParam String[] deptIds, @RequestParam String[] orderNums)\r\n    {\r\n        deptService.updateDeptSort(deptIds, orderNums);\r\n        return success();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.entity.SysDictData;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.system.service.ISysDictDataService;\r\n\r\n/**\r\n * 数据字典信息\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/dict/data\")\r\npublic class SysDictDataController extends BaseController\r\n{\r\n    private String prefix = \"system/dict/data\";\r\n\r\n    @Autowired\r\n    private ISysDictDataService dictDataService;\r\n\r\n    @RequiresPermissions(\"system:dict:view\")\r\n    @GetMapping()\r\n    public String dictData()\r\n    {\r\n        return prefix + \"/data\";\r\n    }\r\n\r\n    @PostMapping(\"/list\")\r\n    @RequiresPermissions(\"system:dict:list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysDictData dictData)\r\n    {\r\n        startPage();\r\n        List<SysDictData> list = dictDataService.selectDictDataList(dictData);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"字典数据\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"system:dict:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysDictData dictData)\r\n    {\r\n        List<SysDictData> list = dictDataService.selectDictDataList(dictData);\r\n        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);\r\n        return util.exportExcel(list, \"字典数据\");\r\n    }\r\n\r\n    /**\r\n     * 新增字典类型\r\n     */\r\n    @RequiresPermissions(\"system:dict:add\")\r\n    @GetMapping(\"/add/{dictType}\")\r\n    public String add(@PathVariable(\"dictType\") String dictType, ModelMap mmap)\r\n    {\r\n        mmap.put(\"dictType\", dictType);\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存字典类型\r\n     */\r\n    @Log(title = \"字典数据\", businessType = BusinessType.INSERT)\r\n    @RequiresPermissions(\"system:dict:add\")\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysDictData dict)\r\n    {\r\n        dict.setCreateBy(getLoginName());\r\n        return toAjax(dictDataService.insertDictData(dict));\r\n    }\r\n\r\n    /**\r\n     * 修改字典类型\r\n     */\r\n    @RequiresPermissions(\"system:dict:edit\")\r\n    @GetMapping(\"/edit/{dictCode}\")\r\n    public String edit(@PathVariable(\"dictCode\") Long dictCode, ModelMap mmap)\r\n    {\r\n        mmap.put(\"dict\", dictDataService.selectDictDataById(dictCode));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存字典类型\r\n     */\r\n    @Log(title = \"字典数据\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"system:dict:edit\")\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysDictData dict)\r\n    {\r\n        dict.setUpdateBy(getLoginName());\r\n        return toAjax(dictDataService.updateDictData(dict));\r\n    }\r\n\r\n    @Log(title = \"字典数据\", businessType = BusinessType.DELETE)\r\n    @RequiresPermissions(\"system:dict:remove\")\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        dictDataService.deleteDictDataByIds(ids);\r\n        return success();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysDictType;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.system.service.ISysDictTypeService;\r\n\r\n/**\r\n * 数据字典信息\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/dict\")\r\npublic class SysDictTypeController extends BaseController\r\n{\r\n    private String prefix = \"system/dict/type\";\r\n\r\n    @Autowired\r\n    private ISysDictTypeService dictTypeService;\r\n\r\n    @RequiresPermissions(\"system:dict:view\")\r\n    @GetMapping()\r\n    public String dictType()\r\n    {\r\n        return prefix + \"/type\";\r\n    }\r\n\r\n    @PostMapping(\"/list\")\r\n    @RequiresPermissions(\"system:dict:list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysDictType dictType)\r\n    {\r\n        startPage();\r\n        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"字典类型\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"system:dict:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysDictType dictType)\r\n    {\r\n\r\n        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);\r\n        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);\r\n        return util.exportExcel(list, \"字典类型\");\r\n    }\r\n\r\n    /**\r\n     * 新增字典类型\r\n     */\r\n    @RequiresPermissions(\"system:dict:add\")\r\n    @GetMapping(\"/add\")\r\n    public String add()\r\n    {\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存字典类型\r\n     */\r\n    @Log(title = \"字典类型\", businessType = BusinessType.INSERT)\r\n    @RequiresPermissions(\"system:dict:add\")\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysDictType dict)\r\n    {\r\n        if (!dictTypeService.checkDictTypeUnique(dict))\r\n        {\r\n            return error(\"新增字典'\" + dict.getDictName() + \"'失败，字典类型已存在\");\r\n        }\r\n        dict.setCreateBy(getLoginName());\r\n        return toAjax(dictTypeService.insertDictType(dict));\r\n    }\r\n\r\n    /**\r\n     * 修改字典类型\r\n     */\r\n    @RequiresPermissions(\"system:dict:edit\")\r\n    @GetMapping(\"/edit/{dictId}\")\r\n    public String edit(@PathVariable(\"dictId\") Long dictId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"dict\", dictTypeService.selectDictTypeById(dictId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存字典类型\r\n     */\r\n    @Log(title = \"字典类型\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"system:dict:edit\")\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysDictType dict)\r\n    {\r\n        if (!dictTypeService.checkDictTypeUnique(dict))\r\n        {\r\n            return error(\"修改字典'\" + dict.getDictName() + \"'失败，字典类型已存在\");\r\n        }\r\n        dict.setUpdateBy(getLoginName());\r\n        return toAjax(dictTypeService.updateDictType(dict));\r\n    }\r\n\r\n    @Log(title = \"字典类型\", businessType = BusinessType.DELETE)\r\n    @RequiresPermissions(\"system:dict:remove\")\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        dictTypeService.deleteDictTypeByIds(ids);\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 刷新字典缓存\r\n     */\r\n    @RequiresPermissions(\"system:dict:remove\")\r\n    @Log(title = \"字典类型\", businessType = BusinessType.CLEAN)\r\n    @GetMapping(\"/refreshCache\")\r\n    @ResponseBody\r\n    public AjaxResult refreshCache()\r\n    {\r\n        dictTypeService.resetDictCache();\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 查询字典详细\r\n     */\r\n    @RequiresPermissions(\"system:dict:list\")\r\n    @GetMapping(\"/detail/{dictId}\")\r\n    public String detail(@PathVariable(\"dictId\") Long dictId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"dict\", dictTypeService.selectDictTypeById(dictId));\r\n        mmap.put(\"dictList\", dictTypeService.selectDictTypeAll());\r\n        return \"system/dict/data/data\";\r\n    }\r\n\r\n    /**\r\n     * 校验字典类型\r\n     */\r\n    @PostMapping(\"/checkDictTypeUnique\")\r\n    @ResponseBody\r\n    public boolean checkDictTypeUnique(SysDictType dictType)\r\n    {\r\n        return dictTypeService.checkDictTypeUnique(dictType);\r\n    }\r\n\r\n    /**\r\n     * 选择字典树\r\n     */\r\n    @GetMapping(\"/selectDictTree/{columnId}/{dictType}\")\r\n    public String selectDictTree(@PathVariable(\"columnId\") Long columnId, @PathVariable(\"dictType\") String dictType, ModelMap mmap)\r\n    {\r\n        mmap.put(\"columnId\", columnId);\r\n        mmap.put(\"dict\", dictTypeService.selectDictTypeByType(dictType));\r\n        return prefix + \"/tree\";\r\n    }\r\n\r\n    /**\r\n     * 加载字典列表树\r\n     */\r\n    @GetMapping(\"/treeData\")\r\n    @ResponseBody\r\n    public List<Ztree> treeData()\r\n    {\r\n        List<Ztree> ztrees = dictTypeService.selectDictTree(new SysDictType());\r\n        return ztrees;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport jakarta.servlet.http.Cookie;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.entity.SysMenu;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.utils.CookieUtils;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.framework.shiro.service.SysPasswordService;\r\nimport com.ruoyi.system.service.ISysConfigService;\r\nimport com.ruoyi.system.service.ISysMenuService;\r\n\r\n/**\r\n * 首页 业务处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\npublic class SysIndexController extends BaseController\r\n{\r\n    @Autowired\r\n    private ISysMenuService menuService;\r\n\r\n    @Autowired\r\n    private ISysConfigService configService;\r\n\r\n    @Autowired\r\n    private SysPasswordService passwordService;\r\n\r\n    // 系统首页\r\n    @GetMapping(\"/index\")\r\n    public String index(ModelMap mmap, HttpServletRequest request)\r\n    {\r\n        // 取身份信息\r\n        SysUser user = getSysUser();\r\n        // 根据用户id取出菜单\r\n        List<SysMenu> menus = menuService.selectMenusByUser(user);\r\n        mmap.put(\"menus\", menus);\r\n        mmap.put(\"user\", user);\r\n        mmap.put(\"sideTheme\", configService.selectConfigByKey(\"sys.index.sideTheme\"));\r\n        mmap.put(\"skinName\", configService.selectConfigByKey(\"sys.index.skinName\"));\r\n        Boolean footer = Convert.toBool(configService.selectConfigByKey(\"sys.index.footer\"), true);\r\n        Boolean tagsView = Convert.toBool(configService.selectConfigByKey(\"sys.index.tagsView\"), true);\r\n        mmap.put(\"footer\", footer);\r\n        mmap.put(\"tagsView\", tagsView);\r\n        mmap.put(\"mainClass\", contentMainClass(footer, tagsView));\r\n        mmap.put(\"copyrightYear\", RuoYiConfig.getCopyrightYear());\r\n        mmap.put(\"demoEnabled\", RuoYiConfig.isDemoEnabled());\r\n        mmap.put(\"isDefaultModifyPwd\", initPasswordIsModify(user.getPwdUpdateDate()));\r\n        mmap.put(\"isPasswordExpired\", passwordIsExpiration(user.getPwdUpdateDate()));\r\n        mmap.put(\"isMobile\", ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader(\"User-Agent\")));\r\n\r\n        // 菜单导航显示风格\r\n        String menuStyle = configService.selectConfigByKey(\"sys.index.menuStyle\");\r\n        // 移动端，默认使左侧导航菜单，否则取默认配置\r\n        String indexStyle = ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader(\"User-Agent\")) ? \"index\" : menuStyle;\r\n\r\n        // 优先Cookie配置导航菜单\r\n        Cookie[] cookies = ServletUtils.getRequest().getCookies();\r\n        for (Cookie cookie : cookies)\r\n        {\r\n            if (StringUtils.isNotEmpty(cookie.getName()) && \"nav-style\".equalsIgnoreCase(cookie.getName()))\r\n            {\r\n                indexStyle = cookie.getValue();\r\n                break;\r\n            }\r\n        }\r\n        String webIndex = \"topnav\".equalsIgnoreCase(indexStyle) ? \"index-topnav\" : \"index\";\r\n        // CSRF Token\r\n        request.getSession().setAttribute(ShiroConstants.CSRF_TOKEN, ServletUtils.generateToken());\r\n        return webIndex;\r\n    }\r\n\r\n    // 锁定屏幕\r\n    @GetMapping(\"/lockscreen\")\r\n    public String lockscreen(ModelMap mmap)\r\n    {\r\n        mmap.put(\"user\", getSysUser());\r\n        ServletUtils.getSession().setAttribute(ShiroConstants.LOCK_SCREEN, true);\r\n        return \"lock\";\r\n    }\r\n\r\n    // 解锁屏幕\r\n    @PostMapping(\"/unlockscreen\")\r\n    @ResponseBody\r\n    public AjaxResult unlockscreen(String password)\r\n    {\r\n        SysUser user = getSysUser();\r\n        if (StringUtils.isNull(user))\r\n        {\r\n            return AjaxResult.error(\"服务器超时，请重新登录\");\r\n        }\r\n        if (passwordService.matches(user, password))\r\n        {\r\n            ServletUtils.getSession().removeAttribute(ShiroConstants.LOCK_SCREEN);\r\n            return AjaxResult.success();\r\n        }\r\n        return AjaxResult.error(\"密码不正确，请重新输入。\");\r\n    }\r\n\r\n    // 切换主题\r\n    @GetMapping(\"/system/switchSkin\")\r\n    public String switchSkin()\r\n    {\r\n        return \"skin\";\r\n    }\r\n\r\n    // 切换菜单\r\n    @GetMapping(\"/system/menuStyle/{style}\")\r\n    public void menuStyle(@PathVariable String style, HttpServletResponse response)\r\n    {\r\n        CookieUtils.setCookie(response, \"nav-style\", style);\r\n    }\r\n\r\n    // 系统介绍\r\n    @GetMapping(\"/system/main\")\r\n    public String main(ModelMap mmap)\r\n    {\r\n        mmap.put(\"version\", RuoYiConfig.getVersion());\r\n        return \"main\";\r\n    }\r\n\r\n    // content-main class\r\n    public String contentMainClass(Boolean footer, Boolean tagsView)\r\n    {\r\n        if (!footer && !tagsView)\r\n        {\r\n            return \"tagsview-footer-hide\";\r\n        }\r\n        else if (!footer)\r\n        {\r\n            return \"footer-hide\";\r\n        }\r\n        else if (!tagsView)\r\n        {\r\n            return \"tagsview-hide\";\r\n        }\r\n        return StringUtils.EMPTY;\r\n    }\r\n\r\n    // 检查初始密码是否提醒修改\r\n    public boolean initPasswordIsModify(Date pwdUpdateDate)\r\n    {\r\n        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey(\"sys.account.initPasswordModify\"));\r\n        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;\r\n    }\r\n\r\n    // 检查密码是否过期\r\n    public boolean passwordIsExpiration(Date pwdUpdateDate)\r\n    {\r\n        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey(\"sys.account.passwordValidateDays\"));\r\n        if (passwordValidateDays != null && passwordValidateDays > 0)\r\n        {\r\n            if (StringUtils.isNull(pwdUpdateDate))\r\n            {\r\n                // 如果从未修改过初始密码，直接提醒过期\r\n                return true;\r\n            }\r\n            Date nowDate = DateUtils.getNowDate();\r\n            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;\r\n        }\r\n        return false;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java",
    "content": "package com.ruoyi.web.controller.system;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.subject.Subject;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport com.ruoyi.common.core.controller.BaseController;\nimport com.ruoyi.common.core.domain.AjaxResult;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.common.utils.ServletUtils;\nimport com.ruoyi.common.utils.StringUtils;\nimport com.ruoyi.framework.web.service.ConfigService;\n\n/**\n * 登录验证\n * \n * @author ruoyi\n */\n@Controller\npublic class SysLoginController extends BaseController\n{\n    /**\n     * 是否开启记住我功能\n     */\n    @Value(\"${shiro.rememberMe.enabled: false}\")\n    private boolean rememberMe;\n\n    @Autowired\n    private ConfigService configService;\n\n    @GetMapping(\"/login\")\n    public String login(HttpServletRequest request, HttpServletResponse response, ModelMap mmap)\n    {\n        // 如果是Ajax请求，返回Json字符串。\n        if (ServletUtils.isAjaxRequest(request))\n        {\n            return ServletUtils.renderString(response, \"{\\\"code\\\":\\\"1\\\",\\\"msg\\\":\\\"未登录或登录超时。请重新登录\\\"}\");\n        }\n        // 是否开启记住我\n        mmap.put(\"isRemembered\", rememberMe);\n        // 是否开启用户注册\n        mmap.put(\"isAllowRegister\", Convert.toBool(configService.getKey(\"sys.account.registerUser\"), false));\n        return \"login\";\n    }\n\n    @PostMapping(\"/login\")\n    @ResponseBody\n    public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe)\n    {\n        UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);\n        Subject subject = SecurityUtils.getSubject();\n        try\n        {\n            subject.login(token);\n            return success();\n        }\n        catch (AuthenticationException e)\n        {\n            String msg = \"用户或密码错误\";\n            if (StringUtils.isNotEmpty(e.getMessage()))\n            {\n                msg = e.getMessage();\n            }\n            return error(msg);\n        }\n    }\n\n    @GetMapping(\"/unauth\")\n    public String unauth()\n    {\n        return \"error/unauth\";\n    }\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.RequestParam;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysMenu;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.framework.shiro.util.AuthorizationUtils;\r\nimport com.ruoyi.system.service.ISysMenuService;\r\n\r\n/**\r\n * 菜单信息\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/menu\")\r\npublic class SysMenuController extends BaseController\r\n{\r\n    private String prefix = \"system/menu\";\r\n\r\n    @Autowired\r\n    private ISysMenuService menuService;\r\n\r\n    @RequiresPermissions(\"system:menu:view\")\r\n    @GetMapping()\r\n    public String menu()\r\n    {\r\n        return prefix + \"/menu\";\r\n    }\r\n\r\n    @RequiresPermissions(\"system:menu:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public List<SysMenu> list(SysMenu menu)\r\n    {\r\n        Long userId = ShiroUtils.getUserId();\r\n        List<SysMenu> menuList = menuService.selectMenuList(menu, userId);\r\n        return menuList;\r\n    }\r\n\r\n    /**\r\n     * 删除菜单\r\n     */\r\n    @Log(title = \"菜单管理\", businessType = BusinessType.DELETE)\r\n    @RequiresPermissions(\"system:menu:remove\")\r\n    @GetMapping(\"/remove/{menuId}\")\r\n    @ResponseBody\r\n    public AjaxResult remove(@PathVariable(\"menuId\") Long menuId)\r\n    {\r\n        if (menuService.selectCountMenuByParentId(menuId) > 0)\r\n        {\r\n            return AjaxResult.warn(\"存在子菜单,不允许删除\");\r\n        }\r\n        if (menuService.selectCountRoleMenuByMenuId(menuId) > 0)\r\n        {\r\n            return AjaxResult.warn(\"菜单已分配,不允许删除\");\r\n        }\r\n        AuthorizationUtils.clearAllCachedAuthorizationInfo();\r\n        return toAjax(menuService.deleteMenuById(menuId));\r\n    }\r\n\r\n    /**\r\n     * 新增\r\n     */\r\n    @RequiresPermissions(\"system:menu:add\")\r\n    @GetMapping(\"/add/{parentId}\")\r\n    public String add(@PathVariable(\"parentId\") Long parentId, ModelMap mmap)\r\n    {\r\n        SysMenu menu = null;\r\n        if (0L != parentId)\r\n        {\r\n            menu = menuService.selectMenuById(parentId);\r\n        }\r\n        else\r\n        {\r\n            menu = new SysMenu();\r\n            menu.setMenuId(0L);\r\n            menu.setMenuName(\"主目录\");\r\n        }\r\n        mmap.put(\"menu\", menu);\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存菜单\r\n     */\r\n    @Log(title = \"菜单管理\", businessType = BusinessType.INSERT)\r\n    @RequiresPermissions(\"system:menu:add\")\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysMenu menu)\r\n    {\r\n        if (!menuService.checkMenuNameUnique(menu))\r\n        {\r\n            return error(\"新增菜单'\" + menu.getMenuName() + \"'失败，菜单名称已存在\");\r\n        }\r\n        menu.setCreateBy(getLoginName());\r\n        AuthorizationUtils.clearAllCachedAuthorizationInfo();\r\n        return toAjax(menuService.insertMenu(menu));\r\n    }\r\n\r\n    /**\r\n     * 修改菜单\r\n     */\r\n    @RequiresPermissions(\"system:menu:edit\")\r\n    @GetMapping(\"/edit/{menuId}\")\r\n    public String edit(@PathVariable(\"menuId\") Long menuId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"menu\", menuService.selectMenuById(menuId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存菜单\r\n     */\r\n    @Log(title = \"菜单管理\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"system:menu:edit\")\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysMenu menu)\r\n    {\r\n        if (!menuService.checkMenuNameUnique(menu))\r\n        {\r\n            return error(\"修改菜单'\" + menu.getMenuName() + \"'失败，菜单名称已存在\");\r\n        }\r\n        menu.setUpdateBy(getLoginName());\r\n        AuthorizationUtils.clearAllCachedAuthorizationInfo();\r\n        return toAjax(menuService.updateMenu(menu));\r\n    }\r\n\r\n    /**\r\n     * 保存菜单排序\r\n     */\r\n    @PostMapping(\"/updateSort\")\r\n    @ResponseBody\r\n    public AjaxResult updateSort(@RequestParam String[] menuIds, @RequestParam String[] orderNums)\r\n    {\r\n        menuService.updateMenuSort(menuIds, orderNums);\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 选择菜单图标\r\n     */\r\n    @GetMapping(\"/icon\")\r\n    public String icon()\r\n    {\r\n        return prefix + \"/icon\";\r\n    }\r\n\r\n    /**\r\n     * 校验菜单名称\r\n     */\r\n    @PostMapping(\"/checkMenuNameUnique\")\r\n    @ResponseBody\r\n    public boolean checkMenuNameUnique(SysMenu menu)\r\n    {\r\n        return menuService.checkMenuNameUnique(menu);\r\n    }\r\n\r\n    /**\r\n     * 加载角色菜单列表树\r\n     */\r\n    @GetMapping(\"/roleMenuTreeData\")\r\n    @ResponseBody\r\n    public List<Ztree> roleMenuTreeData(SysRole role)\r\n    {\r\n        Long userId = ShiroUtils.getUserId();\r\n        List<Ztree> ztrees = menuService.roleMenuTreeData(role, userId);\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 加载所有菜单列表树\r\n     */\r\n    @GetMapping(\"/menuTreeData\")\r\n    @ResponseBody\r\n    public List<Ztree> menuTreeData()\r\n    {\r\n        Long userId = ShiroUtils.getUserId();\r\n        List<Ztree> ztrees = menuService.menuTreeData(userId);\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 选择菜单树\r\n     */\r\n    @GetMapping(\"/selectMenuTree/{menuId}\")\r\n    public String selectMenuTree(@PathVariable(\"menuId\") Long menuId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"menu\", menuService.selectMenuById(menuId));\r\n        return prefix + \"/tree\";\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.system.domain.SysNotice;\r\nimport com.ruoyi.system.service.ISysNoticeReadService;\r\nimport com.ruoyi.system.service.ISysNoticeService;\r\n\r\n/**\r\n * 公告 信息操作处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/notice\")\r\npublic class SysNoticeController extends BaseController\r\n{\r\n    private String prefix = \"system/notice\";\r\n\r\n    @Autowired\r\n    private ISysNoticeService noticeService;\r\n\r\n    @Autowired\r\n    private ISysNoticeReadService noticeReadService;\r\n\r\n    @RequiresPermissions(\"system:notice:view\")\r\n    @GetMapping()\r\n    public String notice()\r\n    {\r\n        return prefix + \"/notice\";\r\n    }\r\n\r\n    /**\r\n     * 查询公告列表\r\n     */\r\n    @RequiresPermissions(\"system:notice:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysNotice notice)\r\n    {\r\n        startPage();\r\n        List<SysNotice> list = noticeService.selectNoticeList(notice);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    /**\r\n     * 新增公告\r\n     */\r\n    @RequiresPermissions(\"system:notice:add\")\r\n    @GetMapping(\"/add\")\r\n    public String add()\r\n    {\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存公告\r\n     */\r\n    @RequiresPermissions(\"system:notice:add\")\r\n    @Log(title = \"通知公告\", businessType = BusinessType.INSERT)\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysNotice notice)\r\n    {\r\n        notice.setCreateBy(getLoginName());\r\n        return toAjax(noticeService.insertNotice(notice));\r\n    }\r\n\r\n    /**\r\n     * 修改公告\r\n     */\r\n    @RequiresPermissions(\"system:notice:edit\")\r\n    @GetMapping(\"/edit/{noticeId}\")\r\n    public String edit(@PathVariable(\"noticeId\") Long noticeId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"notice\", noticeService.selectNoticeById(noticeId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存公告\r\n     */\r\n    @RequiresPermissions(\"system:notice:edit\")\r\n    @Log(title = \"通知公告\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysNotice notice)\r\n    {\r\n        notice.setUpdateBy(getLoginName());\r\n        return toAjax(noticeService.updateNotice(notice));\r\n    }\r\n\r\n    /**\r\n     * 查询公告详细\r\n     */\r\n    @RequiresPermissions(\"system:notice:list\")\r\n    @GetMapping(\"/view/{noticeId}\")\r\n    public String view(@PathVariable(\"noticeId\") Long noticeId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"notice\", noticeService.selectNoticeById(noticeId));\r\n        return prefix + \"/view\";\r\n    }\r\n\r\n    /**\r\n     * 首页顶部公告列表（返回全部正常公告，带当前用户已读标记，最多5条）\r\n     */\r\n    @GetMapping(\"/listTop\")\r\n    @ResponseBody\r\n    public AjaxResult listTop()\r\n    {\r\n        Long userId = ShiroUtils.getSysUser().getUserId();\r\n        List<SysNotice> list = noticeReadService.selectNoticeListWithReadStatus(userId, 5);\r\n        long unreadCount = list.stream().filter(n -> !n.getIsRead()).count();\r\n        AjaxResult result = AjaxResult.success(list);\r\n        result.put(\"unreadCount\", unreadCount);\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * 标记公告已读\r\n     */\r\n    @PostMapping(\"/markRead\")\r\n    @ResponseBody\r\n    public AjaxResult markRead(Long noticeId)\r\n    {\r\n        Long userId = ShiroUtils.getSysUser().getUserId();\r\n        noticeReadService.markRead(noticeId, userId);\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 批量标记已读\r\n     */\r\n    @PostMapping(\"/markReadAll\")\r\n    @ResponseBody\r\n    public AjaxResult markReadAll(String ids)\r\n    {\r\n        Long userId = ShiroUtils.getSysUser().getUserId();\r\n        Long[] noticeIds = Convert.toLongArray(ids);\r\n        noticeReadService.markReadBatch(userId, noticeIds);\r\n        return success();\r\n    }\r\n\r\n    /**\r\n     * 删除公告\r\n     */\r\n    @RequiresPermissions(\"system:notice:remove\")\r\n    @Log(title = \"通知公告\", businessType = BusinessType.DELETE)\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        noticeReadService.deleteByNoticeIds(ids);\r\n        return toAjax(noticeService.deleteNoticeByIds(ids));\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.system.domain.SysPost;\r\nimport com.ruoyi.system.service.ISysPostService;\r\n\r\n/**\r\n * 岗位信息操作处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/post\")\r\npublic class SysPostController extends BaseController\r\n{\r\n    private String prefix = \"system/post\";\r\n\r\n    @Autowired\r\n    private ISysPostService postService;\r\n\r\n    @RequiresPermissions(\"system:post:view\")\r\n    @GetMapping()\r\n    public String operlog()\r\n    {\r\n        return prefix + \"/post\";\r\n    }\r\n\r\n    @RequiresPermissions(\"system:post:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysPost post)\r\n    {\r\n        startPage();\r\n        List<SysPost> list = postService.selectPostList(post);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"岗位管理\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"system:post:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysPost post)\r\n    {\r\n        List<SysPost> list = postService.selectPostList(post);\r\n        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);\r\n        return util.exportExcel(list, \"岗位数据\");\r\n    }\r\n\r\n    @RequiresPermissions(\"system:post:remove\")\r\n    @Log(title = \"岗位管理\", businessType = BusinessType.DELETE)\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        return toAjax(postService.deletePostByIds(ids));\r\n    }\r\n\r\n    /**\r\n     * 新增岗位\r\n     */\r\n    @RequiresPermissions(\"system:post:add\")\r\n    @GetMapping(\"/add\")\r\n    public String add()\r\n    {\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存岗位\r\n     */\r\n    @RequiresPermissions(\"system:post:add\")\r\n    @Log(title = \"岗位管理\", businessType = BusinessType.INSERT)\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysPost post)\r\n    {\r\n        if (!postService.checkPostNameUnique(post))\r\n        {\r\n            return error(\"新增岗位'\" + post.getPostName() + \"'失败，岗位名称已存在\");\r\n        }\r\n        else if (!postService.checkPostCodeUnique(post))\r\n        {\r\n            return error(\"新增岗位'\" + post.getPostName() + \"'失败，岗位编码已存在\");\r\n        }\r\n        post.setCreateBy(getLoginName());\r\n        return toAjax(postService.insertPost(post));\r\n    }\r\n\r\n    /**\r\n     * 修改岗位\r\n     */\r\n    @RequiresPermissions(\"system:post:edit\")\r\n    @GetMapping(\"/edit/{postId}\")\r\n    public String edit(@PathVariable(\"postId\") Long postId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"post\", postService.selectPostById(postId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存岗位\r\n     */\r\n    @RequiresPermissions(\"system:post:edit\")\r\n    @Log(title = \"岗位管理\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysPost post)\r\n    {\r\n        if (!postService.checkPostNameUnique(post))\r\n        {\r\n            return error(\"修改岗位'\" + post.getPostName() + \"'失败，岗位名称已存在\");\r\n        }\r\n        else if (!postService.checkPostCodeUnique(post))\r\n        {\r\n            return error(\"修改岗位'\" + post.getPostName() + \"'失败，岗位编码已存在\");\r\n        }\r\n        post.setUpdateBy(getLoginName());\r\n        return toAjax(postService.updatePost(post));\r\n    }\r\n\r\n    /**\r\n     * 校验岗位名称\r\n     */\r\n    @PostMapping(\"/checkPostNameUnique\")\r\n    @ResponseBody\r\n    public boolean checkPostNameUnique(SysPost post)\r\n    {\r\n        return postService.checkPostNameUnique(post);\r\n    }\r\n\r\n    /**\r\n     * 校验岗位编码\r\n     */\r\n    @PostMapping(\"/checkPostCodeUnique\")\r\n    @ResponseBody\r\n    public boolean checkPostCodeUnique(SysPost post)\r\n    {\r\n        return postService.checkPostCodeUnique(post);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.RequestParam;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport org.springframework.web.multipart.MultipartFile;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.file.FileUploadUtils;\r\nimport com.ruoyi.common.utils.file.FileUtils;\r\nimport com.ruoyi.common.utils.file.MimeTypeUtils;\r\nimport com.ruoyi.framework.shiro.service.SysPasswordService;\r\nimport com.ruoyi.system.service.ISysUserService;\r\n\r\n/**\r\n * 个人信息 业务处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/user/profile\")\r\npublic class SysProfileController extends BaseController\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(SysProfileController.class);\r\n\r\n    private String prefix = \"system/user/profile\";\r\n\r\n    @Autowired\r\n    private ISysUserService userService;\r\n    \r\n    @Autowired\r\n    private SysPasswordService passwordService;\r\n\r\n    /**\r\n     * 个人信息\r\n     */\r\n    @GetMapping()\r\n    public String profile(ModelMap mmap)\r\n    {\r\n        SysUser user = getSysUser();\r\n        mmap.put(\"user\", user);\r\n        mmap.put(\"roleGroup\", userService.selectUserRoleGroup(user.getUserId()));\r\n        mmap.put(\"postGroup\", userService.selectUserPostGroup(user.getUserId()));\r\n        return prefix + \"/profile\";\r\n    }\r\n\r\n    @GetMapping(\"/checkPassword\")\r\n    @ResponseBody\r\n    public boolean checkPassword(String password)\r\n    {\r\n        SysUser user = getSysUser();\r\n        return passwordService.matches(user, password);\r\n    }\r\n\r\n    @GetMapping(\"/resetPwd\")\r\n    public String resetPwd(ModelMap mmap)\r\n    {\r\n        SysUser user = getSysUser();\r\n        mmap.put(\"user\", userService.selectUserById(user.getUserId()));\r\n        return prefix + \"/resetPwd\";\r\n    }\r\n\r\n    @Log(title = \"重置密码\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/resetPwd\")\r\n    @ResponseBody\r\n    public AjaxResult resetPwd(String oldPassword, String newPassword)\r\n    {\r\n        SysUser user = getSysUser();\r\n        if (!passwordService.matches(user, oldPassword))\r\n        {\r\n            return error(\"修改密码失败，旧密码错误\");\r\n        }\r\n        if (passwordService.matches(user, newPassword))\r\n        {\r\n            return error(\"新密码不能与旧密码相同\");\r\n        }\r\n        user.setSalt(ShiroUtils.randomSalt());\r\n        user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt()));\r\n        if (userService.resetUserPwd(user) > 0)\r\n        {\r\n            setSysUser(userService.selectUserById(user.getUserId()));\r\n            return success();\r\n        }\r\n        return error(\"修改密码异常，请联系管理员\");\r\n    }\r\n\r\n    /**\r\n     * 修改用户\r\n     */\r\n    @GetMapping(\"/edit\")\r\n    public String edit(ModelMap mmap)\r\n    {\r\n        SysUser user = getSysUser();\r\n        mmap.put(\"user\", userService.selectUserById(user.getUserId()));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改头像\r\n     */\r\n    @GetMapping(\"/avatar\")\r\n    public String avatar(ModelMap mmap)\r\n    {\r\n        SysUser user = getSysUser();\r\n        mmap.put(\"user\", userService.selectUserById(user.getUserId()));\r\n        return prefix + \"/avatar\";\r\n    }\r\n\r\n    /**\r\n     * 修改用户\r\n     */\r\n    @Log(title = \"个人信息\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/update\")\r\n    @ResponseBody\r\n    public AjaxResult update(SysUser user)\r\n    {\r\n        SysUser currentUser = getSysUser();\r\n        currentUser.setUserName(user.getUserName());\r\n        currentUser.setEmail(user.getEmail());\r\n        currentUser.setPhonenumber(user.getPhonenumber());\r\n        currentUser.setSex(user.getSex());\r\n        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))\r\n        {\r\n            return error(\"修改用户'\" + currentUser.getLoginName() + \"'失败，手机号码已存在\");\r\n        }\r\n        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))\r\n        {\r\n            return error(\"修改用户'\" + currentUser.getLoginName() + \"'失败，邮箱账号已存在\");\r\n        }\r\n        if (userService.updateUserInfo(currentUser) > 0)\r\n        {\r\n            setSysUser(userService.selectUserById(currentUser.getUserId()));\r\n            return success();\r\n        }\r\n        return error();\r\n    }\r\n\r\n    /**\r\n     * 保存头像\r\n     */\r\n    @Log(title = \"个人信息\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/updateAvatar\")\r\n    @ResponseBody\r\n    public AjaxResult updateAvatar(@RequestParam(\"avatarfile\") MultipartFile file)\r\n    {\r\n        try\r\n        {\r\n            if (!file.isEmpty())\r\n            {\r\n                SysUser currentUser = getSysUser();\r\n                String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true);\r\n                if (userService.updateUserAvatar(currentUser.getUserId(), avatar))\r\n                {\r\n                    String oldAvatar = currentUser.getAvatar();\r\n                    if (StringUtils.isNotEmpty(oldAvatar))\r\n                    {\r\n                        FileUtils.deleteFile(RuoYiConfig.getProfile() + FileUtils.stripPrefix(oldAvatar));\r\n                    }\r\n                    currentUser.setAvatar(avatar);\r\n                    setSysUser(currentUser);\r\n                    return success();\r\n                }\r\n            }\r\n            return error();\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"修改头像失败！\", e);\r\n            return error(e.getMessage());\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.framework.shiro.service.SysRegisterService;\r\nimport com.ruoyi.system.service.ISysConfigService;\r\n\r\n/**\r\n * 注册验证\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\npublic class SysRegisterController extends BaseController\r\n{\r\n    @Autowired\r\n    private SysRegisterService registerService;\r\n\r\n    @Autowired\r\n    private ISysConfigService configService;\r\n\r\n    @GetMapping(\"/register\")\r\n    public String register()\r\n    {\r\n        return \"register\";\r\n    }\r\n\r\n    @PostMapping(\"/register\")\r\n    @ResponseBody\r\n    public AjaxResult ajaxRegister(SysUser user)\r\n    {\r\n        if (!(\"true\".equals(configService.selectConfigByKey(\"sys.account.registerUser\"))))\r\n        {\r\n            return error(\"当前系统没有开启注册功能！\");\r\n        }\r\n        String msg = registerService.register(user);\r\n        return StringUtils.isEmpty(msg) ? success() : error(msg);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java",
    "content": "package com.ruoyi.web.controller.system;\n\nimport java.util.List;\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport com.ruoyi.common.annotation.Log;\nimport com.ruoyi.common.constant.Constants;\nimport com.ruoyi.common.core.controller.BaseController;\nimport com.ruoyi.common.core.domain.AjaxResult;\nimport com.ruoyi.common.core.domain.Ztree;\nimport com.ruoyi.common.core.domain.entity.SysRole;\nimport com.ruoyi.common.core.domain.entity.SysUser;\nimport com.ruoyi.common.core.page.TableDataInfo;\nimport com.ruoyi.common.enums.BusinessType;\nimport com.ruoyi.common.utils.poi.ExcelUtil;\nimport com.ruoyi.framework.shiro.util.AuthorizationUtils;\nimport com.ruoyi.system.domain.SysUserRole;\nimport com.ruoyi.system.service.ISysDeptService;\nimport com.ruoyi.system.service.ISysMenuService;\nimport com.ruoyi.system.service.ISysRoleService;\nimport com.ruoyi.system.service.ISysUserService;\n\n/**\n * 角色信息\n * \n * @author ruoyi\n */\n@Controller\n@RequestMapping(\"/system/role\")\npublic class SysRoleController extends BaseController\n{\n    private String prefix = \"system/role\";\n\n    @Autowired\n    private ISysRoleService roleService;\n\n    @Autowired\n    private ISysUserService userService;\n\n    @Autowired\n    private ISysDeptService deptService;\n\n    @Autowired\n    private ISysMenuService menuService;\n\n    @RequiresPermissions(\"system:role:view\")\n    @GetMapping()\n    public String role()\n    {\n        return prefix + \"/role\";\n    }\n\n    @RequiresPermissions(\"system:role:list\")\n    @PostMapping(\"/list\")\n    @ResponseBody\n    public TableDataInfo list(SysRole role)\n    {\n        startPage();\n        List<SysRole> list = roleService.selectRoleList(role);\n        return getDataTable(list);\n    }\n\n    @Log(title = \"角色管理\", businessType = BusinessType.EXPORT)\n    @RequiresPermissions(\"system:role:export\")\n    @PostMapping(\"/export\")\n    @ResponseBody\n    public AjaxResult export(SysRole role)\n    {\n        List<SysRole> list = roleService.selectRoleList(role);\n        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);\n        return util.exportExcel(list, \"角色数据\");\n    }\n\n    /**\n     * 新增角色\n     */\n    @RequiresPermissions(\"system:role:add\")\n    @GetMapping(\"/add\")\n    public String add()\n    {\n        return prefix + \"/add\";\n    }\n\n    /**\n     * 新增保存角色\n     */\n    @RequiresPermissions(\"system:role:add\")\n    @Log(title = \"角色管理\", businessType = BusinessType.INSERT)\n    @PostMapping(\"/add\")\n    @ResponseBody\n    public AjaxResult addSave(@Validated SysRole role)\n    {\n        if (!roleService.checkRoleNameUnique(role))\n        {\n            return error(\"新增角色'\" + role.getRoleName() + \"'失败，角色名称已存在\");\n        }\n        else if (!roleService.checkRoleKeyUnique(role))\n        {\n            return error(\"新增角色'\" + role.getRoleName() + \"'失败，角色权限已存在\");\n        }\n        role.setCreateBy(getLoginName());\n        AuthorizationUtils.clearAllCachedAuthorizationInfo();\n        return toAjax(roleService.insertRole(role));\n\n    }\n\n    /**\n     * 修改角色\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @GetMapping(\"/edit/{roleId}\")\n    public String edit(@PathVariable(\"roleId\") Long roleId, ModelMap mmap)\n    {\n        roleService.checkRoleDataScope(roleId);\n        mmap.put(\"role\", roleService.selectRoleById(roleId));\n        return prefix + \"/edit\";\n    }\n\n    /**\n     * 修改保存角色\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @Log(title = \"角色管理\", businessType = BusinessType.UPDATE)\n    @PostMapping(\"/edit\")\n    @ResponseBody\n    public AjaxResult editSave(@Validated SysRole role)\n    {\n        roleService.checkRoleAllowed(role);\n        roleService.checkRoleDataScope(role.getRoleId());\n        if (!roleService.checkRoleNameUnique(role))\n        {\n            return error(\"修改角色'\" + role.getRoleName() + \"'失败，角色名称已存在\");\n        }\n        else if (!roleService.checkRoleKeyUnique(role))\n        {\n            return error(\"修改角色'\" + role.getRoleName() + \"'失败，角色权限已存在\");\n        }\n        role.setUpdateBy(getLoginName());\n        AuthorizationUtils.clearAllCachedAuthorizationInfo();\n        return toAjax(roleService.updateRole(role));\n    }\n\n    /**\n     * 角色分配数据权限\n     */\n    @GetMapping(\"/authDataScope/{roleId}\")\n    public String authDataScope(@PathVariable(\"roleId\") Long roleId, ModelMap mmap)\n    {\n        roleService.checkRoleDataScope(roleId);\n        mmap.put(\"role\", roleService.selectRoleById(roleId));\n        return prefix + \"/dataScope\";\n    }\n\n    /**\n     * 保存角色分配数据权限\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @Log(title = \"角色管理\", businessType = BusinessType.UPDATE)\n    @PostMapping(\"/authDataScope\")\n    @ResponseBody\n    public AjaxResult authDataScopeSave(SysRole role)\n    {\n        roleService.checkRoleAllowed(role);\n        roleService.checkRoleDataScope(role.getRoleId());\n        role.setUpdateBy(getLoginName());\n        if (roleService.authDataScope(role) > 0)\n        {\n            setSysUser(userService.selectUserById(getUserId()));\n            return success();\n        }\n        return error();\n    }\n\n    @RequiresPermissions(\"system:role:remove\")\n    @Log(title = \"角色管理\", businessType = BusinessType.DELETE)\n    @PostMapping(\"/remove\")\n    @ResponseBody\n    public AjaxResult remove(String ids)\n    {\n        return toAjax(roleService.deleteRoleByIds(ids));\n    }\n\n    /**\n     * 校验角色名称\n     */\n    @PostMapping(\"/checkRoleNameUnique\")\n    @ResponseBody\n    public boolean checkRoleNameUnique(SysRole role)\n    {\n        return roleService.checkRoleNameUnique(role);\n    }\n\n    /**\n     * 校验角色权限\n     */\n    @PostMapping(\"/checkRoleKeyUnique\")\n    @ResponseBody\n    public boolean checkRoleKeyUnique(SysRole role)\n    {\n        return roleService.checkRoleKeyUnique(role);\n    }\n\n    /**\n     * 选择菜单树\n     */\n    @GetMapping(\"/selectMenuTree\")\n    public String selectMenuTree()\n    {\n        return prefix + \"/tree\";\n    }\n\n    /**\n     * 角色状态修改\n     */\n    @Log(title = \"角色管理\", businessType = BusinessType.UPDATE)\n    @RequiresPermissions(\"system:role:edit\")\n    @PostMapping(\"/changeStatus\")\n    @ResponseBody\n    public AjaxResult changeStatus(SysRole role)\n    {\n        roleService.checkRoleAllowed(role);\n        roleService.checkRoleDataScope(role.getRoleId());\n        return toAjax(roleService.changeStatus(role));\n    }\n\n    /**\n     * 分配用户\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @GetMapping(\"/authUser/{roleId}\")\n    public String authUser(@PathVariable(\"roleId\") Long roleId, ModelMap mmap)\n    {\n        roleService.checkRoleDataScope(roleId);\n        mmap.put(\"role\", roleService.selectRoleById(roleId));\n        return prefix + \"/authUser\";\n    }\n\n    /**\n     * 查询已分配用户角色列表\n     */\n    @RequiresPermissions(\"system:role:list\")\n    @PostMapping(\"/authUser/allocatedList\")\n    @ResponseBody\n    public TableDataInfo allocatedList(SysUser user)\n    {\n        startPage();\n        List<SysUser> list = userService.selectAllocatedList(user);\n        return getDataTable(list);\n    }\n\n    /**\n     * 取消授权\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @Log(title = \"角色管理\", businessType = BusinessType.GRANT)\n    @PostMapping(\"/authUser/cancel\")\n    @ResponseBody\n    public AjaxResult cancelAuthUser(SysUserRole userRole)\n    {\n        return toAjax(roleService.deleteAuthUser(userRole));\n    }\n\n    /**\n     * 批量取消授权\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @Log(title = \"角色管理\", businessType = BusinessType.GRANT)\n    @PostMapping(\"/authUser/cancelAll\")\n    @ResponseBody\n    public AjaxResult cancelAuthUserAll(Long roleId, String userIds)\n    {\n        return toAjax(roleService.deleteAuthUsers(roleId, userIds));\n    }\n\n    /**\n     * 选择用户\n     */\n    @RequiresPermissions(\"system:role:list\")\n    @GetMapping(\"/authUser/selectUser/{roleId}\")\n    public String selectUser(@PathVariable(\"roleId\") Long roleId, ModelMap mmap)\n    {\n        mmap.put(\"role\", roleService.selectRoleById(roleId));\n        return prefix + \"/selectUser\";\n    }\n\n    /**\n     * 查询未分配用户角色列表\n     */\n    @RequiresPermissions(\"system:role:list\")\n    @PostMapping(\"/authUser/unallocatedList\")\n    @ResponseBody\n    public TableDataInfo unallocatedList(SysUser user)\n    {\n        startPage();\n        List<SysUser> list = userService.selectUnallocatedList(user);\n        return getDataTable(list);\n    }\n\n    /**\n     * 批量选择用户授权\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @Log(title = \"角色管理\", businessType = BusinessType.GRANT)\n    @PostMapping(\"/authUser/selectAll\")\n    @ResponseBody\n    public AjaxResult selectAuthUserAll(Long roleId, String userIds)\n    {\n        roleService.checkRoleDataScope(roleId);\n        return toAjax(roleService.insertAuthUsers(roleId, userIds));\n    }\n\n    /**\n     * 加载角色部门（数据权限）列表树\n     */\n    @RequiresPermissions(\"system:role:edit\")\n    @GetMapping(\"/deptTreeData\")\n    @ResponseBody\n    public List<Ztree> deptTreeData(SysRole role)\n    {\n        List<Ztree> ztrees = deptService.roleDeptTreeData(role);\n        return ztrees;\n    }\n\n    /**\n     * 查看角色详情\n     */\n    @RequiresPermissions(\"system:role:list\")\n    @GetMapping(\"/view/{roleId}\")\n    public String view(@PathVariable(\"roleId\") Long roleId, ModelMap mmap)\n    {\n        roleService.checkRoleDataScope(roleId);\n        SysRole role = roleService.selectRoleById(roleId);\n        mmap.put(\"role\", role);\n        // 菜单权限\n        mmap.put(\"menuTree\", menuService.roleMenuTreeData(role, getUserId()));\n        // 数据权限部门：仅自定义数据权限时传已勾选部门节点\n        if (Constants.Dept.DATA_SCOPE_CUSTOM.equals(role.getDataScope()))\n        {\n            List<Ztree> deptTree = deptService.roleDeptTreeData(role);\n            mmap.put(\"deptTree\", deptTree);\n        }\n        // 关联用户数量\n        mmap.put(\"userCount\", roleService.countUserRoleByRoleId(roleId));\n        return prefix + \"/view\";\n    }\n}"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java",
    "content": "package com.ruoyi.web.controller.system;\r\n\r\nimport java.util.List;\r\nimport java.util.stream.Collectors;\r\nimport org.apache.commons.lang3.ArrayUtils;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport org.springframework.web.multipart.MultipartFile;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysDept;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.framework.shiro.service.SysPasswordService;\r\nimport com.ruoyi.framework.shiro.util.AuthorizationUtils;\r\nimport com.ruoyi.system.service.ISysDeptService;\r\nimport com.ruoyi.system.service.ISysPostService;\r\nimport com.ruoyi.system.service.ISysRoleService;\r\nimport com.ruoyi.system.service.ISysUserService;\r\n\r\n/**\r\n * 用户信息\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/system/user\")\r\npublic class SysUserController extends BaseController\r\n{\r\n    private String prefix = \"system/user\";\r\n\r\n    @Autowired\r\n    private ISysUserService userService;\r\n\r\n    @Autowired\r\n    private ISysRoleService roleService;\r\n    \r\n    @Autowired\r\n    private ISysDeptService deptService;\r\n\r\n    @Autowired\r\n    private ISysPostService postService;\r\n\r\n    @Autowired\r\n    private SysPasswordService passwordService;\r\n\r\n    @RequiresPermissions(\"system:user:view\")\r\n    @GetMapping()\r\n    public String user()\r\n    {\r\n        return prefix + \"/user\";\r\n    }\r\n\r\n    @RequiresPermissions(\"system:user:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysUser user)\r\n    {\r\n        startPage();\r\n        List<SysUser> list = userService.selectUserList(user);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"用户管理\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"system:user:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysUser user)\r\n    {\r\n        List<SysUser> list = userService.selectUserList(user);\r\n        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);\r\n        return util.exportExcel(list, \"用户数据\");\r\n    }\r\n\r\n    @Log(title = \"用户管理\", businessType = BusinessType.IMPORT)\r\n    @RequiresPermissions(\"system:user:import\")\r\n    @PostMapping(\"/importData\")\r\n    @ResponseBody\r\n    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception\r\n    {\r\n        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);\r\n        List<SysUser> userList = util.importExcel(file.getInputStream());\r\n        String message = userService.importUser(userList, updateSupport, getLoginName());\r\n        return AjaxResult.success(message);\r\n    }\r\n\r\n    @RequiresPermissions(\"system:user:view\")\r\n    @GetMapping(\"/importTemplate\")\r\n    @ResponseBody\r\n    public AjaxResult importTemplate()\r\n    {\r\n        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);\r\n        return util.importTemplateExcel(\"用户数据\");\r\n    }\r\n\r\n    /**\r\n     * 新增用户\r\n     */\r\n    @RequiresPermissions(\"system:user:add\")\r\n    @GetMapping(\"/add\")\r\n    public String add(ModelMap mmap)\r\n    {\r\n        mmap.put(\"roles\", roleService.selectRoleAll().stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));\r\n        mmap.put(\"posts\", postService.selectPostAll());\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存用户\r\n     */\r\n    @RequiresPermissions(\"system:user:add\")\r\n    @Log(title = \"用户管理\", businessType = BusinessType.INSERT)\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysUser user)\r\n    {\r\n        deptService.checkDeptDataScope(user.getDeptId());\r\n        roleService.checkRoleDataScope(user.getRoleIds());\r\n        if (!userService.checkLoginNameUnique(user))\r\n        {\r\n            return error(\"新增用户'\" + user.getLoginName() + \"'失败，登录账号已存在\");\r\n        }\r\n        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))\r\n        {\r\n            return error(\"新增用户'\" + user.getLoginName() + \"'失败，手机号码已存在\");\r\n        }\r\n        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))\r\n        {\r\n            return error(\"新增用户'\" + user.getLoginName() + \"'失败，邮箱账号已存在\");\r\n        }\r\n        user.setSalt(ShiroUtils.randomSalt());\r\n        user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt()));\r\n        user.setPwdUpdateDate(DateUtils.getNowDate());\r\n        user.setCreateBy(getLoginName());\r\n        return toAjax(userService.insertUser(user));\r\n    }\r\n\r\n    /**\r\n     * 修改用户\r\n     */\r\n    @RequiresPermissions(\"system:user:edit\")\r\n    @GetMapping(\"/edit/{userId}\")\r\n    public String edit(@PathVariable(\"userId\") Long userId, ModelMap mmap)\r\n    {\r\n        userService.checkUserDataScope(userId);\r\n        List<SysRole> roles = roleService.selectRolesByUserId(userId);\r\n        mmap.put(\"user\", userService.selectUserById(userId));\r\n        mmap.put(\"roles\", ShiroUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));\r\n        mmap.put(\"posts\", postService.selectPostsByUserId(userId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 查询用户详细\r\n     */\r\n    @RequiresPermissions(\"system:user:list\")\r\n    @GetMapping(\"/view/{userId}\")\r\n    public String view(@PathVariable(\"userId\") Long userId, ModelMap mmap)\r\n    {\r\n        userService.checkUserDataScope(userId);\r\n        mmap.put(\"user\", userService.selectUserById(userId));\r\n        mmap.put(\"roleGroup\", userService.selectUserRoleGroup(userId));\r\n        mmap.put(\"postGroup\", userService.selectUserPostGroup(userId));\r\n        return prefix + \"/view\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存用户\r\n     */\r\n    @RequiresPermissions(\"system:user:edit\")\r\n    @Log(title = \"用户管理\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysUser user)\r\n    {\r\n        userService.checkUserAllowed(user);\r\n        userService.checkUserDataScope(user.getUserId());\r\n        deptService.checkDeptDataScope(user.getDeptId());\r\n        roleService.checkRoleDataScope(user.getRoleIds());\r\n        if (!userService.checkLoginNameUnique(user))\r\n        {\r\n            return error(\"修改用户'\" + user.getLoginName() + \"'失败，登录账号已存在\");\r\n        }\r\n        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))\r\n        {\r\n            return error(\"修改用户'\" + user.getLoginName() + \"'失败，手机号码已存在\");\r\n        }\r\n        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))\r\n        {\r\n            return error(\"修改用户'\" + user.getLoginName() + \"'失败，邮箱账号已存在\");\r\n        }\r\n        user.setUpdateBy(getLoginName());\r\n        AuthorizationUtils.clearAllCachedAuthorizationInfo();\r\n        return toAjax(userService.updateUser(user));\r\n    }\r\n\r\n    @RequiresPermissions(\"system:user:resetPwd\")\r\n    @GetMapping(\"/resetPwd/{userId}\")\r\n    public String resetPwd(@PathVariable(\"userId\") Long userId, ModelMap mmap)\r\n    {\r\n        userService.checkUserDataScope(userId);\r\n        mmap.put(\"user\", userService.selectUserById(userId));\r\n        return prefix + \"/resetPwd\";\r\n    }\r\n\r\n    @RequiresPermissions(\"system:user:resetPwd\")\r\n    @Log(title = \"重置密码\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/resetPwd\")\r\n    @ResponseBody\r\n    public AjaxResult resetPwdSave(SysUser user)\r\n    {\r\n        userService.checkUserAllowed(user);\r\n        userService.checkUserDataScope(user.getUserId());\r\n        user.setSalt(ShiroUtils.randomSalt());\r\n        user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt()));\r\n        if (userService.resetUserPwd(user) > 0)\r\n        {\r\n            if (ShiroUtils.getUserId().longValue() == user.getUserId().longValue())\r\n            {\r\n                setSysUser(userService.selectUserById(user.getUserId()));\r\n            }\r\n            return success();\r\n        }\r\n        return error();\r\n    }\r\n\r\n    /**\r\n     * 进入授权角色页\r\n     */\r\n    @RequiresPermissions(\"system:user:edit\")\r\n    @GetMapping(\"/authRole/{userId}\")\r\n    public String authRole(@PathVariable(\"userId\") Long userId, ModelMap mmap)\r\n    {\r\n        userService.checkUserDataScope(userId);\r\n        SysUser user = userService.selectUserById(userId);\r\n        // 获取用户所属的角色列表\r\n        List<SysRole> roles = roleService.selectRolesByUserId(userId);\r\n        mmap.put(\"user\", user);\r\n        mmap.put(\"roles\", ShiroUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));\r\n        return prefix + \"/authRole\";\r\n    }\r\n\r\n    /**\r\n     * 用户授权角色\r\n     */\r\n    @RequiresPermissions(\"system:user:edit\")\r\n    @Log(title = \"用户管理\", businessType = BusinessType.GRANT)\r\n    @PostMapping(\"/authRole/insertAuthRole\")\r\n    @ResponseBody\r\n    public AjaxResult insertAuthRole(Long userId, Long[] roleIds)\r\n    {\r\n        userService.checkUserDataScope(userId);\r\n        roleService.checkRoleDataScope(roleIds);\r\n        userService.insertUserAuth(userId, roleIds);\r\n        AuthorizationUtils.clearAllCachedAuthorizationInfo();\r\n        return success();\r\n    }\r\n\r\n    @RequiresPermissions(\"system:user:remove\")\r\n    @Log(title = \"用户管理\", businessType = BusinessType.DELETE)\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        if (ArrayUtils.contains(Convert.toLongArray(ids), getUserId()))\r\n        {\r\n            return error(\"当前用户不能删除\");\r\n        }\r\n        return toAjax(userService.deleteUserByIds(ids));\r\n    }\r\n\r\n    /**\r\n     * 校验用户名\r\n     */\r\n    @PostMapping(\"/checkLoginNameUnique\")\r\n    @ResponseBody\r\n    public boolean checkLoginNameUnique(SysUser user)\r\n    {\r\n        return userService.checkLoginNameUnique(user);\r\n    }\r\n\r\n    /**\r\n     * 校验手机号码\r\n     */\r\n    @PostMapping(\"/checkPhoneUnique\")\r\n    @ResponseBody\r\n    public boolean checkPhoneUnique(SysUser user)\r\n    {\r\n        return userService.checkPhoneUnique(user);\r\n    }\r\n\r\n    /**\r\n     * 校验email邮箱\r\n     */\r\n    @PostMapping(\"/checkEmailUnique\")\r\n    @ResponseBody\r\n    public boolean checkEmailUnique(SysUser user)\r\n    {\r\n        return userService.checkEmailUnique(user);\r\n    }\r\n\r\n    /**\r\n     * 用户状态修改\r\n     */\r\n    @Log(title = \"用户管理\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"system:user:edit\")\r\n    @PostMapping(\"/changeStatus\")\r\n    @ResponseBody\r\n    public AjaxResult changeStatus(SysUser user)\r\n    {\r\n        userService.checkUserAllowed(user);\r\n        userService.checkUserDataScope(user.getUserId());\r\n        return toAjax(userService.changeStatus(user));\r\n    }\r\n\r\n    /**\r\n     * 加载部门列表树\r\n     */\r\n    @RequiresPermissions(\"system:user:list\")\r\n    @GetMapping(\"/deptTreeData\")\r\n    @ResponseBody\r\n    public List<Ztree> deptTreeData()\r\n    {\r\n        List<Ztree> ztrees = deptService.selectDeptTree(new SysDept());\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 选择部门树\r\n     * \r\n     * @param deptId 部门ID\r\n     */\r\n    @RequiresPermissions(\"system:user:list\")\r\n    @GetMapping(\"/selectDeptTree/{deptId}\")\r\n    public String selectDeptTree(@PathVariable(\"deptId\") Long deptId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"dept\", deptService.selectDeptById(deptId));\r\n        return prefix + \"/deptTree\";\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/BuildController.java",
    "content": "package com.ruoyi.web.controller.tool;\r\n\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\n\r\n/**\r\n * build 表单构建\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/tool/build\")\r\npublic class BuildController extends BaseController\r\n{\r\n    private String prefix = \"tool/build\";\r\n\r\n    @RequiresPermissions(\"tool:build:view\")\r\n    @GetMapping()\r\n    public String build()\r\n    {\r\n        return prefix + \"/build\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/SwaggerController.java",
    "content": "package com.ruoyi.web.controller.tool;\r\n\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\n\r\n/**\r\n * swagger 接口\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/tool/swagger\")\r\npublic class SwaggerController extends BaseController\r\n{\r\n    @RequiresPermissions(\"tool:swagger:view\")\r\n    @GetMapping()\r\n    public String index()\r\n    {\r\n        return redirect(\"/swagger-ui/index.html\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java",
    "content": "package com.ruoyi.web.controller.tool;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport org.springframework.web.bind.annotation.DeleteMapping;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.PutMapping;\r\nimport org.springframework.web.bind.annotation.RequestBody;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.RestController;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.R;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport io.swagger.v3.oas.annotations.Operation;\r\nimport io.swagger.v3.oas.annotations.media.Schema;\r\nimport io.swagger.v3.oas.annotations.tags.Tag;\r\n\r\n/**\r\n * swagger 用户测试方法\r\n *\r\n * @author ruoyi\r\n */\r\n@Tag(name = \"用户信息管理\")\r\n@RestController\r\n@RequestMapping(\"/test/user\")\r\npublic class TestController extends BaseController\r\n{\r\n    private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();\r\n    {\r\n        users.put(1, new UserEntity(1, \"admin\", \"admin123\", \"15888888888\"));\r\n        users.put(2, new UserEntity(2, \"ry\", \"admin123\", \"15666666666\"));\r\n    }\r\n    \r\n    @Operation(summary = \"获取用户列表\")\r\n    @GetMapping(\"/list\")\r\n    public R<List<UserEntity>> userList()\r\n    {\r\n        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());\r\n        return R.ok(userList);\r\n    }\r\n    \r\n    @Operation(summary = \"获取用户详细\")\r\n    @GetMapping(\"/{userId}\")\r\n    public R<UserEntity> getUser(@PathVariable(name = \"userId\")\r\n    Integer userId)\r\n    {\r\n        if (!users.isEmpty() && users.containsKey(userId))\r\n        {\r\n            return R.ok(users.get(userId));\r\n        }\r\n        else\r\n        {\r\n            return R.fail(\"用户不存在\");\r\n        }\r\n    }\r\n    \r\n    @Operation(summary = \"新增用户\")\r\n    @PostMapping(\"/save\")\r\n    public R<String> save(UserEntity user)\r\n    {\r\n        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))\r\n        {\r\n            return R.fail(\"用户ID不能为空\");\r\n        }\r\n        users.put(user.getUserId(), user);\r\n        return R.ok();\r\n    }\r\n    \r\n    @Operation(summary = \"更新用户\")\r\n    @PutMapping(\"/update\")\r\n    public R<String> update(@RequestBody\r\n    UserEntity user)\r\n    {\r\n        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))\r\n        {\r\n            return R.fail(\"用户ID不能为空\");\r\n        }\r\n        if (users.isEmpty() || !users.containsKey(user.getUserId()))\r\n        {\r\n            return R.fail(\"用户不存在\");\r\n        }\r\n        users.remove(user.getUserId());\r\n        users.put(user.getUserId(), user);\r\n        return R.ok();\r\n    }\r\n    \r\n    @Operation(summary = \"删除用户信息\")\r\n    @DeleteMapping(\"/{userId}\")\r\n    public R<String> delete(@PathVariable(name = \"userId\")\r\n    Integer userId)\r\n    {\r\n        if (!users.isEmpty() && users.containsKey(userId))\r\n        {\r\n            users.remove(userId);\r\n            return R.ok();\r\n        }\r\n        else\r\n        {\r\n            return R.fail(\"用户不存在\");\r\n        }\r\n    }\r\n}\r\n\r\n@Schema(description = \"用户实体\")\r\nclass UserEntity\r\n{\r\n    @Schema(title = \"用户ID\")\r\n    private Integer userId;\r\n    \r\n    @Schema(title = \"用户名称\")\r\n    private String username;\r\n    \r\n    @Schema(title = \"用户密码\")\r\n    private String password;\r\n    \r\n    @Schema(title = \"用户手机\")\r\n    private String mobile;\r\n    \r\n    public UserEntity()\r\n    {\r\n        \r\n    }\r\n    \r\n    public UserEntity(Integer userId, String username, String password, String mobile)\r\n    {\r\n        this.userId = userId;\r\n        this.username = username;\r\n        this.password = password;\r\n        this.mobile = mobile;\r\n    }\r\n    \r\n    public Integer getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n    \r\n    public void setUserId(Integer userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n    \r\n    public String getUsername()\r\n    {\r\n        return username;\r\n    }\r\n    \r\n    public void setUsername(String username)\r\n    {\r\n        this.username = username;\r\n    }\r\n    \r\n    public String getPassword()\r\n    {\r\n        return password;\r\n    }\r\n    \r\n    public void setPassword(String password)\r\n    {\r\n        this.password = password;\r\n    }\r\n    \r\n    public String getMobile()\r\n    {\r\n        return mobile;\r\n    }\r\n    \r\n    public void setMobile(String mobile)\r\n    {\r\n        this.mobile = mobile;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java",
    "content": "package com.ruoyi.web.core.config;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport io.swagger.v3.oas.models.Components;\r\nimport io.swagger.v3.oas.models.OpenAPI;\r\nimport io.swagger.v3.oas.models.info.Contact;\r\nimport io.swagger.v3.oas.models.info.Info;\r\nimport io.swagger.v3.oas.models.security.SecurityRequirement;\r\nimport io.swagger.v3.oas.models.security.SecurityScheme;\r\n\r\n/**\r\n * Swagger2的接口配置\r\n * \r\n * @author ruoyi\r\n */\r\n@Configuration\r\npublic class SwaggerConfig\r\n{\r\n    /** 系统基础配置 */\r\n    @Autowired\r\n    private RuoYiConfig ruoyiConfig;\r\n    \r\n    /**\r\n     * 自定义的 OpenAPI 对象\r\n     */\r\n    @Bean\r\n    public OpenAPI customOpenApi()\r\n    {\r\n        return new OpenAPI().components(new Components()\r\n            // 设置认证的请求头\r\n            .addSecuritySchemes(\"apikey\", securityScheme()))\r\n            .addSecurityItem(new SecurityRequirement().addList(\"apikey\"))\r\n            .info(getApiInfo());\r\n    }\r\n    \r\n    @Bean\r\n    public SecurityScheme securityScheme()\r\n    {\r\n        return new SecurityScheme()\r\n            .type(SecurityScheme.Type.APIKEY)\r\n            .name(\"Authorization\")\r\n            .in(SecurityScheme.In.HEADER)\r\n            .scheme(\"Bearer\");\r\n    }\r\n    \r\n    /**\r\n     * 添加摘要信息\r\n     */\r\n    @SuppressWarnings(\"static-access\")\r\n    public Info getApiInfo()\r\n    {\r\n        return new Info()\r\n            // 设置标题\r\n            .title(\"标题：若依管理系统_接口文档\")\r\n            // 描述\r\n            .description(\"描述：用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...\")\r\n            // 作者信息\r\n            .contact(new Contact().name(ruoyiConfig.getName()))\r\n            // 版本\r\n            .version(\"版本号:\" + ruoyiConfig.getVersion());\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/application-druid.yml",
    "content": "# 数据源配置\r\nspring:\r\n    datasource:\r\n        type: com.alibaba.druid.pool.DruidDataSource\r\n        driverClassName: com.mysql.cj.jdbc.Driver\r\n        druid:\r\n            # 主库数据源\r\n            master:\r\n                url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\r\n                username: root\r\n                password: password\r\n            # 从库数据源\r\n            slave:\r\n                # 从数据源开关/默认关闭\r\n                enabled: false\r\n                url: \r\n                username: \r\n                password: \r\n            # 初始连接数\r\n            initialSize: 5\r\n            # 最小连接池数量\r\n            minIdle: 10\r\n            # 最大连接池数量\r\n            maxActive: 20\r\n            # 配置获取连接等待超时的时间\r\n            maxWait: 60000\r\n            # 配置连接超时时间\r\n            connectTimeout: 30000\r\n            # 配置网络超时时间\r\n            socketTimeout: 60000\r\n            # 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\r\n            timeBetweenEvictionRunsMillis: 60000\r\n            # 配置一个连接在池中最小生存的时间，单位是毫秒\r\n            minEvictableIdleTimeMillis: 300000\r\n            # 配置一个连接在池中最大生存的时间，单位是毫秒\r\n            maxEvictableIdleTimeMillis: 900000\r\n            # 配置检测连接是否有效\r\n            validationQuery: SELECT 1 FROM DUAL\r\n            testWhileIdle: true\r\n            testOnBorrow: false\r\n            testOnReturn: false\r\n            webStatFilter: \r\n                enabled: true\r\n            statViewServlet:\r\n                enabled: true\r\n                # 设置白名单，不填则允许所有访问\r\n                allow:\r\n                url-pattern: /druid/*\r\n                # 控制台管理用户名和密码\r\n                login-username: ruoyi\r\n                login-password: 123456\r\n            filter:\r\n                stat:\r\n                    enabled: true\r\n                    # 慢SQL记录\r\n                    log-slow-sql: true\r\n                    slow-sql-millis: 1000\r\n                    merge-sql: true\r\n                wall:\r\n                    config:\r\n                        multi-statement-allow: true"
  },
  {
    "path": "ruoyi-admin/src/main/resources/application.yml",
    "content": "# 项目相关配置\r\nruoyi:\r\n  # 名称\r\n  name: RuoYi\r\n  # 版本\r\n  version: 4.8.2\r\n  # 版权年份\r\n  copyrightYear: 2026\r\n  # 实例演示开关\r\n  demoEnabled: true\r\n  # 文件路径 示例（ Windows配置D:/ruoyi/uploadPath，Linux配置 /home/ruoyi/uploadPath）\r\n  profile: D:/ruoyi/uploadPath\r\n  # 获取ip地址开关\r\n  addressEnabled: false\r\n\r\n# 开发环境配置\r\nserver:\r\n  # 服务器的HTTP端口，默认为80\r\n  port: 80\r\n  servlet:\r\n    # 应用的访问路径\r\n    context-path: /\r\n  tomcat:\r\n    # tomcat的URI编码\r\n    uri-encoding: UTF-8\r\n    # 连接数满后的排队数，默认为100\r\n    accept-count: 1000\r\n    threads:\r\n      # tomcat最大线程数，默认为200\r\n      max: 800\r\n      # Tomcat启动初始化的线程数，默认值10\r\n      min-spare: 100\r\n \r\n# 日志配置\r\nlogging:\r\n  level:\r\n    com.ruoyi: debug\r\n    org.springframework: warn\r\n\r\n# 用户配置\r\nuser:\r\n  password:\r\n    # 密码错误{maxRetryCount}次锁定10分钟\r\n    maxRetryCount: 5\r\n\r\n# Spring配置\r\nspring:\r\n  jackson:\r\n    date-format: yyyy-MM-dd HH:mm:ss\r\n    time-zone: GMT+8\r\n  # 模板引擎\r\n  thymeleaf:\r\n    mode: HTML\r\n    encoding: utf-8\r\n    # 禁用缓存\r\n    cache: false\r\n  # 资源信息\r\n  messages:\r\n    # 国际化资源文件路径\r\n    basename: static/i18n/messages\r\n  profiles:\r\n    active: druid\r\n  # 文件上传\r\n  servlet:\r\n    multipart:\r\n      # 单个文件大小\r\n      max-file-size: 10MB\r\n      # 设置总上传的文件大小\r\n      max-request-size: 20MB\r\n  # 服务模块\r\n  devtools:\r\n    restart:\r\n      # 热部署开关\r\n      enabled: true\r\n\r\n# MyBatis\r\nmybatis:\r\n  # 搜索指定包别名\r\n  typeAliasesPackage: com.ruoyi.**.domain\r\n  # 配置mapper的扫描，找到所有的mapper.xml映射文件\r\n  mapperLocations: classpath*:mapper/**/*Mapper.xml\r\n  # 加载全局的配置文件\r\n  configLocation: classpath:mybatis/mybatis-config.xml\r\n\r\n# PageHelper分页插件\r\npagehelper:\r\n  helperDialect: mysql\r\n  supportMethodsArguments: true\r\n  params: count=countSql\r\n\r\n# Shiro\r\nshiro:\r\n  user:\r\n    # 登录地址\r\n    loginUrl: /login\r\n    # 权限认证失败地址\r\n    unauthorizedUrl: /unauth\r\n    # 首页地址\r\n    indexUrl: /index\r\n    # 验证码开关\r\n    captchaEnabled: true\r\n    # 验证码类型 math 数字计算 char 字符验证\r\n    captchaType: math\r\n  cookie:\r\n    # 设置Cookie的域名 默认空，即当前访问的域名\r\n    domain:\r\n    # 设置cookie的有效访问路径\r\n    path: /\r\n    # 设置HttpOnly属性\r\n    httpOnly: true\r\n    # 设置Cookie的过期时间，天为单位\r\n    maxAge: 30\r\n    # 设置密钥，务必保持唯一性（生成方式，直接拷贝到main运行即可）Base64.encodeToString(CipherUtils.generateNewKey(128, \"AES\").getEncoded()) （默认启动生成随机秘钥，随机秘钥会导致之前客户端RememberMe Cookie无效，如设置固定秘钥RememberMe Cookie则有效）\r\n    cipherKey:\r\n  session:\r\n    # Session超时时间，-1代表永不过期（默认30分钟）\r\n    expireTime: 30\r\n    # 同步session到数据库的周期（默认1分钟）\r\n    dbSyncPeriod: 1\r\n    # 相隔多久检查一次session的有效性，默认就是10分钟\r\n    validationInterval: 10\r\n    # 同一个用户最大会话数，比如2的意思是同一个账号允许最多同时两个人登录（默认-1不限制）\r\n    maxSession: -1\r\n    # 踢出之前登录的/之后登录的用户，默认踢出之前登录的用户\r\n    kickoutAfter: false\r\n  rememberMe:\r\n    # 是否开启记住我\r\n    enabled: true\r\n\r\n# Springdoc配置\r\nspringdoc:\r\n  api-docs:\r\n    path: /v3/api-docs\r\n  swagger-ui:\r\n    enabled: true\r\n    path: /swagger-ui.html\r\n    tags-sorter: alpha\r\n  group-configs:\r\n    - group: 'default'\r\n      display-name: '测试模块'\r\n      paths-to-match: '/**'\r\n      packages-to-scan: com.ruoyi.web.controller.tool\r\n\r\n# 防止XSS攻击\r\nxss:\r\n  # 过滤开关\r\n  enabled: true\r\n  # 排除链接（多个用逗号分隔）\r\n  excludes: /system/notice/*\r\n  # 匹配链接\r\n  urlPatterns: /system/*,/monitor/*,/tool/*\r\n\r\n# 防止csrf攻击\r\ncsrf:\r\n  # 过滤开关\r\n  enabled: false\r\n  # 白名单（多个用逗号分隔）\r\n  whites: /druid\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/banner.txt",
    "content": "Application Version: ${ruoyi.version}\r\nSpring Boot Version: ${spring-boot.version}\r\n////////////////////////////////////////////////////////////////////\r\n//                          _ooOoo_                               //\r\n//                         o8888888o                              //\r\n//                         88\" . \"88                              //\r\n//                         (| ^_^ |)                              //\r\n//                         O\\  =  /O                              //\r\n//                      ____/`---'\\____                           //\r\n//                    .'  \\\\|     |//  `.                         //\r\n//                   /  \\\\|||  :  |||//  \\                        //\r\n//                  /  _||||| -:- |||||-  \\                       //\r\n//                  |   | \\\\\\  -  /// |   |                       //\r\n//                  | \\_|  ''\\---/''  |   |                       //\r\n//                  \\  .-\\__  `-`  ___/-. /                       //\r\n//                ___`. .'  /--.--\\  `. . ___                     //\r\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\r\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\r\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\r\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\r\n//                           `=---='                              //\r\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\r\n//             佛祖保佑       永不宕机      永无BUG               //\r\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<ehcache name=\"ruoyi\" updateCheck=\"false\">\r\n\r\n    <!-- 磁盘缓存位置 -->\r\n    <diskStore path=\"java.io.tmpdir\"/>\r\n    \r\n    <!-- maxEntriesLocalHeap:堆内存中最大缓存对象数，0没有限制 -->\r\n    <!-- maxElementsInMemory： 在内存中缓存的element的最大数目。-->\r\n    <!-- eternal:elements是否永久有效，如果为true，timeouts将被忽略，element将永不过期 -->\r\n    <!-- timeToIdleSeconds:失效前的空闲秒数，当eternal为false时，这个属性才有效，0为不限制 -->\r\n    <!-- timeToLiveSeconds:失效前的存活秒数，创建时间到失效时间的间隔为存活时间，当eternal为false时，这个属性才有效，0为不限制 -->\r\n    <!-- overflowToDisk： 如果内存中数据超过内存限制，是否要缓存到磁盘上 -->\r\n    <!-- statistics：是否收集统计信息。如果需要监控缓存使用情况，应该打开这个选项。默认为关闭（统计会影响性能）。设置statistics=\"true\"开启统计 -->\r\n    \r\n    <!-- 默认缓存 -->\r\n    <defaultCache\r\n            maxEntriesLocalHeap=\"1000\"\r\n            eternal=\"false\"\r\n            timeToIdleSeconds=\"3600\"\r\n            timeToLiveSeconds=\"3600\"\r\n            overflowToDisk=\"false\">\r\n    </defaultCache>\r\n\r\n    <!-- 登录记录缓存 锁定10分钟 -->\r\n    <cache name=\"loginRecordCache\"\r\n           maxEntriesLocalHeap=\"2000\"\r\n           eternal=\"false\"\r\n           timeToIdleSeconds=\"600\"\r\n           timeToLiveSeconds=\"0\"\r\n           overflowToDisk=\"false\"\r\n           statistics=\"false\">\r\n    </cache>\r\n\r\n    <!-- 系统活跃用户缓存 -->\r\n    <cache name=\"sys-userCache\"\r\n           maxEntriesLocalHeap=\"10000\"\r\n           overflowToDisk=\"false\"\r\n           eternal=\"false\"\r\n           diskPersistent=\"false\"\r\n           timeToLiveSeconds=\"0\"\r\n           timeToIdleSeconds=\"0\"\r\n           statistics=\"false\">\r\n    </cache>\r\n    \r\n    <!-- 系统用户授权缓存  没必要过期 -->\r\n    <cache name=\"sys-authCache\"\r\n           maxEntriesLocalHeap=\"10000\"\r\n           overflowToDisk=\"false\"\r\n           eternal=\"false\"\r\n           diskPersistent=\"false\"\r\n           timeToLiveSeconds=\"0\"\r\n           timeToIdleSeconds=\"0\"\r\n           memoryStoreEvictionPolicy=\"LRU\"\r\n           statistics=\"false\"/>\r\n    \r\n    <!-- 系统缓存 -->\r\n    <cache name=\"sys-cache\"\r\n           maxEntriesLocalHeap=\"1000\"\r\n           eternal=\"true\"\r\n           overflowToDisk=\"true\"\r\n           statistics=\"false\">\r\n    </cache>\r\n    \r\n    <!-- 系统参数缓存 -->\r\n    <cache name=\"sys-config\"\r\n           maxEntriesLocalHeap=\"1000\"\r\n           eternal=\"true\"\r\n           overflowToDisk=\"true\"\r\n           statistics=\"false\">\r\n    </cache>\r\n    \r\n    <!-- 系统字典缓存 -->\r\n    <cache name=\"sys-dict\"\r\n           maxEntriesLocalHeap=\"1000\"\r\n           eternal=\"true\"\r\n           overflowToDisk=\"true\"\r\n           statistics=\"false\">\r\n    </cache>\r\n    \r\n    <!-- 系统会话缓存 -->\r\n    <cache name=\"shiro-activeSessionCache\"\r\n           maxEntriesLocalHeap=\"10000\"\r\n           overflowToDisk=\"false\"\r\n           eternal=\"false\"\r\n           diskPersistent=\"false\"\r\n           timeToLiveSeconds=\"0\"\r\n           timeToIdleSeconds=\"0\"\r\n           statistics=\"false\"/>\r\n    \r\n</ehcache>\r\n\t"
  },
  {
    "path": "ruoyi-admin/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<configuration>\r\n    <!-- 日志存放路径 -->\r\n\t<property name=\"log.path\" value=\"/home/ruoyi/logs\" />\r\n    <!-- 日志输出格式 -->\r\n\t<property name=\"log.pattern\" value=\"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n\" />\r\n\r\n\t<!-- 控制台输出 -->\r\n\t<appender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\r\n\t\t<encoder>\r\n\t\t\t<pattern>${log.pattern}</pattern>\r\n\t\t</encoder>\r\n\t</appender>\r\n\t\r\n\t<!-- 系统日志输出 -->\r\n\t<appender name=\"file_info\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n\t    <file>${log.path}/sys-info.log</file>\r\n        <!-- 循环政策：基于时间创建日志文件 -->\r\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <!-- 日志文件名格式 -->\r\n\t\t\t<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>\r\n\t\t\t<!-- 日志最大的历史 60天 -->\r\n\t\t\t<maxHistory>60</maxHistory>\r\n\t\t</rollingPolicy>\r\n\t\t<encoder>\r\n\t\t\t<pattern>${log.pattern}</pattern>\r\n\t\t</encoder>\r\n\t\t<filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\r\n            <!-- 过滤的级别 -->\r\n            <level>INFO</level>\r\n            <!-- 匹配时的操作：接收（记录） -->\r\n            <onMatch>ACCEPT</onMatch>\r\n            <!-- 不匹配时的操作：拒绝（不记录） -->\r\n            <onMismatch>DENY</onMismatch>\r\n        </filter>\r\n\t</appender>\r\n\t\r\n\t<appender name=\"file_error\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n\t    <file>${log.path}/sys-error.log</file>\r\n        <!-- 循环政策：基于时间创建日志文件 -->\r\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <!-- 日志文件名格式 -->\r\n            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>\r\n\t\t\t<!-- 日志最大的历史 60天 -->\r\n\t\t\t<maxHistory>60</maxHistory>\r\n        </rollingPolicy>\r\n        <encoder>\r\n            <pattern>${log.pattern}</pattern>\r\n        </encoder>\r\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\r\n            <!-- 过滤的级别 -->\r\n            <level>ERROR</level>\r\n\t\t\t<!-- 匹配时的操作：接收（记录） -->\r\n            <onMatch>ACCEPT</onMatch>\r\n\t\t\t<!-- 不匹配时的操作：拒绝（不记录） -->\r\n            <onMismatch>DENY</onMismatch>\r\n        </filter>\r\n    </appender>\r\n\t\r\n\t<!-- 用户访问日志输出  -->\r\n    <appender name=\"sys-user\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\r\n\t\t<file>${log.path}/sys-user.log</file>\r\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\r\n            <!-- 按天回滚 daily -->\r\n            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>\r\n            <!-- 日志最大的历史 60天 -->\r\n            <maxHistory>60</maxHistory>\r\n        </rollingPolicy>\r\n        <encoder>\r\n            <pattern>${log.pattern}</pattern>\r\n        </encoder>\r\n    </appender>\r\n\t\r\n\t<!-- 系统模块日志级别控制  -->\r\n\t<logger name=\"com.ruoyi\" level=\"info\" />\r\n\t<!-- Spring日志级别控制  -->\r\n\t<logger name=\"org.springframework\" level=\"warn\" />\r\n\t<!-- Thymeleaf日志级别控制  -->\r\n\t<Logger name=\"org.thymeleaf\" level=\"error\"/>\r\n\t<!-- springdoc日志级别控制  -->\r\n\t<logger name=\"org.springdoc\" level=\"error\" />\r\n\t<!-- BeanPostProcessorChecker日志级别控制 -->\r\n\t<logger name=\"org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker\" level=\"error\" />\r\n\r\n\t<root level=\"info\">\r\n\t\t<appender-ref ref=\"console\" />\r\n\t</root>\r\n\t\r\n\t<!--系统操作日志-->\r\n    <root level=\"info\">\r\n        <appender-ref ref=\"file_info\" />\r\n        <appender-ref ref=\"file_error\" />\r\n    </root>\r\n\t\r\n\t<!--系统用户操作日志-->\r\n    <logger name=\"sys-user\" level=\"info\">\r\n        <appender-ref ref=\"sys-user\"/>\r\n    </logger>\r\n</configuration> "
  },
  {
    "path": "ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration\nPUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <!-- 全局参数 -->\n    <settings>\n        <!-- 使全局的映射器启用或禁用缓存 -->\n        <setting name=\"cacheEnabled\"             value=\"true\"   />\n        <!-- 允许JDBC 支持自动生成主键 -->\n        <setting name=\"useGeneratedKeys\"         value=\"true\"   />\n        <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->\n        <setting name=\"defaultExecutorType\"      value=\"SIMPLE\" />\n\t\t<!-- 指定 MyBatis 所用日志的具体实现 -->\n        <setting name=\"logImpl\"                  value=\"SLF4J\"  />\n        <!-- 使用驼峰命名法转换字段 -->\n\t\t<!-- <setting name=\"mapUnderscoreToCamelCase\" value=\"true\"/> -->\n\t</settings>\n\t\n</configuration>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/beautifyhtml/beautifyhtml.js",
    "content": "/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */\r\n/*\r\n\r\n  The MIT License (MIT)\r\n\r\n  Copyright (c) 2007-2013 Einar Lielmanis and contributors.\r\n\r\n  Permission is hereby granted, free of charge, to any person\r\n  obtaining a copy of this software and associated documentation files\r\n  (the \"Software\"), to deal in the Software without restriction,\r\n  including without limitation the rights to use, copy, modify, merge,\r\n  publish, distribute, sublicense, and/or sell copies of the Software,\r\n  and to permit persons to whom the Software is furnished to do so,\r\n  subject to the following conditions:\r\n\r\n  The above copyright notice and this permission notice shall be\r\n  included in all copies or substantial portions of the Software.\r\n\r\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r\n  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r\n  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r\n  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n  SOFTWARE.\r\n\r\n\r\n Style HTML\r\n---------------\r\n\r\n  Written by Nochum Sossonko, (nsossonko@hotmail.com)\r\n\r\n  Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>\r\n    http://jsbeautifier.org/\r\n\r\n  Usage:\r\n    style_html(html_source);\r\n\r\n    style_html(html_source, options);\r\n\r\n  The options are:\r\n    indent_size (default 4)          — indentation size,\r\n    indent_char (default space)      — character to indent with,\r\n    max_char (default 250)            -  maximum amount of characters per line (0 = disable)\r\n    brace_style (default \"collapse\") - \"collapse\" | \"expand\" | \"end-expand\"\r\n            put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.\r\n    unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted\r\n    indent_scripts (default normal)  - \"keep\"|\"separate\"|\"normal\"\r\n\r\n    e.g.\r\n\r\n    style_html(html_source, {\r\n      'indent_size': 2,\r\n      'indent_char': ' ',\r\n      'max_char': 78,\r\n      'brace_style': 'expand',\r\n      'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u']\r\n    });\r\n*/\r\n\r\n(function() {\r\n\r\n    function style_html(html_source, options, js_beautify, css_beautify) {\r\n    //Wrapper function to invoke all the necessary constructors and deal with the output.\r\n\r\n      var multi_parser,\r\n          indent_size,\r\n          indent_character,\r\n          max_char,\r\n          brace_style,\r\n          unformatted;\r\n\r\n      options = options || {};\r\n      indent_size = options.indent_size || 4;\r\n      indent_character = options.indent_char || ' ';\r\n      brace_style = options.brace_style || 'collapse';\r\n      max_char = options.max_char === 0 ? Infinity : options.max_char || 250;\r\n      unformatted = options.unformatted || ['a', 'span', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];\r\n\r\n      function Parser() {\r\n\r\n        this.pos = 0; //Parser position\r\n        this.token = '';\r\n        this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT\r\n        this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values\r\n          parent: 'parent1',\r\n          parentcount: 1,\r\n          parent1: ''\r\n        };\r\n        this.tag_type = '';\r\n        this.token_text = this.last_token = this.last_text = this.token_type = '';\r\n\r\n        this.Utils = { //Uilities made available to the various functions\r\n          whitespace: \"\\n\\r\\t \".split(''),\r\n          single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML\r\n          extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them\r\n          in_array: function (what, arr) {\r\n            for (var i=0; i<arr.length; i++) {\r\n              if (what === arr[i]) {\r\n                return true;\r\n              }\r\n            }\r\n            return false;\r\n          }\r\n        };\r\n\r\n        this.get_content = function () { //function to capture regular content between tags\r\n\r\n          var input_char = '',\r\n              content = [],\r\n              space = false; //if a space is needed\r\n\r\n          while (this.input.charAt(this.pos) !== '<') {\r\n            if (this.pos >= this.input.length) {\r\n              return content.length?content.join(''):['', 'TK_EOF'];\r\n            }\r\n\r\n            input_char = this.input.charAt(this.pos);\r\n            this.pos++;\r\n            this.line_char_count++;\r\n\r\n            if (this.Utils.in_array(input_char, this.Utils.whitespace)) {\r\n              if (content.length) {\r\n                space = true;\r\n              }\r\n              this.line_char_count--;\r\n              continue; //don't want to insert unnecessary space\r\n            }\r\n            else if (space) {\r\n              if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached\r\n                content.push('\\n');\r\n                for (var i=0; i<this.indent_level; i++) {\r\n                  content.push(this.indent_string);\r\n                }\r\n                this.line_char_count = 0;\r\n              }\r\n              else{\r\n                content.push(' ');\r\n                this.line_char_count++;\r\n              }\r\n              space = false;\r\n            }\r\n            content.push(input_char); //letter at-a-time (or string) inserted to an array\r\n          }\r\n          return content.length?content.join(''):'';\r\n        };\r\n\r\n        this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify\r\n          if (this.pos === this.input.length) {\r\n            return ['', 'TK_EOF'];\r\n          }\r\n          var input_char = '';\r\n          var content = '';\r\n          var reg_match = new RegExp('</' + name + '\\\\s*>', 'igm');\r\n          reg_match.lastIndex = this.pos;\r\n          var reg_array = reg_match.exec(this.input);\r\n          var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script\r\n          if(this.pos < end_script) { //get everything in between the script tags\r\n            content = this.input.substring(this.pos, end_script);\r\n            this.pos = end_script;\r\n          }\r\n          return content;\r\n        };\r\n\r\n        this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object\r\n          if (this.tags[tag + 'count']) { //check for the existence of this tag type\r\n            this.tags[tag + 'count']++;\r\n            this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level\r\n          }\r\n          else { //otherwise initialize this tag type\r\n            this.tags[tag + 'count'] = 1;\r\n            this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level\r\n          }\r\n          this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)\r\n          this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')\r\n        };\r\n\r\n        this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer\r\n          if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it\r\n            var temp_parent = this.tags.parent; //check to see if it's a closable tag.\r\n            while (temp_parent) { //till we reach '' (the initial value);\r\n              if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it\r\n                break;\r\n              }\r\n              temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree\r\n            }\r\n            if (temp_parent) { //if we caught something\r\n              this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly\r\n              this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent\r\n            }\r\n            delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...\r\n            delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself\r\n            if (this.tags[tag + 'count'] === 1) {\r\n              delete this.tags[tag + 'count'];\r\n            }\r\n            else {\r\n              this.tags[tag + 'count']--;\r\n            }\r\n          }\r\n        };\r\n\r\n        this.get_tag = function (peek) { //function to get a full tag and parse its type\r\n          var input_char = '',\r\n              content = [],\r\n              comment = '',\r\n              space = false,\r\n              tag_start, tag_end,\r\n              orig_pos = this.pos,\r\n              orig_line_char_count = this.line_char_count;\r\n\r\n          peek = peek !== undefined ? peek : false;\r\n\r\n          do {\r\n            if (this.pos >= this.input.length) {\r\n              if (peek) {\r\n                this.pos = orig_pos;\r\n                this.line_char_count = orig_line_char_count;\r\n              }\r\n              return content.length?content.join(''):['', 'TK_EOF'];\r\n            }\r\n\r\n            input_char = this.input.charAt(this.pos);\r\n            this.pos++;\r\n            this.line_char_count++;\r\n\r\n            if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space\r\n              space = true;\r\n              this.line_char_count--;\r\n              continue;\r\n            }\r\n\r\n            if (input_char === \"'\" || input_char === '\"') {\r\n              if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially\r\n                input_char += this.get_unformatted(input_char);\r\n                space = true;\r\n              }\r\n            }\r\n\r\n            if (input_char === '=') { //no space before =\r\n              space = false;\r\n            }\r\n\r\n            if (content.length && content[content.length-1] !== '=' && input_char !== '>' && space) {\r\n                //no space after = or before >\r\n              if (this.line_char_count >= this.max_char) {\r\n                this.print_newline(false, content);\r\n                this.line_char_count = 0;\r\n              }\r\n              else {\r\n                content.push(' ');\r\n                this.line_char_count++;\r\n              }\r\n              space = false;\r\n            }\r\n            if (input_char === '<') {\r\n              tag_start = this.pos - 1;\r\n            }\r\n            content.push(input_char); //inserts character at-a-time (or string)\r\n          } while (input_char !== '>');\r\n\r\n          var tag_complete = content.join('');\r\n          var tag_index;\r\n          if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends\r\n            tag_index = tag_complete.indexOf(' ');\r\n          }\r\n          else { //otherwise go with the tag ending\r\n            tag_index = tag_complete.indexOf('>');\r\n          }\r\n          var tag_check = tag_complete.substring(1, tag_index).toLowerCase();\r\n          if (tag_complete.charAt(tag_complete.length-2) === '/' ||\r\n            this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)\r\n            if ( ! peek) {\r\n              this.tag_type = 'SINGLE';\r\n            }\r\n          }\r\n          else if (tag_check === 'script') { //for later script handling\r\n            if ( ! peek) {\r\n              this.record_tag(tag_check);\r\n              this.tag_type = 'SCRIPT';\r\n            }\r\n          }\r\n          else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)\r\n            if ( ! peek) {\r\n              this.record_tag(tag_check);\r\n              this.tag_type = 'STYLE';\r\n            }\r\n          }\r\n          else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the \"unformatted\" tags\r\n            comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function\r\n            content.push(comment);\r\n            // Preserve collapsed whitespace either before or after this tag.\r\n            if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){\r\n                content.splice(0, 0, this.input.charAt(tag_start - 1));\r\n            }\r\n            tag_end = this.pos - 1;\r\n            if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){\r\n                content.push(this.input.charAt(tag_end + 1));\r\n            }\r\n            this.tag_type = 'SINGLE';\r\n          }\r\n          else if (tag_check.charAt(0) === '!') { //peek for <!-- comment\r\n            if (tag_check.indexOf('[if') !== -1) { //peek for <!--[if conditional comment\r\n              if (tag_complete.indexOf('!IE') !== -1) { //this type needs a closing --> so...\r\n                comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted\r\n                content.push(comment);\r\n              }\r\n              if ( ! peek) {\r\n                this.tag_type = 'START';\r\n              }\r\n            }\r\n            else if (tag_check.indexOf('[endif') !== -1) {//peek for <!--[endif end conditional comment\r\n              this.tag_type = 'END';\r\n              this.unindent();\r\n            }\r\n            else if (tag_check.indexOf('[cdata[') !== -1) { //if it's a <[cdata[ comment...\r\n              comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function\r\n              content.push(comment);\r\n              if ( ! peek) {\r\n                this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags\r\n              }\r\n            }\r\n            else {\r\n              comment = this.get_unformatted('-->', tag_complete);\r\n              content.push(comment);\r\n              this.tag_type = 'SINGLE';\r\n            }\r\n          }\r\n          else if ( ! peek) {\r\n            if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending\r\n              this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors\r\n              this.tag_type = 'END';\r\n            }\r\n            else { //otherwise it's a start-tag\r\n              this.record_tag(tag_check); //push it on the tag stack\r\n              this.tag_type = 'START';\r\n            }\r\n            if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line\r\n              this.print_newline(true, this.output);\r\n            }\r\n          }\r\n\r\n          if (peek) {\r\n            this.pos = orig_pos;\r\n            this.line_char_count = orig_line_char_count;\r\n          }\r\n\r\n          return content.join(''); //returns fully formatted tag\r\n        };\r\n\r\n        this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety\r\n\r\n          if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) {\r\n            return '';\r\n          }\r\n          var input_char = '';\r\n          var content = '';\r\n          var space = true;\r\n          do {\r\n\r\n            if (this.pos >= this.input.length) {\r\n              return content;\r\n            }\r\n\r\n            input_char = this.input.charAt(this.pos);\r\n            this.pos++;\r\n\r\n            if (this.Utils.in_array(input_char, this.Utils.whitespace)) {\r\n              if (!space) {\r\n                this.line_char_count--;\r\n                continue;\r\n              }\r\n              if (input_char === '\\n' || input_char === '\\r') {\r\n                content += '\\n';\r\n                /*  Don't change tab indention for unformatted blocks.  If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'\r\n                for (var i=0; i<this.indent_level; i++) {\r\n                  content += this.indent_string;\r\n                }\r\n                space = false; //...and make sure other indentation is erased\r\n                */\r\n                this.line_char_count = 0;\r\n                continue;\r\n              }\r\n            }\r\n            content += input_char;\r\n            this.line_char_count++;\r\n            space = true;\r\n\r\n\r\n          } while (content.toLowerCase().indexOf(delimiter) === -1);\r\n          return content;\r\n        };\r\n\r\n        this.get_token = function () { //initial handler for token-retrieval\r\n          var token;\r\n\r\n          if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript\r\n           var type = this.last_token.substr(7);\r\n           token = this.get_contents_to(type);\r\n            if (typeof token !== 'string') {\r\n              return token;\r\n            }\r\n            return [token, 'TK_' + type];\r\n          }\r\n          if (this.current_mode === 'CONTENT') {\r\n            token = this.get_content();\r\n            if (typeof token !== 'string') {\r\n              return token;\r\n            }\r\n            else {\r\n              return [token, 'TK_CONTENT'];\r\n            }\r\n          }\r\n\r\n          if (this.current_mode === 'TAG') {\r\n            token = this.get_tag();\r\n            if (typeof token !== 'string') {\r\n              return token;\r\n            }\r\n            else {\r\n              var tag_name_type = 'TK_TAG_' + this.tag_type;\r\n              return [token, tag_name_type];\r\n            }\r\n          }\r\n        };\r\n\r\n        this.get_full_indent = function (level) {\r\n          level = this.indent_level + level || 0;\r\n          if (level < 1) {\r\n            return '';\r\n          }\r\n\r\n          return Array(level + 1).join(this.indent_string);\r\n        };\r\n\r\n        this.is_unformatted = function(tag_check, unformatted) {\r\n            //is this an HTML5 block-level link?\r\n            if (!this.Utils.in_array(tag_check, unformatted)){\r\n                return false;\r\n            }\r\n\r\n            if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)){\r\n                return true;\r\n            }\r\n\r\n            //at this point we have an  tag; is its first child something we want to remain\r\n            //unformatted?\r\n            var next_tag = this.get_tag(true /* peek. */);\r\n\r\n            // tets next_tag to see if it is just html tag (no external content)\r\n            var tag = (next_tag || \"\").match(/^\\s*<\\s*\\/?([a-z]*)\\s*[^>]*>\\s*$/);\r\n\r\n            // if next_tag comes back but is not an isolated tag, then\r\n            // let's treat the 'a' tag as having content\r\n            // and respect the unformatted option\r\n            if (!tag || this.Utils.in_array(tag, unformatted)){\r\n                return true;\r\n            } else {\r\n                return false;\r\n            }\r\n        };\r\n\r\n        this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions\r\n\r\n          this.input = js_source || ''; //gets the input for the Parser\r\n          this.output = [];\r\n          this.indent_character = indent_character;\r\n          this.indent_string = '';\r\n          this.indent_size = indent_size;\r\n          this.brace_style = brace_style;\r\n          this.indent_level = 0;\r\n          this.max_char = max_char;\r\n          this.line_char_count = 0; //count to see if max_char was exceeded\r\n\r\n          for (var i=0; i<this.indent_size; i++) {\r\n            this.indent_string += this.indent_character;\r\n          }\r\n\r\n          this.print_newline = function (ignore, arr) {\r\n            this.line_char_count = 0;\r\n            if (!arr || !arr.length) {\r\n              return;\r\n            }\r\n            if (!ignore) { //we might want the extra line\r\n              while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {\r\n                arr.pop();\r\n              }\r\n            }\r\n            arr.push('\\n');\r\n            for (var i=0; i<this.indent_level; i++) {\r\n              arr.push(this.indent_string);\r\n            }\r\n          };\r\n\r\n          this.print_token = function (text) {\r\n            this.output.push(text);\r\n          };\r\n\r\n          this.indent = function () {\r\n            this.indent_level++;\r\n          };\r\n\r\n          this.unindent = function () {\r\n            if (this.indent_level > 0) {\r\n              this.indent_level--;\r\n            }\r\n          };\r\n        };\r\n        return this;\r\n      }\r\n\r\n      /*_____________________--------------------_____________________*/\r\n\r\n      multi_parser = new Parser(); //wrapping functions Parser\r\n      multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values\r\n\r\n      while (true) {\r\n          var t = multi_parser.get_token();\r\n          multi_parser.token_text = t[0];\r\n          multi_parser.token_type = t[1];\r\n\r\n        if (multi_parser.token_type === 'TK_EOF') {\r\n          break;\r\n        }\r\n\r\n        switch (multi_parser.token_type) {\r\n          case 'TK_TAG_START':\r\n            multi_parser.print_newline(false, multi_parser.output);\r\n            multi_parser.print_token(multi_parser.token_text);\r\n            multi_parser.indent();\r\n            multi_parser.current_mode = 'CONTENT';\r\n            break;\r\n          case 'TK_TAG_STYLE':\r\n          case 'TK_TAG_SCRIPT':\r\n            multi_parser.print_newline(false, multi_parser.output);\r\n            multi_parser.print_token(multi_parser.token_text);\r\n            multi_parser.current_mode = 'CONTENT';\r\n            break;\r\n          case 'TK_TAG_END':\r\n            //Print new line only if the tag has no content and has child\r\n            if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {\r\n                var tag_name = multi_parser.token_text.match(/\\w+/)[0];\r\n                var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\\s*(\\w+)/);\r\n                if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name) {\r\n                    multi_parser.print_newline(true, multi_parser.output);\r\n                }\r\n            }\r\n            multi_parser.print_token(multi_parser.token_text);\r\n            multi_parser.current_mode = 'CONTENT';\r\n            break;\r\n          case 'TK_TAG_SINGLE':\r\n            // Don't add a newline before elements that should remain unformatted.\r\n            var tag_check = multi_parser.token_text.match(/^\\s*<([a-z]+)/i);\r\n            if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){\r\n                multi_parser.print_newline(false, multi_parser.output);\r\n            }\r\n            multi_parser.print_token(multi_parser.token_text);\r\n            multi_parser.current_mode = 'CONTENT';\r\n            break;\r\n          case 'TK_CONTENT':\r\n            if (multi_parser.token_text !== '') {\r\n              multi_parser.print_token(multi_parser.token_text);\r\n            }\r\n            multi_parser.current_mode = 'TAG';\r\n            break;\r\n          case 'TK_STYLE':\r\n          case 'TK_SCRIPT':\r\n            if (multi_parser.token_text !== '') {\r\n              multi_parser.output.push('\\n');\r\n              var text = multi_parser.token_text,\r\n                  _beautifier,\r\n                  script_indent_level = 1;\r\n              if (multi_parser.token_type === 'TK_SCRIPT') {\r\n                _beautifier = typeof js_beautify === 'function' && js_beautify;\r\n              } else if (multi_parser.token_type === 'TK_STYLE') {\r\n                _beautifier = typeof css_beautify === 'function' && css_beautify;\r\n              }\r\n\r\n              if (options.indent_scripts === \"keep\") {\r\n                script_indent_level = 0;\r\n              } else if (options.indent_scripts === \"separate\") {\r\n                script_indent_level = -multi_parser.indent_level;\r\n              }\r\n\r\n              var indentation = multi_parser.get_full_indent(script_indent_level);\r\n              if (_beautifier) {\r\n                // call the Beautifier if avaliable\r\n                text = _beautifier(text.replace(/^\\s*/, indentation), options);\r\n              } else {\r\n                // simply indent the string otherwise\r\n                var white = text.match(/^\\s*/)[0];\r\n                var _level = white.match(/[^\\n\\r]*$/)[0].split(multi_parser.indent_string).length - 1;\r\n                var reindent = multi_parser.get_full_indent(script_indent_level -_level);\r\n                text = text.replace(/^\\s*/, indentation)\r\n                       .replace(/\\r\\n|\\r|\\n/g, '\\n' + reindent)\r\n                       .replace(/\\s*$/, '');\r\n              }\r\n              if (text) {\r\n                multi_parser.print_token(text);\r\n                multi_parser.print_newline(true, multi_parser.output);\r\n              }\r\n            }\r\n            multi_parser.current_mode = 'TAG';\r\n            break;\r\n        }\r\n        multi_parser.last_token = multi_parser.token_type;\r\n        multi_parser.last_text = multi_parser.token_text;\r\n      }\r\n      return multi_parser.output.join('');\r\n    }\r\n\r\n    // If we're running a web page and don't have either of the above, add our one global\r\n    window.html_beautify = function(html_source, options) {\r\n        return style_html(html_source, options, window.js_beautify, window.css_beautify);\r\n    };\r\n\r\n}());\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/blockUI/jquery.blockUI.js",
    "content": "﻿/*!\r\n * jQuery blockUI plugin\r\n * Version 2.70.0-2014.11.23\r\n * Requires jQuery v1.7 or later\r\n *\r\n * Examples at: http://malsup.com/jquery/block/\r\n * Copyright (c) 2007-2013 M. Alsup\r\n * Dual licensed under the MIT and GPL licenses:\r\n * http://www.opensource.org/licenses/mit-license.php\r\n * http://www.gnu.org/licenses/gpl.html\r\n *\r\n * Thanks to Amir-Hossein Sobhi for some excellent contributions!\r\n */\r\n\r\n;(function() {\r\n/*jshint eqeqeq:false curly:false latedef:false */\r\n\"use strict\";\r\n\r\n\tfunction setup($) {\r\n\t\t$.fn._fadeIn = $.fn.fadeIn;\r\n\r\n\t\tvar noOp = $.noop || function() {};\r\n\r\n\t\t// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle\r\n\t\t// confusing userAgent strings on Vista)\r\n\t\tvar msie = /MSIE/.test(navigator.userAgent);\r\n\t\tvar ie6  = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);\r\n\t\tvar mode = document.documentMode || 0;\r\n\t\tvar setExpr = $.isFunction( document.createElement('div').style.setExpression );\r\n\r\n\t\t// global $ methods for blocking/unblocking the entire page\r\n\t\t$.blockUI   = function(opts) { install(window, opts); };\r\n\t\t$.unblockUI = function(opts) { remove(window, opts); };\r\n\r\n\t\t// convenience method for quick growl-like notifications  (http://www.google.com/search?q=growl)\r\n\t\t$.growlUI = function(title, message, timeout, onClose) {\r\n\t\t\tvar $m = $('<div class=\"growlUI\"></div>');\r\n\t\t\tif (title) $m.append('<h1>'+title+'</h1>');\r\n\t\t\tif (message) $m.append('<h2>'+message+'</h2>');\r\n\t\t\tif (timeout === undefined) timeout = 3000;\r\n\r\n\t\t\t// Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications\r\n\t\t\tvar callBlock = function(opts) {\r\n\t\t\t\topts = opts || {};\r\n\r\n\t\t\t\t$.blockUI({\r\n\t\t\t\t\tmessage: $m,\r\n\t\t\t\t\tfadeIn : typeof opts.fadeIn  !== 'undefined' ? opts.fadeIn  : 700,\r\n\t\t\t\t\tfadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,\r\n\t\t\t\t\ttimeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,\r\n\t\t\t\t\tcenterY: false,\r\n\t\t\t\t\tshowOverlay: false,\r\n\t\t\t\t\tonUnblock: onClose,\r\n\t\t\t\t\tcss: $.blockUI.defaults.growlCSS\r\n\t\t\t\t});\r\n\t\t\t};\r\n\r\n\t\t\tcallBlock();\r\n\t\t\tvar nonmousedOpacity = $m.css('opacity');\r\n\t\t\t$m.mouseover(function() {\r\n\t\t\t\tcallBlock({\r\n\t\t\t\t\tfadeIn: 0,\r\n\t\t\t\t\ttimeout: 30000\r\n\t\t\t\t});\r\n\r\n\t\t\t\tvar displayBlock = $('.blockMsg');\r\n\t\t\t\tdisplayBlock.stop(); // cancel fadeout if it has started\r\n\t\t\t\tdisplayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency\r\n\t\t\t}).mouseout(function() {\r\n\t\t\t\t$('.blockMsg').fadeOut(1000);\r\n\t\t\t});\r\n\t\t\t// End konapun additions\r\n\t\t};\r\n\r\n\t\t// plugin method for blocking element content\r\n\t\t$.fn.block = function(opts) {\r\n\t\t\tif ( this[0] === window ) {\r\n\t\t\t\t$.blockUI( opts );\r\n\t\t\t\treturn this;\r\n\t\t\t}\r\n\t\t\tvar fullOpts = $.extend({}, $.blockUI.defaults, opts || {});\r\n\t\t\tthis.each(function() {\r\n\t\t\t\tvar $el = $(this);\r\n\t\t\t\tif (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))\r\n\t\t\t\t\treturn;\r\n\t\t\t\t$el.unblock({ fadeOut: 0 });\r\n\t\t\t});\r\n\r\n\t\t\treturn this.each(function() {\r\n\t\t\t\tif ($.css(this,'position') == 'static') {\r\n\t\t\t\t\tthis.style.position = 'relative';\r\n\t\t\t\t\t$(this).data('blockUI.static', true);\r\n\t\t\t\t}\r\n\t\t\t\tthis.style.zoom = 1; // force 'hasLayout' in ie\r\n\t\t\t\tinstall(this, opts);\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\t// plugin method for unblocking element content\r\n\t\t$.fn.unblock = function(opts) {\r\n\t\t\tif ( this[0] === window ) {\r\n\t\t\t\t$.unblockUI( opts );\r\n\t\t\t\treturn this;\r\n\t\t\t}\r\n\t\t\treturn this.each(function() {\r\n\t\t\t\tremove(this, opts);\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\t$.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!\r\n\r\n\t\t// override these in your code to change the default behavior and style\r\n\t\t$.blockUI.defaults = {\r\n\t\t\t// message displayed when blocking (use null for no message)\r\n\t\t\tmessage:  '<div class=\"loaderbox\"><div class=\"loading-activity\"></div> 加载中......</div>',\r\n\r\n\t\t\ttitle: null,\t\t// title string; only used when theme == true\r\n\t\t\tdraggable: true,\t// only used when theme == true (requires jquery-ui.js to be loaded)\r\n\r\n\t\t\ttheme: false, // set to true to use with jQuery UI themes\r\n\r\n\t\t\t// styles for the message when blocking; if you wish to disable\r\n\t\t\t// these and use an external stylesheet then do this in your code:\r\n\t\t\t// $.blockUI.defaults.css = {};\r\n\t\t\tcss: {\r\n\t\t\t\tpadding:\t0,\r\n\t\t\t\tmargin:\t\t0,\r\n\t\t\t\twidth:\t\t'30%',\r\n\t\t\t\ttop:\t\t'40%',\r\n\t\t\t\tleft:\t\t'35%',\r\n\t\t\t\ttextAlign:\t'center',\r\n\t\t\t\tcolor:\t\t'#000',\r\n\t\t\t\tborder:\t\t'0px',\r\n\t\t\t\tbackgroundColor:'transparent',\r\n\t\t\t\tcursor:\t\t'wait'\r\n\t\t\t},\r\n\r\n\t\t\t// minimal style set used when themes are used\r\n\t\t\tthemedCSS: {\r\n\t\t\t\twidth:\t'30%',\r\n\t\t\t\ttop:\t'40%',\r\n\t\t\t\tleft:\t'35%'\r\n\t\t\t},\r\n\r\n\t\t\t// styles for the overlay\r\n\t\t\toverlayCSS:  {\r\n\t\t\t\tbackgroundColor:\t'#000',\r\n\t\t\t\topacity:\t\t\t0.6,\r\n\t\t\t\tcursor:\t\t\t\t'wait'\r\n\t\t\t},\r\n\r\n\t\t\t// style to replace wait cursor before unblocking to correct issue\r\n\t\t\t// of lingering wait cursor\r\n\t\t\tcursorReset: 'default',\r\n\r\n\t\t\t// styles applied when using $.growlUI\r\n\t\t\tgrowlCSS: {\r\n\t\t\t\twidth:\t\t'350px',\r\n\t\t\t\ttop:\t\t'10px',\r\n\t\t\t\tleft:\t\t'',\r\n\t\t\t\tright:\t\t'10px',\r\n\t\t\t\tborder:\t\t'none',\r\n\t\t\t\tpadding:\t'5px',\r\n\t\t\t\topacity:\t0.6,\r\n\t\t\t\tcursor:\t\t'default',\r\n\t\t\t\tcolor:\t\t'#fff',\r\n\t\t\t\tbackgroundColor: '#000',\r\n\t\t\t\t'-webkit-border-radius':'10px',\r\n\t\t\t\t'-moz-border-radius':\t'10px',\r\n\t\t\t\t'border-radius':\t\t'10px'\r\n\t\t\t},\r\n\r\n\t\t\t// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w\r\n\t\t\t// (hat tip to Jorge H. N. de Vasconcelos)\r\n\t\t\t/*jshint scripturl:true */\r\n\t\t\tiframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',\r\n\r\n\t\t\t// force usage of iframe in non-IE browsers (handy for blocking applets)\r\n\t\t\tforceIframe: false,\r\n\r\n\t\t\t// z-index for the blocking overlay\r\n\t\t\tbaseZ: 1000,\r\n\r\n\t\t\t// set these to true to have the message automatically centered\r\n\t\t\tcenterX: true, // <-- only effects element blocking (page block controlled via css above)\r\n\t\t\tcenterY: true,\r\n\r\n\t\t\t// allow body element to be stetched in ie6; this makes blocking look better\r\n\t\t\t// on \"short\" pages.  disable if you wish to prevent changes to the body height\r\n\t\t\tallowBodyStretch: true,\r\n\r\n\t\t\t// enable if you want key and mouse events to be disabled for content that is blocked\r\n\t\t\tbindEvents: true,\r\n\r\n\t\t\t// be default blockUI will supress tab navigation from leaving blocking content\r\n\t\t\t// (if bindEvents is true)\r\n\t\t\tconstrainTabKey: true,\r\n\r\n\t\t\t// fadeIn time in millis; set to 0 to disable fadeIn on block\r\n\t\t\tfadeIn:  200,\r\n\r\n\t\t\t// fadeOut time in millis; set to 0 to disable fadeOut on unblock\r\n\t\t\tfadeOut:  400,\r\n\r\n\t\t\t// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock\r\n\t\t\ttimeout: 0,\r\n\r\n\t\t\t// disable if you don't want to show the overlay\r\n\t\t\tshowOverlay: true,\r\n\r\n\t\t\t// if true, focus will be placed in the first available input field when\r\n\t\t\t// page blocking\r\n\t\t\tfocusInput: true,\r\n\r\n            // elements that can receive focus\r\n            focusableElements: ':input:enabled:visible',\r\n\r\n\t\t\t// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)\r\n\t\t\t// no longer needed in 2012\r\n\t\t\t// applyPlatformOpacityRules: true,\r\n\r\n\t\t\t// callback method invoked when fadeIn has completed and blocking message is visible\r\n\t\t\tonBlock: null,\r\n\r\n\t\t\t// callback method invoked when unblocking has completed; the callback is\r\n\t\t\t// passed the element that has been unblocked (which is the window object for page\r\n\t\t\t// blocks) and the options that were passed to the unblock call:\r\n\t\t\t//\tonUnblock(element, options)\r\n\t\t\tonUnblock: null,\r\n\r\n\t\t\t// callback method invoked when the overlay area is clicked.\r\n\t\t\t// setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.\r\n\t\t\tonOverlayClick: null,\r\n\r\n\t\t\t// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493\r\n\t\t\tquirksmodeOffsetHack: 4,\r\n\r\n\t\t\t// class name of the message block\r\n\t\t\tblockMsgClass: 'blockMsg',\r\n\r\n\t\t\t// if it is already blocked, then ignore it (don't unblock and reblock)\r\n\t\t\tignoreIfBlocked: false\r\n\t\t};\r\n\r\n\t\t// private data and functions follow...\r\n\r\n\t\tvar pageBlock = null;\r\n\t\tvar pageBlockEls = [];\r\n\r\n\t\tfunction install(el, opts) {\r\n\t\t\tvar css, themedCSS;\r\n\t\t\tvar full = (el == window);\r\n\t\t\tvar msg = (opts && opts.message !== undefined ? opts.message : undefined);\r\n\t\t\topts = $.extend({}, $.blockUI.defaults, opts || {});\r\n\r\n\t\t\tif (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))\r\n\t\t\t\treturn;\r\n\r\n\t\t\topts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});\r\n\t\t\tcss = $.extend({}, $.blockUI.defaults.css, opts.css || {});\r\n\t\t\tif (opts.onOverlayClick)\r\n\t\t\t\topts.overlayCSS.cursor = 'pointer';\r\n\r\n\t\t\tthemedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});\r\n\t\t\tmsg = msg === undefined ? opts.message : msg;\r\n\r\n\t\t\t// remove the current block (if there is one)\r\n\t\t\tif (full && pageBlock)\r\n\t\t\t\tremove(window, {fadeOut:0});\r\n\r\n\t\t\t// if an existing element is being used as the blocking content then we capture\r\n\t\t\t// its current place in the DOM (and current display style) so we can restore\r\n\t\t\t// it when we unblock\r\n\t\t\tif (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {\r\n\t\t\t\tvar node = msg.jquery ? msg[0] : msg;\r\n\t\t\t\tvar data = {};\r\n\t\t\t\t$(el).data('blockUI.history', data);\r\n\t\t\t\tdata.el = node;\r\n\t\t\t\tdata.parent = node.parentNode;\r\n\t\t\t\tdata.display = node.style.display;\r\n\t\t\t\tdata.position = node.style.position;\r\n\t\t\t\tif (data.parent)\r\n\t\t\t\t\tdata.parent.removeChild(node);\r\n\t\t\t}\r\n\r\n\t\t\t$(el).data('blockUI.onUnblock', opts.onUnblock);\r\n\t\t\tvar z = opts.baseZ;\r\n\r\n\t\t\t// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;\r\n\t\t\t// layer1 is the iframe layer which is used to supress bleed through of underlying content\r\n\t\t\t// layer2 is the overlay layer which has opacity and a wait cursor (by default)\r\n\t\t\t// layer3 is the message content that is displayed while blocking\r\n\t\t\tvar lyr1, lyr2, lyr3, s;\r\n\t\t\tif (msie || opts.forceIframe)\r\n\t\t\t\tlyr1 = $('<iframe class=\"blockUI\" style=\"z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0\" src=\"'+opts.iframeSrc+'\"></iframe>');\r\n\t\t\telse\r\n\t\t\t\tlyr1 = $('<div class=\"blockUI\" style=\"display:none\"></div>');\r\n\r\n\t\t\tif (opts.theme)\r\n\t\t\t\tlyr2 = $('<div class=\"blockUI blockOverlay ui-widget-overlay\" style=\"z-index:'+ (z++) +';display:none\"></div>');\r\n\t\t\telse\r\n\t\t\t\tlyr2 = $('<div class=\"blockUI blockOverlay\" style=\"z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0\"></div>');\r\n\r\n\t\t\tif (opts.theme && full) {\r\n\t\t\t\ts = '<div class=\"blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all\" style=\"z-index:'+(z+10)+';display:none;position:fixed\">';\r\n\t\t\t\tif ( opts.title ) {\r\n\t\t\t\t\ts += '<div class=\"ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle\">'+(opts.title || '&nbsp;')+'</div>';\r\n\t\t\t\t}\r\n\t\t\t\ts += '<div class=\"ui-widget-content ui-dialog-content\"></div>';\r\n\t\t\t\ts += '</div>';\r\n\t\t\t}\r\n\t\t\telse if (opts.theme) {\r\n\t\t\t\ts = '<div class=\"blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all\" style=\"z-index:'+(z+10)+';display:none;position:absolute\">';\r\n\t\t\t\tif ( opts.title ) {\r\n\t\t\t\t\ts += '<div class=\"ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle\">'+(opts.title || '&nbsp;')+'</div>';\r\n\t\t\t\t}\r\n\t\t\t\ts += '<div class=\"ui-widget-content ui-dialog-content\"></div>';\r\n\t\t\t\ts += '</div>';\r\n\t\t\t}\r\n\t\t\telse if (full) {\r\n\t\t\t\ts = '<div class=\"blockUI ' + opts.blockMsgClass + ' blockPage\" style=\"z-index:'+(z+10)+';display:none;position:fixed\"></div>';\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\ts = '<div class=\"blockUI ' + opts.blockMsgClass + ' blockElement\" style=\"z-index:'+(z+10)+';display:none;position:absolute\"></div>';\r\n\t\t\t}\r\n\t\t\tlyr3 = $(s);\r\n\r\n\t\t\t// if we have a message, style it\r\n\t\t\tif (msg) {\r\n\t\t\t\tif (opts.theme) {\r\n\t\t\t\t\tlyr3.css(themedCSS);\r\n\t\t\t\t\tlyr3.addClass('ui-widget-content');\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\tlyr3.css(css);\r\n\t\t\t}\r\n\r\n\t\t\t// style the overlay\r\n\t\t\tif (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)\r\n\t\t\t\tlyr2.css(opts.overlayCSS);\r\n\t\t\tlyr2.css('position', full ? 'fixed' : 'absolute');\r\n\r\n\t\t\t// make iframe layer transparent in IE\r\n\t\t\tif (msie || opts.forceIframe)\r\n\t\t\t\tlyr1.css('opacity',0.0);\r\n\r\n\t\t\t//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);\r\n\t\t\tvar layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);\r\n\t\t\t$.each(layers, function() {\r\n\t\t\t\tthis.appendTo($par);\r\n\t\t\t});\r\n\r\n\t\t\tif (opts.theme && opts.draggable && $.fn.draggable) {\r\n\t\t\t\tlyr3.draggable({\r\n\t\t\t\t\thandle: '.ui-dialog-titlebar',\r\n\t\t\t\t\tcancel: 'li'\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)\r\n\t\t\tvar expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);\r\n\t\t\tif (ie6 || expr) {\r\n\t\t\t\t// give body 100% height\r\n\t\t\t\tif (full && opts.allowBodyStretch && $.support.boxModel)\r\n\t\t\t\t\t$('html,body').css('height','100%');\r\n\r\n\t\t\t\t// fix ie6 issue when blocked element has a border width\r\n\t\t\t\tif ((ie6 || !$.support.boxModel) && !full) {\r\n\t\t\t\t\tvar t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');\r\n\t\t\t\t\tvar fixT = t ? '(0 - '+t+')' : 0;\r\n\t\t\t\t\tvar fixL = l ? '(0 - '+l+')' : 0;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// simulate fixed position\r\n\t\t\t\t$.each(layers, function(i,o) {\r\n\t\t\t\t\tvar s = o[0].style;\r\n\t\t\t\t\ts.position = 'absolute';\r\n\t\t\t\t\tif (i < 2) {\r\n\t\t\t\t\t\tif (full)\r\n\t\t\t\t\t\t\ts.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + \"px\"');\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\ts.setExpression('height','this.parentNode.offsetHeight + \"px\"');\r\n\t\t\t\t\t\tif (full)\r\n\t\t\t\t\t\t\ts.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + \"px\"');\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\ts.setExpression('width','this.parentNode.offsetWidth + \"px\"');\r\n\t\t\t\t\t\tif (fixL) s.setExpression('left', fixL);\r\n\t\t\t\t\t\tif (fixT) s.setExpression('top', fixT);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (opts.centerY) {\r\n\t\t\t\t\t\tif (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + \"px\"');\r\n\t\t\t\t\t\ts.marginTop = 0;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (!opts.centerY && full) {\r\n\t\t\t\t\t\tvar top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;\r\n\t\t\t\t\t\tvar expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + \"px\"';\r\n\t\t\t\t\t\ts.setExpression('top',expression);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// show the message\r\n\t\t\tif (msg) {\r\n\t\t\t\tif (opts.theme)\r\n\t\t\t\t\tlyr3.find('.ui-widget-content').append(msg);\r\n\t\t\t\telse\r\n\t\t\t\t\tlyr3.append(msg);\r\n\t\t\t\tif (msg.jquery || msg.nodeType)\r\n\t\t\t\t\t$(msg).show();\r\n\t\t\t}\r\n\r\n\t\t\tif ((msie || opts.forceIframe) && opts.showOverlay)\r\n\t\t\t\tlyr1.show(); // opacity is zero\r\n\t\t\tif (opts.fadeIn) {\r\n\t\t\t\tvar cb = opts.onBlock ? opts.onBlock : noOp;\r\n\t\t\t\tvar cb1 = (opts.showOverlay && !msg) ? cb : noOp;\r\n\t\t\t\tvar cb2 = msg ? cb : noOp;\r\n\t\t\t\tif (opts.showOverlay)\r\n\t\t\t\t\tlyr2._fadeIn(opts.fadeIn, cb1);\r\n\t\t\t\tif (msg)\r\n\t\t\t\t\tlyr3._fadeIn(opts.fadeIn, cb2);\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tif (opts.showOverlay)\r\n\t\t\t\t\tlyr2.show();\r\n\t\t\t\tif (msg)\r\n\t\t\t\t\tlyr3.show();\r\n\t\t\t\tif (opts.onBlock)\r\n\t\t\t\t\topts.onBlock.bind(lyr3)();\r\n\t\t\t}\r\n\r\n\t\t\t// bind key and mouse events\r\n\t\t\tbind(1, el, opts);\r\n\r\n\t\t\tif (full) {\r\n\t\t\t\tpageBlock = lyr3[0];\r\n\t\t\t\tpageBlockEls = $(opts.focusableElements,pageBlock);\r\n\t\t\t\tif (opts.focusInput)\r\n\t\t\t\t\tsetTimeout(focus, 20);\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t\tcenter(lyr3[0], opts.centerX, opts.centerY);\r\n\r\n\t\t\tif (opts.timeout) {\r\n\t\t\t\t// auto-unblock\r\n\t\t\t\tvar to = setTimeout(function() {\r\n\t\t\t\t\tif (full)\r\n\t\t\t\t\t\t$.unblockUI(opts);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\t$(el).unblock(opts);\r\n\t\t\t\t}, opts.timeout);\r\n\t\t\t\t$(el).data('blockUI.timeout', to);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// remove the block\r\n\t\tfunction remove(el, opts) {\r\n\t\t\tvar count;\r\n\t\t\tvar full = (el == window);\r\n\t\t\tvar $el = $(el);\r\n\t\t\tvar data = $el.data('blockUI.history');\r\n\t\t\tvar to = $el.data('blockUI.timeout');\r\n\t\t\tif (to) {\r\n\t\t\t\tclearTimeout(to);\r\n\t\t\t\t$el.removeData('blockUI.timeout');\r\n\t\t\t}\r\n\t\t\topts = $.extend({}, $.blockUI.defaults, opts || {});\r\n\t\t\tbind(0, el, opts); // unbind events\r\n\r\n\t\t\tif (opts.onUnblock === null) {\r\n\t\t\t\topts.onUnblock = $el.data('blockUI.onUnblock');\r\n\t\t\t\t$el.removeData('blockUI.onUnblock');\r\n\t\t\t}\r\n\r\n\t\t\tvar els;\r\n\t\t\tif (full) // crazy selector to handle odd field errors in ie6/7\r\n\t\t\t\tels = $('body').children().filter('.blockUI').add('body > .blockUI');\r\n\t\t\telse\r\n\t\t\t\tels = $el.find('>.blockUI');\r\n\r\n\t\t\t// fix cursor issue\r\n\t\t\tif ( opts.cursorReset ) {\r\n\t\t\t\tif ( els.length > 1 )\r\n\t\t\t\t\tels[1].style.cursor = opts.cursorReset;\r\n\t\t\t\tif ( els.length > 2 )\r\n\t\t\t\t\tels[2].style.cursor = opts.cursorReset;\r\n\t\t\t}\r\n\r\n\t\t\tif (full)\r\n\t\t\t\tpageBlock = pageBlockEls = null;\r\n\r\n\t\t\tif (opts.fadeOut) {\r\n\t\t\t\tcount = els.length;\r\n\t\t\t\tels.stop().fadeOut(opts.fadeOut, function() {\r\n\t\t\t\t\tif ( --count === 0)\r\n\t\t\t\t\t\treset(els,data,opts,el);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t\treset(els, data, opts, el);\r\n\t\t}\r\n\r\n\t\t// move blocking element back into the DOM where it started\r\n\t\tfunction reset(els,data,opts,el) {\r\n\t\t\tvar $el = $(el);\r\n\t\t\tif ( $el.data('blockUI.isBlocked') )\r\n\t\t\t\treturn;\r\n\r\n\t\t\tels.each(function(i,o) {\r\n\t\t\t\t// remove via DOM calls so we don't lose event handlers\r\n\t\t\t\tif (this.parentNode)\r\n\t\t\t\t\tthis.parentNode.removeChild(this);\r\n\t\t\t});\r\n\r\n\t\t\tif (data && data.el) {\r\n\t\t\t\tdata.el.style.display = data.display;\r\n\t\t\t\tdata.el.style.position = data.position;\r\n\t\t\t\tdata.el.style.cursor = 'default'; // #59\r\n\t\t\t\tif (data.parent)\r\n\t\t\t\t\tdata.parent.appendChild(data.el);\r\n\t\t\t\t$el.removeData('blockUI.history');\r\n\t\t\t}\r\n\r\n\t\t\tif ($el.data('blockUI.static')) {\r\n\t\t\t\t$el.css('position', 'static'); // #22\r\n\t\t\t}\r\n\r\n\t\t\tif (typeof opts.onUnblock == 'function')\r\n\t\t\t\topts.onUnblock(el,opts);\r\n\r\n\t\t\t// fix issue in Safari 6 where block artifacts remain until reflow\r\n\t\t\tvar body = $(document.body), w = body.width(), cssW = body[0].style.width;\r\n\t\t\tbody.width(w-1).width(w);\r\n\t\t\tbody[0].style.width = cssW;\r\n\t\t}\r\n\r\n\t\t// bind/unbind the handler\r\n\t\tfunction bind(b, el, opts) {\r\n\t\t\tvar full = el == window, $el = $(el);\r\n\r\n\t\t\t// don't bother unbinding if there is nothing to unbind\r\n\t\t\tif (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))\r\n\t\t\t\treturn;\r\n\r\n\t\t\t$el.data('blockUI.isBlocked', b);\r\n\r\n\t\t\t// don't bind events when overlay is not in use or if bindEvents is false\r\n\t\t\tif (!full || !opts.bindEvents || (b && !opts.showOverlay))\r\n\t\t\t\treturn;\r\n\r\n\t\t\t// bind anchors and inputs for mouse and key events\r\n\t\t\tvar events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';\r\n\t\t\tif (b)\r\n\t\t\t\t$(document).bind(events, opts, handler);\r\n\t\t\telse\r\n\t\t\t\t$(document).unbind(events, handler);\r\n\r\n\t\t// former impl...\r\n\t\t//\t\tvar $e = $('a,:input');\r\n\t\t//\t\tb ? $e.bind(events, opts, handler) : $e.unbind(events, handler);\r\n\t\t}\r\n\r\n\t\t// event handler to suppress keyboard/mouse events when blocking\r\n\t\tfunction handler(e) {\r\n\t\t\t// allow tab navigation (conditionally)\r\n\t\t\tif (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {\r\n\t\t\t\tif (pageBlock && e.data.constrainTabKey) {\r\n\t\t\t\t\tvar els = pageBlockEls;\r\n\t\t\t\t\tvar fwd = !e.shiftKey && e.target === els[els.length-1];\r\n\t\t\t\t\tvar back = e.shiftKey && e.target === els[0];\r\n\t\t\t\t\tif (fwd || back) {\r\n\t\t\t\t\t\tsetTimeout(function(){focus(back);},10);\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tvar opts = e.data;\r\n\t\t\tvar target = $(e.target);\r\n\t\t\tif (target.hasClass('blockOverlay') && opts.onOverlayClick)\r\n\t\t\t\topts.onOverlayClick(e);\r\n\r\n\t\t\t// allow events within the message content\r\n\t\t\tif (target.parents('div.' + opts.blockMsgClass).length > 0)\r\n\t\t\t\treturn true;\r\n\r\n\t\t\t// allow events for content that is not being blocked\r\n\t\t\treturn target.parents().children().filter('div.blockUI').length === 0;\r\n\t\t}\r\n\r\n\t\tfunction focus(back) {\r\n\t\t\tif (!pageBlockEls)\r\n\t\t\t\treturn;\r\n\t\t\tvar e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];\r\n\t\t\tif (e)\r\n\t\t\t\te.focus();\r\n\t\t}\r\n\r\n\t\tfunction center(el, x, y) {\r\n\t\t\tvar p = el.parentNode, s = el.style;\r\n\t\t\tvar l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');\r\n\t\t\tvar t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');\r\n\t\t\tif (x) s.left = l > 0 ? (l+'px') : '0';\r\n\t\t\tif (y) s.top  = t > 0 ? (t+'px') : '0';\r\n\t\t}\r\n\r\n\t\tfunction sz(el, p) {\r\n\t\t\treturn parseInt($.css(el,p),10)||0;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\r\n\t/*global define:true */\r\n\tif (typeof define === 'function' && define.amd && define.amd.jQuery) {\r\n\t\tdefine(['jquery'], setup);\r\n\t} else {\r\n\t\tsetup(jQuery);\r\n\t}\r\n\r\n})();"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.css",
    "content": "/*!\r\n * bootstrap-fileinput v5.5.4\r\n * http://plugins.krajee.com/file-input\r\n *\r\n * Krajee default styling for bootstrap-fileinput.\r\n *\r\n * Author: Kartik Visweswaran\r\n * Copyright: 2014 - 2022, Kartik Visweswaran, Krajee.com\r\n *\r\n * Licensed under the BSD-3-Clause\r\n * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md\r\n */\r\n\r\n.file-loading input[type=file],\r\ninput[type=file].file-loading {\r\n    width: 0;\r\n    height: 0;\r\n}\r\n\r\n.file-no-browse {\r\n    position: absolute;\r\n    left: 50%;\r\n    bottom: 20%;\r\n    width: 1px;\r\n    height: 1px;\r\n    font-size: 0;\r\n    opacity: 0;\r\n    border: none;\r\n    background: none;\r\n    outline: none;\r\n    box-shadow: none;\r\n}\r\n\r\n.kv-hidden,\r\n.file-caption-icon,\r\n.file-zoom-dialog .modal-header:before,\r\n.file-zoom-dialog .modal-header:after,\r\n.file-input-new .file-preview,\r\n.file-input-new .close,\r\n.file-input-new .glyphicon-file,\r\n.file-input-new .fileinput-remove-button,\r\n.file-input-new .fileinput-upload-button,\r\n.file-input-new .no-browse .input-group-btn,\r\n.file-input-ajax-new .fileinput-remove-button,\r\n.file-input-ajax-new .fileinput-upload-button,\r\n.file-input-ajax-new .no-browse .input-group-btn,\r\n.hide-content .kv-file-content,\r\n.is-locked .fileinput-upload-button,\r\n.is-locked .fileinput-remove-button {\r\n    display: none;\r\n}\r\n\r\n.file-caption .input-group {\r\n    align-items: center;\r\n}\r\n\r\n.btn-file input[type=file],\r\n.file-caption-icon,\r\n.file-preview .fileinput-remove,\r\n.krajee-default .file-thumb-progress,\r\n.file-zoom-dialog .btn-navigate,\r\n.file-zoom-dialog .floating-buttons {\r\n    position: absolute;\r\n}\r\n\r\n.file-caption-icon .kv-caption-icon {\r\n    line-height: inherit;\r\n}\r\n\r\n.file-input,\r\n.file-loading:before,\r\n.btn-file,\r\n.file-caption,\r\n.file-preview,\r\n.krajee-default.file-preview-frame,\r\n.krajee-default .file-thumbnail-footer,\r\n.file-zoom-dialog .modal-dialog {\r\n    position: relative;\r\n}\r\n\r\n.file-error-message pre,\r\n.file-error-message ul,\r\n.krajee-default .file-actions,\r\n.krajee-default .file-other-error {\r\n    text-align: left;\r\n}\r\n\r\n.file-error-message pre,\r\n.file-error-message ul {\r\n    margin: 0;\r\n}\r\n\r\n.krajee-default .file-drag-handle,\r\n.krajee-default .file-upload-indicator {\r\n    float: left;\r\n    margin-top: 10px;\r\n    width: 16px;\r\n    height: 16px;\r\n}\r\n\r\n.file-thumb-progress .progress,\r\n.file-thumb-progress .progress-bar {\r\n    font-family: Verdana, Helvetica, sans-serif;\r\n    font-size: 0.7rem;\r\n}\r\n\r\n.krajee-default .file-thumb-progress .progress,\r\n.kv-upload-progress .progress {\r\n    background-color: #ccc;\r\n}\r\n\r\n.krajee-default .file-caption-info,\r\n.krajee-default .file-size-info {\r\n    display: block;\r\n    white-space: nowrap;\r\n    overflow: hidden;\r\n    text-overflow: ellipsis;\r\n    width: 160px;\r\n    height: 15px;\r\n    margin: auto;\r\n}\r\n\r\n.file-zoom-content > .file-object.type-video,\r\n.file-zoom-content > .file-object.type-flash,\r\n.file-zoom-content > .file-object.type-image {\r\n    max-width: 100%;\r\n    max-height: 100%;\r\n    width: auto;\r\n}\r\n\r\n.file-zoom-content > .file-object.type-video,\r\n.file-zoom-content > .file-object.type-flash {\r\n    height: 100%;\r\n}\r\n\r\n.file-zoom-content > .file-object.type-pdf,\r\n.file-zoom-content > .file-object.type-html,\r\n.file-zoom-content > .file-object.type-text,\r\n.file-zoom-content > .file-object.type-default {\r\n    width: 100%;\r\n}\r\n\r\n.file-loading:before {\r\n    content: \" Loading...\";\r\n    display: inline-block;\r\n    padding-left: 20px;\r\n    line-height: 16px;\r\n    font-size: 13px;\r\n    font-variant: small-caps;\r\n    color: #999;\r\n    background: transparent url(loading.gif) top left no-repeat;\r\n}\r\n\r\n.file-object {\r\n    margin: 0 0 -5px 0;\r\n    padding: 0;\r\n}\r\n\r\n.btn-file {\r\n    overflow: hidden;\r\n}\r\n\r\n.btn-file input[type=file] {\r\n    top: 0;\r\n    left: 0;\r\n    min-width: 100%;\r\n    min-height: 100%;\r\n    text-align: right;\r\n    opacity: 0;\r\n    background: none repeat scroll 0 0 transparent;\r\n    cursor: inherit;\r\n    display: block;\r\n}\r\n\r\n.btn-file ::-ms-browse {\r\n    font-size: 10000px;\r\n    width: 100%;\r\n    height: 100%;\r\n}\r\n\r\n.file-caption.icon-visible .file-caption-icon {\r\n    display: inline-block;\r\n}\r\n\r\n.file-caption.icon-visible .file-caption-name {\r\n    padding-left: 25px;\r\n}\r\n\r\n.file-caption.icon-visible > .input-group-lg .file-caption-name {\r\n    padding-left: 30px;\r\n}\r\n\r\n.file-caption.icon-visible > .input-group-sm .file-caption-name {\r\n    padding-left: 22px;\r\n}\r\n\r\n.file-caption-name:not(.file-caption-disabled) {\r\n    background-color: transparent;\r\n}\r\n\r\n.file-caption-name.file-processing {\r\n    font-style: italic;\r\n    border-color: #bbb;\r\n    opacity: 0.5;\r\n}\r\n\r\n.file-caption-icon {\r\n    padding: 7px 5px;\r\n    left: 4px;\r\n}\r\n\r\n.input-group-lg .file-caption-icon {\r\n    font-size: 1.25rem;\r\n}\r\n\r\n.input-group-sm .file-caption-icon {\r\n    font-size: 0.875rem;\r\n    padding: 0.25rem;\r\n}\r\n\r\n.file-error-message {\r\n    color: #a94442;\r\n    background-color: #f2dede;\r\n    margin: 5px;\r\n    border: 1px solid #ebccd1;\r\n    border-radius: 4px;\r\n    padding: 15px;\r\n}\r\n\r\n.file-error-message pre {\r\n    margin: 5px 0;\r\n}\r\n\r\n.file-caption-disabled {\r\n    background-color: #eee;\r\n    cursor: not-allowed;\r\n    opacity: 1;\r\n}\r\n\r\n.file-preview {\r\n    border-radius: 5px;\r\n    border: 1px solid #ddd;\r\n    padding: 8px;\r\n    width: 100%;\r\n    margin-bottom: 5px;\r\n}\r\n\r\n.file-preview .btn-xs {\r\n    padding: 1px 5px;\r\n    font-size: 12px;\r\n    line-height: 1.5;\r\n    border-radius: 3px;\r\n}\r\n\r\n.file-preview .fileinput-remove {\r\n    top: 1px;\r\n    right: 1px;\r\n    line-height: 10px;\r\n}\r\n\r\n.file-preview .clickable {\r\n    cursor: pointer;\r\n}\r\n\r\n.file-preview-image {\r\n    font: 40px Impact, Charcoal, sans-serif;\r\n    color: #008000;\r\n    width: auto;\r\n    height: auto;\r\n    max-width: 100%;\r\n    max-height: 100%;\r\n}\r\n\r\n.krajee-default.file-preview-frame {\r\n    margin: 8px;\r\n    border: 1px solid rgba(0, 0, 0, 0.2);\r\n    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);\r\n    padding: 6px;\r\n    float: left;\r\n    text-align: center;\r\n\r\n}\r\n\r\n.krajee-default.file-preview-frame .kv-file-content {\r\n    width: 213px;\r\n    height: 160px;\r\n}\r\n\r\n.krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered {\r\n    width: 400px;\r\n}\r\n\r\n.krajee-default.file-preview-frame[data-template=\"audio\"] .kv-file-content {\r\n    width: 240px;\r\n    height: 55px;\r\n}\r\n\r\n.krajee-default.file-preview-frame .file-thumbnail-footer {\r\n    height: 70px;\r\n}\r\n\r\n.krajee-default.file-preview-frame:not(.file-preview-error):hover {\r\n    border: 1px solid rgba(0, 0, 0, 0.3);\r\n    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4);\r\n}\r\n\r\n.krajee-default .file-preview-text {\r\n    color: #428bca;\r\n    border: 1px solid #ddd;\r\n    outline: none;\r\n    resize: none;\r\n}\r\n\r\n.krajee-default .file-preview-html {\r\n    border: 1px solid #ddd;\r\n}\r\n\r\n.krajee-default .file-other-icon {\r\n    font-size: 6em;\r\n    line-height: 1;\r\n}\r\n\r\n.krajee-default .file-footer-buttons {\r\n    float: right;\r\n}\r\n\r\n.krajee-default .file-footer-caption {\r\n    display: block;\r\n    text-align: center;\r\n    padding-top: 4px;\r\n    font-size: 11px;\r\n    color: #999;\r\n    margin-bottom: 30px;\r\n}\r\n\r\n.file-upload-stats {\r\n    font-size: 10px;\r\n    text-align: center;\r\n    width: 100%;\r\n}\r\n\r\n.kv-upload-progress .file-upload-stats {\r\n    font-size: 12px;\r\n    margin: -10px 0 5px;\r\n}\r\n\r\n.krajee-default .file-preview-error {\r\n    opacity: 0.65;\r\n    box-shadow: none;\r\n}\r\n\r\n.krajee-default .file-thumb-progress {\r\n    top: 37px;\r\n    left: 0;\r\n    right: 0;\r\n}\r\n\r\n.krajee-default.kvsortable-ghost {\r\n    background: #e1edf7;\r\n    border: 2px solid #a1abff;\r\n}\r\n\r\n.krajee-default .file-preview-other:hover {\r\n    opacity: 0.8;\r\n}\r\n\r\n.krajee-default .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover {\r\n    color: #000;\r\n}\r\n\r\n.kv-upload-progress .progress {\r\n    height: 20px;\r\n    margin: 10px 0;\r\n    overflow: hidden;\r\n}\r\n\r\n.kv-upload-progress .progress-bar {\r\n    height: 20px;\r\n    font-family: Verdana, Helvetica, sans-serif;\r\n}\r\n\r\n\r\n/*noinspection CssOverwrittenProperties*/\r\n\r\n.file-zoom-dialog .file-other-icon {\r\n    font-size: 22em;\r\n    font-size: 50vmin;\r\n}\r\n\r\n.file-zoom-dialog .modal-dialog {\r\n    width: auto;\r\n}\r\n\r\n.file-zoom-dialog .modal-header {\r\n    display: flex;\r\n    align-items: center;\r\n    justify-content: space-between;\r\n}\r\n\r\n.file-zoom-dialog .btn-navigate {\r\n    margin: 0 0.1rem;\r\n    padding: 0;\r\n    font-size: 1.2rem;\r\n    width: 2.4rem;\r\n    height: 2.4rem;\r\n    top: 50%;\r\n    border-radius: 50%;\r\n    text-align: center;\r\n}\r\n\r\n.btn-navigate * {\r\n    width: auto;\r\n}\r\n\r\n.file-zoom-dialog .floating-buttons {\r\n    top: 5px;\r\n    right: 10px;\r\n}\r\n\r\n.file-zoom-dialog .btn-kv-prev {\r\n    left: 0;\r\n}\r\n\r\n.file-zoom-dialog .btn-kv-next {\r\n    right: 0;\r\n}\r\n\r\n.file-zoom-dialog .kv-zoom-header {\r\n    padding: 0.5rem;\r\n}\r\n\r\n.file-zoom-dialog .kv-zoom-body {\r\n    padding: 0.25rem;\r\n}\r\n\r\n.file-zoom-dialog .kv-zoom-description {\r\n    position: absolute;\r\n    opacity: 0.8;\r\n    font-size: 0.8rem;\r\n    background-color: #1a1a1a;\r\n    padding: 1rem;\r\n    text-align: center;\r\n    border-radius: 0.5rem;\r\n    color: #fff;\r\n    left: 15%;\r\n    right: 15%;\r\n    bottom: 15%;\r\n}\r\n\r\n.file-zoom-dialog .kv-desc-hide {\r\n    float: right;\r\n    color: #fff;\r\n    padding: 0 0.1rem;\r\n    background: none;\r\n    border: none;\r\n}\r\n\r\n.file-zoom-dialog .kv-desc-hide:hover {\r\n    opacity: 0.7;\r\n}\r\n\r\n.file-zoom-dialog .kv-desc-hide:focus {\r\n    opacity: 0.9;\r\n}\r\n\r\n.file-input-new .no-browse .form-control {\r\n    border-top-right-radius: 4px;\r\n    border-bottom-right-radius: 4px;\r\n}\r\n\r\n.file-input-ajax-new .no-browse .form-control {\r\n    border-top-right-radius: 4px;\r\n    border-bottom-right-radius: 4px;\r\n}\r\n\r\n.file-caption {\r\n    width: 100%;\r\n    position: relative;\r\n}\r\n\r\n.file-thumb-loading {\r\n    background: transparent url(loading.gif) no-repeat scroll center center content-box !important;\r\n}\r\n\r\n.file-drop-zone {\r\n    border: 1px dashed #aaa;\r\n    min-height: 260px;\r\n    border-radius: 4px;\r\n    text-align: center;\r\n    vertical-align: middle;\r\n    margin: 12px 15px 12px 12px;\r\n    padding: 5px;\r\n}\r\n\r\n.file-drop-zone.clickable:hover {\r\n    border: 2px dashed #999;\r\n}\r\n\r\n.file-drop-zone.clickable:focus {\r\n    border: 2px solid #5acde2;\r\n}\r\n\r\n.file-drop-zone .file-preview-thumbnails {\r\n    cursor: default;\r\n}\r\n\r\n.file-drop-zone-title {\r\n    color: #aaa;\r\n    font-size: 1.6em;\r\n    text-align: center;\r\n    padding: 85px 10px;\r\n    cursor: default;\r\n}\r\n\r\n.file-highlighted {\r\n    border: 2px dashed #999 !important;\r\n    background-color: #eee;\r\n}\r\n\r\n.file-uploading {\r\n    background: url(loading-sm.gif) no-repeat center bottom 10px;\r\n    opacity: 0.65;\r\n}\r\n\r\n.file-zoom-fullscreen .modal-dialog {\r\n    min-width: 100%;\r\n    margin: 0;\r\n}\r\n\r\n.file-zoom-fullscreen .modal-content {\r\n    border-radius: 0;\r\n    box-shadow: none;\r\n    min-height: 100vh;\r\n}\r\n\r\n.file-zoom-fullscreen .kv-zoom-body {\r\n    overflow-y: auto;\r\n}\r\n\r\n.floating-buttons {\r\n    z-index: 3000;\r\n}\r\n\r\n.floating-buttons .btn-kv {\r\n    margin-left: 3px;\r\n    z-index: 3000;\r\n}\r\n\r\n.kv-zoom-actions {\r\n    min-width: 140px;\r\n}\r\n\r\n.kv-zoom-actions .btn-kv {\r\n    margin-left: 3px;\r\n}\r\n\r\n.file-zoom-content {\r\n    text-align: center;\r\n    white-space: nowrap;\r\n    min-height: 300px;\r\n}\r\n\r\n.file-zoom-content:hover {\r\n    background: transparent;\r\n}\r\n\r\n.file-zoom-content .file-preview-image {\r\n    max-height: 100%;\r\n}\r\n\r\n.file-zoom-content .file-preview-video {\r\n    max-height: 100%;\r\n}\r\n\r\n.file-zoom-content > .file-object.type-image {\r\n    height: auto;\r\n    min-height: inherit;\r\n}\r\n\r\n.file-zoom-content > .file-object.type-audio {\r\n    width: auto;\r\n    height: 30px;\r\n}\r\n\r\n@media (min-width: 576px) {\r\n    .file-zoom-dialog .modal-dialog {\r\n        max-width: 500px;\r\n    }\r\n}\r\n\r\n@media (min-width: 992px) {\r\n    .file-zoom-dialog .modal-lg {\r\n        max-width: 800px;\r\n    }\r\n}\r\n\r\n@media (max-width: 767px) {\r\n    .file-preview-thumbnails {\r\n        display: flex;\r\n        justify-content: center;\r\n        align-items: center;\r\n        flex-direction: column;\r\n    }\r\n\r\n    .file-zoom-dialog .modal-header {\r\n        flex-direction: column;\r\n    }\r\n}\r\n\r\n@media (max-width: 350px) {\r\n    .krajee-default.file-preview-frame:not([data-template=\"audio\"]) .kv-file-content {\r\n        width: 160px;\r\n    }\r\n}\r\n\r\n@media (max-width: 420px) {\r\n    .krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered {\r\n        width: 100%;\r\n    }\r\n}\r\n\r\n.file-loading[dir=rtl]:before {\r\n    background: transparent url(loading.gif) top right no-repeat;\r\n    padding-left: 0;\r\n    padding-right: 20px;\r\n}\r\n\r\n.clickable .file-drop-zone-title {\r\n    cursor: pointer;\r\n}\r\n\r\n.file-sortable .file-drag-handle:hover {\r\n    opacity: 0.7;\r\n}\r\n\r\n.file-sortable .file-drag-handle {\r\n    cursor: grab;\r\n    opacity: 1;\r\n}\r\n\r\n.file-grabbing,\r\n.file-grabbing * {\r\n    cursor: not-allowed !important;\r\n}\r\n\r\n.file-grabbing .file-preview-thumbnails * {\r\n    cursor: grabbing !important;\r\n}\r\n\r\n.file-preview-frame.sortable-chosen {\r\n    background-color: #d9edf7;\r\n    border-color: #17a2b8;\r\n    box-shadow: none !important;\r\n}\r\n\r\n.file-preview .kv-zoom-cache {\r\n    display: none;\r\n}\r\n\r\n.file-preview-other-frame, .file-preview-object, .kv-file-content, .kv-zoom-body {\r\n    display: flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n}\r\n\r\n.btn-kv-rotate,\r\n.kv-file-rotate {\r\n    display: none;\r\n}\r\n\r\n.rotatable:not(.hide-rotate) .btn-kv-rotate,\r\n.rotatable:not(.hide-rotate) .kv-file-rotate {\r\n    display: inline-block;\r\n}\r\n\r\n.rotatable .file-zoom-detail,\r\n.rotatable .kv-file-content,\r\n.rotatable .kv-file-content > :first-child {\r\n    transform-origin: center center;\r\n}\r\n\r\n.rotate-animate {\r\n    transition: transform 0.3s ease;\r\n}\r\n\r\n.kv-overflow-hidden {\r\n    overflow: hidden;\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.js",
    "content": "/*!\n * bootstrap-fileinput v5.5.4\n * http://plugins.krajee.com/file-input\n *\n * Author: Kartik Visweswaran\n * Copyright: 2014 - 2024, Kartik Visweswaran, Krajee.com\n *\n * Licensed under the BSD-3-Clause\n * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md\n */\n(function (factory) {\n  \"use strict\";\n  if (typeof define === \"function\" && define.amd) {\n    define([\"jquery\"], factory);\n  } else if (typeof module === \"object\" && typeof module.exports === \"object\") {\n    factory(require(\"jquery\"));\n  } else {\n    factory(window.jQuery);\n  }\n})(function ($) {\n  \"use strict\";\n\n  $.fn.fileinputLocales = {};\n  $.fn.fileinputThemes = {};\n\n  if (!$.fn.fileinputBsVersion) {\n    $.fn.fileinputBsVersion =\n      (window.bootstrap && window.bootstrap.Alert && window.bootstrap.Alert.VERSION) ||\n      (window.Alert && window.Alert.VERSION) ||\n      \"3.x.x\";\n  }\n\n  String.prototype.setTokens = function (replacePairs) {\n    var str = this.toString(),\n      key,\n      re;\n    for (key in replacePairs) {\n      if (replacePairs.hasOwnProperty(key)) {\n        re = new RegExp(\"{\" + key + \"}\", \"g\");\n        str = str.replace(re, replacePairs[key]);\n      }\n    }\n    return str;\n  };\n\n  if (!Array.prototype.flatMap) {\n    // polyfill flatMap\n    Array.prototype.flatMap = function (lambda) {\n      return [].concat(this.map(lambda));\n    };\n  }\n\n  var $h, FileInput;\n\n  // fileinput helper object for all global variables and internal helper methods\n  $h = {\n    FRAMES: \".kv-preview-thumb\",\n    SORT_CSS: \"file-sortable\",\n    INIT_FLAG: \"init-\",\n    SCRIPT_SRC: (document && document.currentScript && document.currentScript.src) || null,\n    OBJECT_PARAMS:\n      '<param name=\"controller\" value=\"true\" />\\n' +\n      '<param name=\"allowFullScreen\" value=\"true\" />\\n' +\n      '<param name=\"allowScriptAccess\" value=\"always\" />\\n' +\n      '<param name=\"autoPlay\" value=\"false\" />\\n' +\n      '<param name=\"autoStart\" value=\"false\" />\\n' +\n      '<param name=\"quality\" value=\"high\" />\\n',\n    DEFAULT_PREVIEW:\n      '<div class=\"file-preview-other\">\\n' +\n      '<span class=\"{previewFileIconClass}\">{previewFileIcon}</span>\\n' +\n      \"</div>\",\n    MODAL_ID: \"kvFileinputModal\",\n    MODAL_EVENTS: [\"show\", \"shown\", \"hide\", \"hidden\", \"loaded\"],\n    logMessages: {\n      ajaxError: \"{status}: {error}. Error Details: {text}.\",\n      badDroppedFiles: \"Error scanning dropped files!\",\n      badExifParser: \"Error loading the piexif.js library. {details}\",\n      badInputType: 'The input \"type\" must be set to \"file\" for initializing the \"bootstrap-fileinput\" plugin.',\n      exifWarning:\n        'To avoid this warning, either set \"autoOrientImage\" to \"false\" OR ensure you have loaded ' +\n        'the \"piexif.js\" library correctly on your page before the \"fileinput.js\" script.',\n      invalidChunkSize: 'Invalid upload chunk size: \"{chunkSize}\". Resumable uploads are disabled.',\n      invalidThumb: 'Invalid thumb frame with id: \"{id}\".',\n      noResumableSupport: \"The browser does not support resumable or chunk uploads.\",\n      noUploadUrl: 'The \"uploadUrl\" is not set. Ajax uploads and resumable uploads have been disabled.',\n      retryStatus: \"Retrying upload for chunk # {chunk} for {filename}... retry # {retry}.\",\n      chunkQueueError: \"Could not push task to ajax pool for chunk index # {index}.\",\n      resumableMaxRetriesReached: \"Maximum resumable ajax retries ({n}) reached.\",\n      resumableRetryError: \"Could not retry the resumable request (try # {n})... aborting.\",\n      resumableAborting: \"Aborting / cancelling the resumable request.\",\n      resumableRequestError: \"Error processing resumable request. {msg}\",\n    },\n    objUrl: window.URL || window.webkitURL,\n    getZoomPlaceholder: function () {\n      // used to prevent 404 errors in URL parsing\n      var src = $h.SCRIPT_SRC,\n        srcPath,\n        zoomVar = \"?kvTemp__2873389129__=\";\n      if (!src) {\n        return zoomVar;\n      }\n      srcPath = src.substring(0, src.lastIndexOf(\"/\"));\n      return srcPath.substring(0, srcPath.lastIndexOf(\"/\") + 1) + \"img/loading.gif\" + zoomVar;\n    },\n    defaultButtonCss: function (fill) {\n      return \"btn-default btn-\" + (fill ? \"\" : \"outline-\") + \"secondary\";\n    },\n    isBs: function (ver) {\n      var chk = $h.trim(($.fn.fileinputBsVersion || \"\") + \"\");\n      ver = parseInt(ver, 10);\n      if (!chk) {\n        return ver === 4;\n      }\n      return ver === parseInt(chk.charAt(0), 10);\n    },\n    isNumeric: function (n) {\n      if (n === undefined) {\n        return false;\n      }\n      return !isNaN(parseFloat(n)) && isFinite(n);\n    },\n    trim: function (val) {\n      if (val === undefined) {\n        return \"\";\n      }\n      return val.toString().trim();\n    },\n    now: function () {\n      return new Date().getTime();\n    },\n    round: function (num) {\n      num = parseFloat(num);\n      return isNaN(num) ? 0 : Math.floor(Math.round(num));\n    },\n    getArray: function (obj) {\n      var i,\n        arr = [],\n        len = (obj && obj.length) || 0;\n      for (i = 0; i < len; i++) {\n        arr.push(obj[i]);\n      }\n      return arr;\n    },\n    getFileRelativePath: function (file) {\n      /** @namespace file.relativePath */\n      /** @namespace file.webkitRelativePath */\n      return String(file.newPath || file.relativePath || file.webkitRelativePath || $h.getFileName(file) || null);\n    },\n    getFileId: function (file, generateFileId) {\n      var relativePath = $h.getFileRelativePath(file);\n      if (typeof generateFileId === \"function\") {\n        return generateFileId(file);\n      }\n      if (!file) {\n        return null;\n      }\n      if (!relativePath) {\n        return null;\n      }\n      return file.size + \"_\" + encodeURIComponent(relativePath).replace(/%/g, \"_\");\n    },\n    getFrameSelector: function (id, selector) {\n      selector = selector || \"\";\n      return '[id=\"' + id + '\"]' + selector;\n    },\n    getZoomSelector: function (id, selector) {\n      return $h.getFrameSelector(\"zoom-\" + id, selector);\n    },\n    getFrameElement: function ($element, id, selector) {\n      return $element.find($h.getFrameSelector(id, selector));\n    },\n    getZoomElement: function ($element, id, selector) {\n      return $element.find($h.getZoomSelector(id, selector));\n    },\n    getElapsed: function (seconds) {\n      var delta = seconds,\n        out = \"\",\n        result = {},\n        structure = {\n          year: 31536000,\n          month: 2592000,\n          week: 604800, // uncomment row to ignore\n          day: 86400, // feel free to add your own row\n          hour: 3600,\n          minute: 60,\n          second: 1,\n        };\n      $h.getObjectKeys(structure).forEach(function (key) {\n        result[key] = Math.floor(delta / structure[key]);\n        delta -= result[key] * structure[key];\n      });\n      $.each(result, function (key, value) {\n        if (value > 0) {\n          out += (out ? \" \" : \"\") + value + key.substring(0, 1);\n        }\n      });\n      return out;\n    },\n    debounce: function (func, delay) {\n      var inDebounce;\n      return function () {\n        var args = arguments,\n          context = this;\n        clearTimeout(inDebounce);\n        inDebounce = setTimeout(function () {\n          func.apply(context, args);\n        }, delay);\n      };\n    },\n    stopEvent: function (e) {\n      e.stopPropagation();\n      e.preventDefault();\n    },\n    getFileName: function (file) {\n      /** @namespace file.fileName */\n      return file ? file.fileName || file.name || \"\" : \"\"; // some confusion in different versions of Firefox\n    },\n    createObjectURL: function (data) {\n      if ($h.objUrl && $h.objUrl.createObjectURL && data) {\n        return $h.objUrl.createObjectURL(data);\n      }\n      return \"\";\n    },\n    revokeObjectURL: function (data) {\n      if ($h.objUrl && $h.objUrl.revokeObjectURL && data) {\n        $h.objUrl.revokeObjectURL(data);\n      }\n    },\n    compare: function (input, str, exact) {\n      return input !== undefined && (exact ? input === str : input.match(str));\n    },\n    isIE: function (ver) {\n      var div, status;\n      // check for IE versions < 11\n      if (navigator.appName !== \"Microsoft Internet Explorer\") {\n        return false;\n      }\n      if (ver === 10) {\n        return new RegExp(\"msie\\\\s\" + ver, \"i\").test(navigator.userAgent);\n      }\n      div = document.createElement(\"div\");\n      div.innerHTML = \"<!--[if IE \" + ver + \"]> <i></i> <![endif]-->\";\n      status = div.getElementsByTagName(\"i\").length;\n      document.body.appendChild(div);\n      div.parentNode.removeChild(div);\n      return status;\n    },\n    canOrientImage: function ($el) {\n      var $img = $(document.createElement(\"img\")).css({ width: \"1px\", height: \"1px\" }).insertAfter($el),\n        flag = $img.css(\"image-orientation\");\n      $img.remove();\n      return !!flag;\n    },\n    canAssignFilesToInput: function () {\n      var input = document.createElement(\"input\");\n      try {\n        input.type = \"file\";\n        input.files = null;\n        return true;\n      } catch (err) {\n        return false;\n      }\n    },\n    getDragDropFolders: function (items) {\n      var i,\n        item,\n        len = items ? items.length : 0,\n        folders = 0;\n      if (len > 0 && items[0].webkitGetAsEntry()) {\n        for (i = 0; i < len; i++) {\n          item = items[i].webkitGetAsEntry();\n          if (item && item.isDirectory) {\n            folders++;\n          }\n        }\n      }\n      return folders;\n    },\n    initModal: function ($modal) {\n      var $body = $(\"body\");\n      if ($body.length) {\n        $modal.appendTo($body);\n      }\n    },\n    isFunction: function (v) {\n      return typeof v === \"function\";\n    },\n    isEmpty: function (value, trim) {\n      if (value === undefined || value === null || value === \"\") {\n        return true;\n      }\n      if ($h.isString(value) && trim) {\n        return $h.trim(value) === \"\";\n      }\n      if ($h.isArray(value)) {\n        return value.length === 0;\n      }\n      if ($.isPlainObject(value) && $.isEmptyObject(value)) {\n        return true;\n      }\n      return false;\n    },\n    isArray: function (a) {\n      return Array.isArray(a) || Object.prototype.toString.call(a) === \"[object Array]\";\n    },\n    isString: function (a) {\n      return Object.prototype.toString.call(a) === \"[object String]\";\n    },\n    ifSet: function (needle, haystack, def) {\n      def = def || \"\";\n      return haystack && typeof haystack === \"object\" && needle in haystack ? haystack[needle] : def;\n    },\n    cleanArray: function (arr) {\n      if (!(arr instanceof Array)) {\n        arr = [];\n      }\n      return arr.filter(function (e) {\n        return e !== undefined && e !== null;\n      });\n    },\n    spliceArray: function (arr, index, reverseOrder) {\n      var i,\n        j = 0,\n        out = [],\n        newArr;\n      if (!(arr instanceof Array)) {\n        return [];\n      }\n      newArr = $.extend(true, [], arr);\n      if (reverseOrder) {\n        newArr.reverse();\n      }\n      for (i = 0; i < newArr.length; i++) {\n        if (i !== index) {\n          out[j] = newArr[i];\n          j++;\n        }\n      }\n      if (reverseOrder) {\n        out.reverse();\n      }\n      return out;\n    },\n    getNum: function (num, def) {\n      def = def || 0;\n      if (typeof num === \"number\") {\n        return num;\n      }\n      if (typeof num === \"string\") {\n        num = parseFloat(num);\n      }\n      return isNaN(num) ? def : num;\n    },\n    hasFileAPISupport: function () {\n      return !!(window.File && window.FileReader);\n    },\n    hasDragDropSupport: function () {\n      var div = document.createElement(\"div\");\n      /** @namespace div.draggable */\n      /** @namespace div.ondragstart */\n      /** @namespace div.ondrop */\n      return (\n        !$h.isIE(9) && (div.draggable !== undefined || (div.ondragstart !== undefined && div.ondrop !== undefined))\n      );\n    },\n    hasFileUploadSupport: function () {\n      return $h.hasFileAPISupport() && window.FormData;\n    },\n    hasBlobSupport: function () {\n      try {\n        return !!window.Blob && Boolean(new Blob());\n      } catch (e) {\n        return false;\n      }\n    },\n    hasArrayBufferViewSupport: function () {\n      try {\n        return new Blob([new Uint8Array(100)]).size === 100;\n      } catch (e) {\n        return false;\n      }\n    },\n    hasResumableUploadSupport: function () {\n      /** @namespace Blob.prototype.webkitSlice */\n      /** @namespace Blob.prototype.mozSlice */\n      return (\n        $h.hasFileUploadSupport() &&\n        $h.hasBlobSupport() &&\n        $h.hasArrayBufferViewSupport() &&\n        (!!Blob.prototype.webkitSlice || !!Blob.prototype.mozSlice || !!Blob.prototype.slice || false)\n      );\n    },\n    dataURI2Blob: function (dataURI) {\n      var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder,\n        canBlob = $h.hasBlobSupport(),\n        byteStr,\n        arrayBuffer,\n        intArray,\n        i,\n        mimeStr,\n        bb,\n        canProceed = (canBlob || BlobBuilder) && window.atob && window.ArrayBuffer && window.Uint8Array;\n      if (!canProceed) {\n        return null;\n      }\n      if (dataURI.split(\",\")[0].indexOf(\"base64\") >= 0) {\n        byteStr = atob(dataURI.split(\",\")[1]);\n      } else {\n        byteStr = decodeURIComponent(dataURI.split(\",\")[1]);\n      }\n      arrayBuffer = new ArrayBuffer(byteStr.length);\n      intArray = new Uint8Array(arrayBuffer);\n      for (i = 0; i < byteStr.length; i += 1) {\n        intArray[i] = byteStr.charCodeAt(i);\n      }\n      mimeStr = dataURI.split(\",\")[0].split(\":\")[1].split(\";\")[0];\n      if (canBlob) {\n        return new Blob([$h.hasArrayBufferViewSupport() ? intArray : arrayBuffer], { type: mimeStr });\n      }\n      bb = new BlobBuilder();\n      bb.append(arrayBuffer);\n      return bb.getBlob(mimeStr);\n    },\n    arrayBuffer2String: function (buffer) {\n      if (window.TextDecoder) {\n        return new TextDecoder(\"utf-8\").decode(buffer);\n      }\n      var array = Array.prototype.slice.apply(new Uint8Array(buffer)),\n        out = \"\",\n        i = 0,\n        len,\n        c,\n        char2,\n        char3;\n      len = array.length;\n      while (i < len) {\n        c = array[i++];\n        switch (\n          c >> 4 // jshint ignore:line\n        ) {\n          case 0:\n          case 1:\n          case 2:\n          case 3:\n          case 4:\n          case 5:\n          case 6:\n          case 7:\n            // 0xxxxxxx\n            out += String.fromCharCode(c);\n            break;\n          case 12:\n          case 13:\n            // 110x xxxx   10xx xxxx\n            char2 = array[i++];\n            out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f)); // jshint ignore:line\n            break;\n          case 14:\n            // 1110 xxxx  10xx xxxx  10xx xxxx\n            char2 = array[i++];\n            char3 = array[i++];\n            out += String.fromCharCode(\n              ((c & 0x0f) << 12) | // jshint ignore:line\n                ((char2 & 0x3f) << 6) | // jshint ignore:line\n                ((char3 & 0x3f) << 0)\n            ); // jshint ignore:line\n            break;\n        }\n      }\n      return out;\n    },\n    isSvg: function (str) {\n      if ($h.isEmpty(str)) {\n        return false;\n      }\n      str = $h.trim(str).replace(/\\n/g, \" \");\n      if (str.length === 0) {\n        return false;\n      }\n      return str.match(/^\\s*<\\?xml/i) && (str.match(/<!DOCTYPE svg/i) || str.match(/<svg/i));\n    },\n    getMimeType: function (sign, contents, type) {\n      var signature = sign || \"\";\n      switch (signature) {\n        case \"ffd8ffe0\":\n        case \"ffd8ffe1\":\n        case \"ffd8ffe2\":\n          return \"image/jpeg\";\n        case \"89504e47\":\n          return \"image/png\";\n        case \"47494638\":\n          return \"image/gif\";\n        case \"49492a00\":\n          return \"image/tiff\";\n        case \"52494646\":\n          return \"image/webp\";\n        case \"41433130\":\n          return \"image/vnd.dwg\";\n        case \"66747970\":\n          return \"video/3gp\";\n        case \"4f676753\":\n          return \"video/ogg\";\n        case \"1a45dfa3\":\n          return \"video/mkv\";\n        case \"000001ba\":\n        case \"000001b3\":\n          return \"video/mpeg\";\n        case \"3026b275\":\n          return \"video/wmv\";\n        case \"25504446\":\n          return \"application/pdf\";\n        case \"25215053\":\n          return \"application/ps\";\n        case \"504b0304\":\n        case \"504b0506\":\n        case \"504b0508\":\n          return \"application/zip\";\n        case \"377abcaf\":\n          return \"application/7z\";\n        case \"75737461\":\n          return \"application/tar\";\n        case \"7801730d\":\n          return \"application/dmg\";\n        default:\n          switch (signature.substring(0, 6)) {\n            case \"435753\":\n              return \"application/x-shockwave-flash\";\n            case \"494433\":\n              return \"audio/mp3\";\n            case \"425a68\":\n              return \"application/bzip\";\n            default:\n              switch (signature.substring(0, 4)) {\n                case \"424d\":\n                  return \"image/bmp\";\n                case \"fffb\":\n                  return \"audio/mp3\";\n                case \"4d5a\":\n                  return \"application/exe\";\n                case \"1f9d\":\n                case \"1fa0\":\n                  return \"application/zip\";\n                case \"1f8b\":\n                  return \"application/gzip\";\n                default:\n                  return contents && !contents.match(/[^\\u0000-\\u007f]/) ? \"application/text-plain\" : type;\n              }\n          }\n      }\n    },\n    addCss: function ($el, css) {\n      $el.removeClass(css).addClass(css);\n    },\n    getElement: function (options, param, value) {\n      return $h.isEmpty(options) || $h.isEmpty(options[param]) ? value : $(options[param]);\n    },\n    createDiv: function () {\n      return $(document.createElement(\"div\"));\n    },\n    createElement: function (str, tag) {\n      tag = tag || \"div\";\n      return $($.parseHTML(\"<\" + tag + \">\" + str + \"</\" + tag + \">\"));\n    },\n    uniqId: function () {\n      return (new Date().getTime() + Math.floor(Math.random() * Math.pow(10, 15))).toString(36);\n    },\n    cspBuffer: {\n      CSP_ATTRIB: \"data-csp-01928735\", // a randomly named temporary attribute to store the CSP elem id\n      domElementsStyles: {},\n      stash: function (htmlString) {\n        var self = this,\n          outerDom = $.parseHTML(\"<div>\" + htmlString + \"</div>\"),\n          $el = $(outerDom);\n        $el.find(\"[style]\").each(function (key, elem) {\n          var $elem = $(elem),\n            styleDeclaration = $elem[0].style,\n            id = $h.uniqId(),\n            styles = {};\n          if (styleDeclaration && styleDeclaration.length) {\n            $(styleDeclaration).each(function () {\n              styles[this] = styleDeclaration[this];\n            });\n            self.domElementsStyles[id] = styles;\n            $elem.removeAttr(\"style\").attr(self.CSP_ATTRIB, id);\n          }\n        });\n        $el.filter(\"*\").removeAttr(\"style\"); // make sure all style attr are removed\n        var values = Object.values\n          ? Object.values(outerDom)\n          : Object.keys(outerDom).map(function (itm) {\n              return outerDom[itm];\n            });\n        return values\n          .flatMap(function (elem) {\n            return elem.innerHTML;\n          })\n          .join(\"\");\n      },\n      apply: function (domElement) {\n        var self = this,\n          $el = $(domElement);\n        $el.find(\"[\" + self.CSP_ATTRIB + \"]\").each(function (key, elem) {\n          var $elem = $(elem),\n            id = $elem.attr(self.CSP_ATTRIB),\n            styles = self.domElementsStyles[id];\n          if (styles) {\n            $elem.css(styles);\n          }\n          $elem.removeAttr(self.CSP_ATTRIB);\n        });\n        self.domElementsStyles = {};\n      },\n    },\n    setHtml: function ($elem, htmlString) {\n      var buf = $h.cspBuffer;\n      $elem.html(buf.stash(htmlString));\n      buf.apply($elem);\n      return $elem;\n    },\n    htmlEncode: function (str, undefVal) {\n      if (str === undefined) {\n        return undefVal || null;\n      }\n      return str\n        .replace(/&/g, \"&amp;\")\n        .replace(/</g, \"&lt;\")\n        .replace(/>/g, \"&gt;\")\n        .replace(/\"/g, \"&quot;\")\n        .replace(/'/g, \"&apos;\");\n    },\n    replaceTags: function (str, tags) {\n      var out = str;\n      if (!tags) {\n        return out;\n      }\n      $.each(tags, function (key, value) {\n        if (typeof value === \"function\") {\n          value = value();\n        }\n        out = out.split(key).join(value);\n      });\n      return out;\n    },\n    cleanMemory: function ($thumb) {\n      var data = $thumb.is(\"img\") ? $thumb.attr(\"src\") : $thumb.find(\"source\").attr(\"src\");\n      $h.revokeObjectURL(data);\n    },\n    findFileName: function (filePath) {\n      var sepIndex = filePath.lastIndexOf(\"/\");\n      if (sepIndex === -1) {\n        sepIndex = filePath.lastIndexOf(\"\\\\\");\n      }\n      return filePath.split(filePath.substring(sepIndex, sepIndex + 1)).pop();\n    },\n    checkFullScreen: function () {\n      return (\n        document.fullscreenElement ||\n        document.mozFullScreenElement ||\n        document.webkitFullscreenElement ||\n        document.msFullscreenElement\n      );\n    },\n    toggleFullScreen: function (maximize) {\n      var doc = document,\n        de = doc.documentElement,\n        isFullScreen = $h.checkFullScreen();\n      if (de && maximize && !isFullScreen) {\n        if (de.requestFullscreen) {\n          de.requestFullscreen();\n        } else {\n          if (de.msRequestFullscreen) {\n            de.msRequestFullscreen();\n          } else {\n            if (de.mozRequestFullScreen) {\n              de.mozRequestFullScreen();\n            } else {\n              if (de.webkitRequestFullscreen) {\n                de.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);\n              }\n            }\n          }\n        }\n      } else {\n        if (isFullScreen) {\n          if (doc.exitFullscreen) {\n            doc.exitFullscreen();\n          } else {\n            if (doc.msExitFullscreen) {\n              doc.msExitFullscreen();\n            } else {\n              if (doc.mozCancelFullScreen) {\n                doc.mozCancelFullScreen();\n              } else {\n                if (doc.webkitExitFullscreen) {\n                  doc.webkitExitFullscreen();\n                }\n              }\n            }\n          }\n        }\n      }\n    },\n    moveArray: function (arr, oldIndex, newIndex, reverseOrder) {\n      var newArr = $.extend(true, [], arr);\n      if (reverseOrder) {\n        newArr.reverse();\n      }\n      if (newIndex >= newArr.length) {\n        var k = newIndex - newArr.length;\n        while (k-- + 1) {\n          newArr.push(undefined);\n        }\n      }\n      newArr.splice(newIndex, 0, newArr.splice(oldIndex, 1)[0]);\n      if (reverseOrder) {\n        newArr.reverse();\n      }\n      return newArr;\n    },\n    closeButton: function (css) {\n      css = ($h.isBs(5) ? \"btn-close\" : \"close\") + (css ? \" \" + css : \"\");\n      return (\n        '<button type=\"button\" class=\"' +\n        css +\n        '\" aria-label=\"Close\">\\n' +\n        ($h.isBs(5) ? \"\" : '  <span aria-hidden=\"true\">&times;</span>\\n') +\n        \"</button>\"\n      );\n    },\n    getRotation: function (value) {\n      switch (value) {\n        case 2:\n          return \"rotateY(180deg)\";\n        case 3:\n          return \"rotate(180deg)\";\n        case 4:\n          return \"rotate(180deg) rotateY(180deg)\";\n        case 5:\n          return \"rotate(270deg) rotateY(180deg)\";\n        case 6:\n          return \"rotate(90deg)\";\n        case 7:\n          return \"rotate(90deg) rotateY(180deg)\";\n        case 8:\n          return \"rotate(270deg)\";\n        default:\n          return \"\";\n      }\n    },\n    setTransform: function (el, val) {\n      if (!el) {\n        return;\n      }\n      el.style.transform = val;\n      el.style.webkitTransform = val;\n      el.style[\"-moz-transform\"] = val;\n      el.style[\"-ms-transform\"] = val;\n      el.style[\"-o-transform\"] = val;\n    },\n    getObjectKeys: function (obj) {\n      var keys = [];\n      if (obj) {\n        $.each(obj, function (key) {\n          keys.push(key);\n        });\n      }\n      return keys;\n    },\n    getObjectSize: function (obj) {\n      return $h.getObjectKeys(obj).length;\n    },\n    /**\n     * Small dependency injection for the task manager\n     * https://gist.github.com/fearphage/4341799\n     */\n    whenAll: function (array) {\n      var s = [].slice,\n        resolveValues = arguments.length === 1 && $h.isArray(array) ? array : s.call(arguments),\n        deferred = $.Deferred(),\n        i,\n        failed = 0,\n        value,\n        length = resolveValues.length,\n        remaining = length,\n        rejectContexts,\n        rejectValues,\n        resolveContexts,\n        updateFunc;\n      rejectContexts = rejectValues = resolveContexts = Array(length);\n      updateFunc = function (index, contexts, values) {\n        return function () {\n          if (values !== resolveValues) {\n            failed++;\n          }\n          deferred.notifyWith((contexts[index] = this), (values[index] = s.call(arguments)));\n          if (!--remaining) {\n            deferred[(!failed ? \"resolve\" : \"reject\") + \"With\"](contexts, values);\n          }\n        };\n      };\n      for (i = 0; i < length; i++) {\n        if ((value = resolveValues[i]) && $h.isFunction(value.promise)) {\n          value\n            .promise()\n            .done(updateFunc(i, resolveContexts, resolveValues))\n            .fail(updateFunc(i, rejectContexts, rejectValues));\n        } else {\n          deferred.notifyWith(this, value);\n          --remaining;\n        }\n      }\n      if (!remaining) {\n        deferred.resolveWith(resolveContexts, resolveValues);\n      }\n      return deferred.promise();\n    },\n  };\n  FileInput = function (element, options) {\n    var self = this;\n    self.$element = $(element);\n    self.$parent = self.$element.parent();\n    if (!self._validate()) {\n      return;\n    }\n    self.isPreviewable = $h.hasFileAPISupport();\n    self.isIE9 = $h.isIE(9);\n    self.isIE10 = $h.isIE(10);\n    if (self.isPreviewable || self.isIE9) {\n      self._init(options);\n      self._listen();\n    }\n    self.$element.removeClass(\"file-loading\");\n  };\n\n  FileInput.prototype = {\n    constructor: FileInput,\n    _cleanup: function () {\n      var self = this;\n      self.reader = null;\n      self.clearFileStack();\n      self.fileBatchCompleted = true;\n      self.isError = false;\n      self.isDuplicateError = false;\n      self.isPersistentError = false;\n      self.cancelling = false;\n      self.paused = false;\n      self.lastProgress = 0;\n      self._initAjax();\n    },\n    _isAborted: function () {\n      var self = this;\n      return self.cancelling || self.paused;\n    },\n    _initAjax: function () {\n      var self = this,\n        tm = (self.taskManager = {\n          pool: {},\n          addPool: function (id) {\n            return (tm.pool[id] = new tm.TasksPool(id));\n          },\n          getPool: function (id) {\n            return tm.pool[id];\n          },\n          addTask: function (id, logic) {\n            // add standalone task directly from task manager\n            return new tm.Task(id, logic);\n          },\n          TasksPool: function (id) {\n            var tp = this;\n            tp.id = id;\n            tp.cancelled = false;\n            tp.cancelledDeferrer = $.Deferred();\n            tp.tasks = {};\n            tp.addTask = function (id, logic) {\n              return (tp.tasks[id] = new tm.Task(id, logic));\n            };\n            tp.size = function () {\n              return $h.getObjectSize(tp.tasks);\n            };\n            tp.run = function (maxThreads) {\n              var i = 0,\n                failed = false,\n                task,\n                tasksList = $h.getObjectKeys(tp.tasks).map(function (key) {\n                  return tp.tasks[key];\n                }),\n                tasksDone = [],\n                deferred = $.Deferred(),\n                enqueue,\n                callback;\n\n              if (tp.cancelled) {\n                tp.cancelledDeferrer.resolve();\n                return deferred.reject();\n              }\n              // if run all at once\n              if (!maxThreads) {\n                var tasksDeferredList = $h.getObjectKeys(tp.tasks).map(function (key) {\n                  return tp.tasks[key].deferred;\n                });\n                // when all are done\n                $h.whenAll(tasksDeferredList)\n                  .done(function () {\n                    var argv = $h.getArray(arguments);\n                    if (!tp.cancelled) {\n                      deferred.resolve.apply(null, argv);\n                      tp.cancelledDeferrer.reject();\n                    } else {\n                      deferred.reject.apply(null, argv);\n                      tp.cancelledDeferrer.resolve();\n                    }\n                  })\n                  .fail(function () {\n                    var argv = $h.getArray(arguments);\n                    deferred.reject.apply(null, argv);\n                    if (!tp.cancelled) {\n                      tp.cancelledDeferrer.reject();\n                    } else {\n                      tp.cancelledDeferrer.resolve();\n                    }\n                  });\n                // run all tasks\n                $.each(tp.tasks, function (id) {\n                  task = tp.tasks[id];\n                  task.run();\n                });\n                return deferred;\n              }\n              enqueue = function (task) {\n                $.when(task.deferred)\n                  .fail(function () {\n                    failed = true;\n                    callback.apply(null, arguments);\n                  })\n                  .always(callback);\n              };\n              callback = function () {\n                var argv = $h.getArray(arguments);\n                // notify a task just ended\n                deferred.notify(argv);\n                tasksDone.push(argv);\n                if (tp.cancelled) {\n                  deferred.reject.apply(null, tasksDone);\n                  tp.cancelledDeferrer.resolve();\n                  return;\n                }\n                if (tasksDone.length === tp.size()) {\n                  if (failed) {\n                    deferred.reject.apply(null, tasksDone);\n                  } else {\n                    deferred.resolve.apply(null, tasksDone);\n                  }\n                }\n                // if there are any tasks remaining\n                if (tasksList.length) {\n                  task = tasksList.shift();\n                  enqueue(task);\n                  task.run();\n                }\n              };\n              // run the first \"maxThreads\" tasks\n              while (tasksList.length && i++ < maxThreads) {\n                task = tasksList.shift();\n                enqueue(task);\n                task.run();\n              }\n              return deferred;\n            };\n            tp.cancel = function () {\n              tp.cancelled = true;\n              return tp.cancelledDeferrer;\n            };\n          },\n          Task: function (id, logic) {\n            var tk = this;\n            tk.id = id;\n            tk.deferred = $.Deferred();\n            tk.logic = logic;\n            tk.context = null;\n            tk.run = function () {\n              var argv = $h.getArray(arguments);\n              argv.unshift(tk.deferred); // add deferrer as first argument\n              logic.apply(tk.context, argv); // run task\n              return tk.deferred; // return deferrer\n            };\n            tk.runWithContext = function (context) {\n              tk.context = context;\n              return tk.run();\n            };\n          },\n        });\n      self.ajaxQueue = [];\n      self.ajaxRequests = [];\n      self.ajaxPool = null;\n      self.ajaxAborted = false;\n    },\n    _init: function (options, refreshMode) {\n      var self = this,\n        f,\n        $el = self.$element,\n        $cont,\n        t,\n        tmp;\n      self.options = options;\n      self.zoomPlaceholder = $h.getZoomPlaceholder();\n      self.canOrientImage = $h.canOrientImage($el);\n      $.each(options, function (key, value) {\n        switch (key) {\n          case \"minFileCount\":\n          case \"maxFileCount\":\n          case \"maxTotalFileCount\":\n          case \"minFileSize\":\n          case \"maxFileSize\":\n          case \"maxMultipleFileSize\":\n          case \"maxFilePreviewSize\":\n          case \"resizeQuality\":\n          case \"resizeIfSizeMoreThan\":\n          case \"progressUploadThreshold\":\n          case \"initialPreviewCount\":\n          case \"zoomModalHeight\":\n          case \"minImageHeight\":\n          case \"maxImageHeight\":\n          case \"minImageWidth\":\n          case \"maxImageWidth\":\n          case \"bytesToKB\":\n            self[key] = $h.getNum(value);\n            break;\n          default:\n            self[key] = value;\n            break;\n        }\n      });\n      if (!self.bytesToKB || self.bytesToKB <= 0) {\n        self.bytesToKB = 1024;\n      }\n      if (self.errorCloseButton === undefined) {\n        self.errorCloseButton = $h.closeButton(\"kv-error-close\" + ($h.isBs(5) ? \"  float-end\" : \"\"));\n      }\n      if (self.maxTotalFileCount > 0 && self.maxTotalFileCount < self.maxFileCount) {\n        self.maxTotalFileCount = self.maxFileCount;\n      }\n      if (self.rtl) {\n        // swap buttons for rtl\n        tmp = self.previewZoomButtonIcons.prev;\n        self.previewZoomButtonIcons.prev = self.previewZoomButtonIcons.next;\n        self.previewZoomButtonIcons.next = tmp;\n      }\n      // validate chunk threads to not exceed maxAjaxThreads\n      if (!isNaN(self.maxAjaxThreads) && self.maxAjaxThreads < self.resumableUploadOptions.maxThreads) {\n        self.resumableUploadOptions.maxThreads = self.maxAjaxThreads;\n      }\n      self._initFileManager();\n      if (typeof self.autoOrientImage === \"function\") {\n        self.autoOrientImage = self.autoOrientImage();\n      }\n      if (typeof self.autoOrientImageInitial === \"function\") {\n        self.autoOrientImageInitial = self.autoOrientImageInitial();\n      }\n      if (!refreshMode) {\n        self._cleanup();\n      }\n      self.duplicateErrors = [];\n      self.$form = $el.closest(\"form\");\n      self._initTemplateDefaults();\n      self.uploadFileAttr = !$h.isEmpty($el.attr(\"name\")) ? $el.attr(\"name\") : \"file_data\";\n      t = self._getLayoutTemplate(\"progress\");\n      self.progressTemplate = t.replace(\"{class}\", self.progressClass);\n      self.progressInfoTemplate = t.replace(\"{class}\", self.progressInfoClass);\n      self.progressPauseTemplate = t.replace(\"{class}\", self.progressPauseClass);\n      self.progressCompleteTemplate = t.replace(\"{class}\", self.progressCompleteClass);\n      self.progressErrorTemplate = t.replace(\"{class}\", self.progressErrorClass);\n      self.isDisabled = $el.attr(\"disabled\") || $el.attr(\"readonly\");\n      if (self.isDisabled) {\n        $el.attr(\"disabled\", true);\n      }\n      self.isClickable =\n        self.browseOnZoneClick && self.showPreview && (self.dropZoneEnabled || !$h.isEmpty(self.defaultPreviewContent));\n      self.isAjaxUpload = $h.hasFileUploadSupport() && !$h.isEmpty(self.uploadUrl);\n      self.dropZoneEnabled = $h.hasDragDropSupport() && self.dropZoneEnabled;\n      if (!self.isAjaxUpload) {\n        self.dropZoneEnabled = self.dropZoneEnabled && $h.canAssignFilesToInput();\n      }\n      self.slug = typeof options.slugCallback === \"function\" ? options.slugCallback : self._slugDefault;\n      self.mainTemplate = self.showCaption ? self._getLayoutTemplate(\"main1\") : self._getLayoutTemplate(\"main2\");\n      self.captionTemplate = self._getLayoutTemplate(\"caption\");\n      self.previewGenericTemplate = self._getPreviewTemplate(\"generic\");\n      if (!self.imageCanvas && self.resizeImage && (self.maxImageWidth || self.maxImageHeight)) {\n        self.imageCanvas = document.createElement(\"canvas\");\n        self.imageCanvasContext = self.imageCanvas.getContext(\"2d\");\n      }\n      if ($h.isEmpty($el.attr(\"id\"))) {\n        $el.attr(\"id\", $h.uniqId());\n      }\n      self.namespace = \".fileinput_\" + $el.attr(\"id\").replace(/-/g, \"_\");\n      if (self.$container === undefined) {\n        self.$container = self._createContainer();\n      } else {\n        self._refreshContainer();\n      }\n      $cont = self.$container;\n      self.$dropZone = $cont.find(\".file-drop-zone\");\n      self.$progress = $cont.find(\".kv-upload-progress\");\n      self.$btnUpload = $cont.find(\".fileinput-upload\");\n      self.$captionContainer = $h.getElement(options, \"elCaptionContainer\", $cont.find(\".file-caption\"));\n      self.$caption = $h.getElement(options, \"elCaptionText\", $cont.find(\".file-caption-name\"));\n      if (!$h.isEmpty(self.msgPlaceholder)) {\n        f = $el.attr(\"multiple\") ? self.filePlural : self.fileSingle;\n        self.$caption.attr(\"placeholder\", self.msgPlaceholder.replace(\"{files}\", f));\n      }\n      self.$captionIcon = self.$captionContainer.find(\".file-caption-icon\");\n      self.$previewContainer = $h.getElement(options, \"elPreviewContainer\", $cont.find(\".file-preview\"));\n      self.$preview = $h.getElement(options, \"elPreviewImage\", $cont.find(\".file-preview-thumbnails\"));\n      self.$previewStatus = $h.getElement(options, \"elPreviewStatus\", $cont.find(\".file-preview-status\"));\n      self.$errorContainer = $h.getElement(\n        options,\n        \"elErrorContainer\",\n        self.$previewContainer.find(\".kv-fileinput-error\")\n      );\n      self._validateDisabled();\n      if (!$h.isEmpty(self.msgErrorClass)) {\n        $h.addCss(self.$errorContainer, self.msgErrorClass);\n      }\n      if (!refreshMode) {\n        self._resetErrors();\n        self.$errorContainer.hide();\n        self.previewInitId = \"thumb-\" + $el.attr(\"id\");\n        self._initPreviewCache();\n        self._initPreview(true);\n        self._initPreviewActions();\n        if (self.$parent.hasClass(\"file-loading\")) {\n          self.$container.insertBefore(self.$parent);\n          self.$parent.remove();\n        }\n      } else {\n        if (!self._errorsExist()) {\n          self.$errorContainer.hide();\n        }\n      }\n      self._setFileDropZoneTitle();\n      if ($el.attr(\"disabled\")) {\n        self.disable();\n      }\n      self._initZoom();\n      if (self.hideThumbnailContent) {\n        $h.addCss(self.$preview, \"hide-content\");\n      }\n    },\n    _initFileManager: function () {\n      var self = this;\n      self.uploadStartTime = $h.now();\n      self.fileManager = {\n        stack: {},\n        filesProcessed: [],\n        errors: [],\n        loadedImages: {},\n        totalImages: 0,\n        totalFiles: null,\n        totalSize: null,\n        uploadedSize: 0,\n        stats: {},\n        bpsLog: [],\n        bps: 0,\n        initStats: function (id) {\n          var data = { started: $h.now() };\n          if (id) {\n            self.fileManager.stats[id] = data;\n          } else {\n            self.fileManager.stats = data;\n          }\n        },\n        getUploadStats: function (id, loaded, total) {\n          var fm = self.fileManager,\n            started = id ? (fm.stats[id] && fm.stats[id].started) || $h.now() : self.uploadStartTime,\n            elapsed = ($h.now() - started) / 1000,\n            bps = Math.ceil(elapsed ? loaded / elapsed : 0),\n            pendingBytes = total - loaded,\n            out,\n            delay = fm.bpsLog.length ? self.bitrateUpdateDelay : 0;\n          setTimeout(function () {\n            var i,\n              j = 0,\n              n = 0,\n              len,\n              beg;\n            fm.bpsLog.push(bps);\n            fm.bpsLog.sort(function (a, b) {\n              return a - b;\n            });\n            len = fm.bpsLog.length;\n            beg = len > 10 ? len - 10 : Math.ceil(len / 2);\n            for (i = len; i > beg; i--) {\n              n = parseFloat(fm.bpsLog[i]);\n              j++;\n            }\n            fm.bps = (j > 0 ? n / j : 0) * 64;\n          }, delay);\n          out = {\n            fileId: id,\n            started: started,\n            elapsed: elapsed,\n            loaded: loaded,\n            total: total,\n            bps: fm.bps,\n            bitrate: self._getSize(fm.bps, false, self.bitRateUnits),\n            pendingBytes: pendingBytes,\n          };\n          if (id) {\n            fm.stats[id] = out;\n          } else {\n            fm.stats = out;\n          }\n          return out;\n        },\n        exists: function (id) {\n          return $.inArray(id, self.fileManager.getIdList()) !== -1;\n        },\n        count: function () {\n          return self.fileManager.getIdList().length;\n        },\n        total: function () {\n          var fm = self.fileManager;\n          if (!fm.totalFiles) {\n            fm.totalFiles = fm.count();\n          }\n          return fm.totalFiles;\n        },\n        getTotalSize: function () {\n          var fm = self.fileManager;\n          if (fm.totalSize) {\n            return fm.totalSize;\n          }\n          fm.totalSize = 0;\n          $.each(self.getFileStack(), function (id, f) {\n            var size = parseFloat(f.size);\n            fm.totalSize += isNaN(size) ? 0 : size;\n          });\n          return fm.totalSize;\n        },\n        add: function (file, id) {\n          if (!id) {\n            id = self.fileManager.getId(file);\n          }\n          if (!id) {\n            return;\n          }\n          self.fileManager.stack[id] = {\n            file: file,\n            name: $h.getFileName(file),\n            relativePath: $h.getFileRelativePath(file),\n            size: file.size,\n            nameFmt: self._getFileName(file, \"\"),\n            sizeFmt: self._getSize(file.size),\n          };\n        },\n        remove: function ($thumb) {\n          var id = self._getThumbFileId($thumb);\n          self.fileManager.removeFile(id);\n        },\n        removeFile: function (id) {\n          var fm = self.fileManager;\n          if (!id) {\n            return;\n          }\n          delete fm.stack[id];\n          delete fm.loadedImages[id];\n        },\n        move: function (idFrom, idTo) {\n          var result = {},\n            stack = self.fileManager.stack;\n          if ((!idFrom && !idTo) || idFrom === idTo) {\n            return;\n          }\n          $.each(stack, function (k, v) {\n            if (k !== idFrom) {\n              result[k] = v;\n            }\n            if (k === idTo) {\n              result[idFrom] = stack[idFrom];\n            }\n          });\n          self.fileManager.stack = result;\n        },\n        list: function () {\n          var files = [];\n          $.each(self.getFileStack(), function (k, v) {\n            if (v && v.file) {\n              files.push(v.file);\n            }\n          });\n          return files;\n        },\n        isPending: function (id) {\n          return $.inArray(id, self.fileManager.filesProcessed) === -1 && self.fileManager.exists(id);\n        },\n        isProcessed: function () {\n          var filesProcessed = true,\n            fm = self.fileManager;\n          $.each(self.getFileStack(), function (id) {\n            if (fm.isPending(id)) {\n              filesProcessed = false;\n            }\n          });\n          return filesProcessed;\n        },\n        clear: function () {\n          var fm = self.fileManager;\n          self.isDuplicateError = false;\n          self.isPersistentError = false;\n          fm.totalFiles = null;\n          fm.totalSize = null;\n          fm.uploadedSize = 0;\n          fm.stack = {};\n          fm.errors = [];\n          fm.filesProcessed = [];\n          fm.stats = {};\n          fm.bpsLog = [];\n          fm.bps = 0;\n          fm.clearImages();\n        },\n        clearImages: function () {\n          self.fileManager.loadedImages = {};\n          self.fileManager.totalImages = 0;\n        },\n        addImage: function (id, config) {\n          self.fileManager.loadedImages[id] = config;\n        },\n        removeImage: function (id) {\n          delete self.fileManager.loadedImages[id];\n        },\n        getImageIdList: function () {\n          return $h.getObjectKeys(self.fileManager.loadedImages);\n        },\n        getImageCount: function () {\n          return self.fileManager.getImageIdList().length;\n        },\n        getId: function (file) {\n          return self._getFileId(file);\n        },\n        getIndex: function (id) {\n          return self.fileManager.getIdList().indexOf(id);\n        },\n        getThumb: function (id) {\n          var $thumb = null;\n          self._getThumbs().each(function () {\n            var $t = $(this);\n            if (self._getThumbFileId($t) === id) {\n              $thumb = $t;\n            }\n          });\n          return $thumb;\n        },\n        getThumbIndex: function ($thumb) {\n          var id = self._getThumbFileId($thumb);\n          return self.fileManager.getIndex(id);\n        },\n        getIdList: function () {\n          return $h.getObjectKeys(self.fileManager.stack);\n        },\n        getFile: function (id) {\n          return self.fileManager.stack[id] || null;\n        },\n        getFileName: function (id, fmt) {\n          var file = self.fileManager.getFile(id);\n          if (!file) {\n            return \"\";\n          }\n          return fmt ? file.nameFmt || \"\" : file.name || \"\";\n        },\n        getFirstFile: function () {\n          var ids = self.fileManager.getIdList(),\n            id = ids && ids.length ? ids[0] : null;\n          return self.fileManager.getFile(id);\n        },\n        setFile: function (id, file) {\n          if (self.fileManager.getFile(id)) {\n            self.fileManager.stack[id].file = file;\n          } else {\n            self.fileManager.add(file, id);\n          }\n        },\n        setProcessed: function (id) {\n          self.fileManager.filesProcessed.push(id);\n        },\n        getProgress: function () {\n          var total = self.fileManager.total(),\n            filesProcessed = self.fileManager.filesProcessed.length;\n          if (!total) {\n            return 0;\n          }\n          return Math.ceil((filesProcessed / total) * 100);\n        },\n        setProgress: function (id, pct) {\n          var f = self.fileManager.getFile(id);\n          if (!isNaN(pct) && f) {\n            f.progress = pct;\n          }\n        },\n      };\n    },\n    _setUploadData: function (fd, config) {\n      var self = this;\n      $.each(config, function (key, value) {\n        var param = self.uploadParamNames[key] || key;\n        if ($h.isArray(value)) {\n          fd.append(param, value[0], value[1]);\n        } else {\n          fd.append(param, value);\n        }\n      });\n    },\n    _initResumableUpload: function () {\n      var self = this,\n        opts = self.resumableUploadOptions,\n        logs = $h.logMessages,\n        rm,\n        fm = self.fileManager;\n      if (!self.enableResumableUpload) {\n        return;\n      }\n      if (opts.fallback !== false && typeof opts.fallback !== \"function\") {\n        opts.fallback = function (s) {\n          s._log(logs.noResumableSupport);\n          s.enableResumableUpload = false;\n        };\n      }\n      if (!$h.hasResumableUploadSupport() && opts.fallback !== false) {\n        opts.fallback(self);\n        return;\n      }\n      if (!self.uploadUrl && self.enableResumableUpload) {\n        self._log(logs.noUploadUrl);\n        self.enableResumableUpload = false;\n        return;\n      }\n      opts.chunkSize = parseFloat(opts.chunkSize);\n      if (opts.chunkSize <= 0 || isNaN(opts.chunkSize)) {\n        self._log(logs.invalidChunkSize, { chunkSize: opts.chunkSize });\n        self.enableResumableUpload = false;\n        return;\n      }\n      rm = self.resumableManager = {\n        init: function (id, f, index) {\n          rm.logs = [];\n          rm.stack = [];\n          rm.error = \"\";\n          rm.id = id;\n          rm.file = f.file;\n          rm.fileName = f.name;\n          rm.fileIndex = index;\n          rm.completed = false;\n          rm.lastProgress = 0;\n          if (self.showPreview) {\n            rm.$thumb = fm.getThumb(id) || null;\n            rm.$progress = rm.$btnDelete = null;\n            if (rm.$thumb && rm.$thumb.length) {\n              rm.$progress = rm.$thumb.find(\".file-thumb-progress\");\n              rm.$btnDelete = rm.$thumb.find(\".kv-file-remove\");\n            }\n          }\n          rm.chunkSize = opts.chunkSize * self.bytesToKB;\n          rm.chunkCount = rm.getTotalChunks();\n        },\n        setAjaxError: function (jqXHR, textStatus, errorThrown, isTest) {\n          if (jqXHR.responseJSON && jqXHR.responseJSON.error) {\n            errorThrown = jqXHR.responseJSON.error.toString();\n          }\n          if (!isTest) {\n            rm.error = errorThrown;\n          }\n          if (opts.showErrorLog) {\n            self._log(logs.ajaxError, {\n              status: jqXHR.status,\n              error: errorThrown,\n              text: jqXHR.responseText || \"\",\n            });\n          }\n        },\n        reset: function () {\n          rm.stack = [];\n          rm.chunksProcessed = {};\n        },\n        setProcessed: function (status) {\n          var id = rm.id,\n            msg,\n            $thumb = rm.$thumb,\n            $prog = rm.$progress,\n            hasThumb = $thumb && $thumb.length,\n            params = { id: hasThumb ? $thumb.attr(\"id\") : \"\", index: fm.getIndex(id), fileId: id },\n            tokens,\n            skipErrorsAndProceed = self.resumableUploadOptions.skipErrorsAndProceed;\n          rm.completed = true;\n          rm.lastProgress = 0;\n          if (hasThumb) {\n            $thumb.removeClass(\"file-uploading\");\n          }\n          if (status === \"success\") {\n            fm.uploadedSize += rm.file.size;\n            if (self.showPreview) {\n              self._setProgress(101, $prog);\n              self._setThumbStatus($thumb, \"Success\");\n              self._initUploadSuccess(rm.chunksProcessed[id].data, $thumb);\n            }\n            fm.removeFile(id);\n            delete rm.chunksProcessed[id];\n            self._raise(\"fileuploaded\", [params.id, params.index, params.fileId]);\n            if (fm.isProcessed()) {\n              self._setProgress(101);\n            }\n          } else {\n            if (status !== \"cancel\") {\n              if (self.showPreview) {\n                self._setThumbStatus($thumb, \"Error\");\n                self._setPreviewError($thumb, true);\n                self._setProgress(101, $prog, self.msgProgressError);\n                self._setProgress(101, self.$progress, self.msgProgressError);\n                self.cancelling = !skipErrorsAndProceed;\n              }\n              if (!self.$errorContainer.find('li[data-file-id=\"' + params.fileId + '\"]').length) {\n                tokens = { file: rm.fileName, max: opts.maxRetries, error: rm.error };\n                msg = self.msgResumableUploadRetriesExceeded.setTokens(tokens);\n                $.extend(params, tokens);\n                self._showFileError(msg, params, \"filemaxretries\");\n                if (skipErrorsAndProceed) {\n                  fm.removeFile(id);\n                  delete rm.chunksProcessed[id];\n                  if (fm.isProcessed()) {\n                    self._setProgress(101);\n                  }\n                }\n              }\n            }\n          }\n          if (fm.isProcessed()) {\n            rm.reset();\n          }\n        },\n        check: function () {\n          var status = true;\n          $.each(rm.logs, function (index, value) {\n            if (!value) {\n              status = false;\n              return false;\n            }\n          });\n        },\n        processedResumables: function () {\n          var logs = rm.logs,\n            i,\n            count = 0;\n          if (!logs || !logs.length) {\n            return 0;\n          }\n          for (i = 0; i < logs.length; i++) {\n            if (logs[i] === true) {\n              count++;\n            }\n          }\n          return count;\n        },\n        getUploadedSize: function () {\n          var size = rm.processedResumables() * rm.chunkSize;\n          return size > rm.file.size ? rm.file.size : size;\n        },\n        getTotalChunks: function () {\n          var chunkSize = parseFloat(rm.chunkSize);\n          if (!isNaN(chunkSize) && chunkSize > 0) {\n            return Math.ceil(rm.file.size / chunkSize);\n          }\n          return 0;\n        },\n        getProgress: function () {\n          var chunksProcessed = rm.processedResumables(),\n            total = rm.chunkCount;\n          if (total === 0) {\n            return 0;\n          }\n          return Math.ceil((chunksProcessed / total) * 100);\n        },\n        checkAborted: function (intervalId) {\n          if (self._isAborted()) {\n            clearInterval(intervalId);\n            self.unlock();\n          }\n        },\n        upload: function () {\n          var ids = fm.getIdList(),\n            flag = \"new\",\n            intervalId;\n          intervalId = setInterval(function () {\n            var id;\n            rm.checkAborted(intervalId);\n            if (flag === \"new\") {\n              self.lock();\n              flag = \"processing\";\n              id = ids.shift();\n              fm.initStats(id);\n              if (fm.stack[id]) {\n                rm.init(id, fm.stack[id], fm.getIndex(id));\n                rm.processUpload();\n              }\n            }\n            if (!fm.isPending(id) && rm.completed) {\n              flag = \"new\";\n            }\n            if (fm.isProcessed()) {\n              var $initThumbs = self.$preview.find(\".file-preview-initial\");\n              if ($initThumbs.length) {\n                $h.addCss($initThumbs, $h.SORT_CSS);\n                self._initSortable();\n              }\n              clearInterval(intervalId);\n              self._clearFileInput();\n              self.unlock();\n              setTimeout(function () {\n                var data = self.previewCache.data;\n                if (data) {\n                  self.initialPreview = data.content;\n                  self.initialPreviewConfig = data.config;\n                  self.initialPreviewThumbTags = data.tags;\n                }\n                self._raise(\"filebatchuploadcomplete\", [\n                  self.initialPreview,\n                  self.initialPreviewConfig,\n                  self.initialPreviewThumbTags,\n                  self._getExtraData(),\n                ]);\n              }, self.processDelay);\n            }\n          }, self.processDelay);\n        },\n        uploadResumable: function () {\n          var i,\n            pool,\n            tm = self.taskManager,\n            total = rm.chunkCount;\n          pool = tm.addPool(rm.id);\n          for (i = 0; i < total; i++) {\n            rm.logs[i] = !!(rm.chunksProcessed[rm.id] && rm.chunksProcessed[rm.id][i]);\n            if (!rm.logs[i]) {\n              rm.pushAjax(i, 0);\n            }\n          }\n          pool\n            .run(opts.maxThreads)\n            .done(function () {\n              rm.setProcessed(\"success\");\n            })\n            .fail(function () {\n              rm.setProcessed(pool.cancelled ? \"cancel\" : \"error\");\n            });\n        },\n        processUpload: function () {\n          var fd,\n            f,\n            id = rm.id,\n            fnBefore,\n            fnSuccess,\n            fnError,\n            fnComplete,\n            outData;\n          if (!opts.testUrl) {\n            rm.uploadResumable();\n            return;\n          }\n          fd = new FormData();\n          f = fm.stack[id];\n          self._setUploadData(fd, {\n            fileId: id,\n            fileName: f.fileName,\n            fileSize: f.size,\n            fileRelativePath: f.relativePath,\n            chunkSize: rm.chunkSize,\n            chunkCount: rm.chunkCount,\n          });\n          fnBefore = function (jqXHR) {\n            outData = self._getOutData(fd, jqXHR);\n            self._raise(\"filetestbeforesend\", [id, fm, rm, outData]);\n          };\n          fnSuccess = function (data, textStatus, jqXHR) {\n            outData = self._getOutData(fd, jqXHR, data);\n            var pNames = self.uploadParamNames,\n              chunksUploaded = pNames.chunksUploaded || \"chunksUploaded\",\n              params = [id, fm, rm, outData];\n            if (!data[chunksUploaded] || !$h.isArray(data[chunksUploaded])) {\n              self._raise(\"filetesterror\", params);\n            } else {\n              if (!rm.chunksProcessed[id]) {\n                rm.chunksProcessed[id] = {};\n              }\n              $.each(data[chunksUploaded], function (key, index) {\n                rm.logs[index] = true;\n                rm.chunksProcessed[id][index] = true;\n              });\n              rm.chunksProcessed[id].data = data;\n              self._raise(\"filetestsuccess\", params);\n            }\n            rm.uploadResumable();\n          };\n          fnError = function (jqXHR, textStatus, errorThrown) {\n            outData = self._getOutData(fd, jqXHR);\n            self._raise(\"filetestajaxerror\", [id, fm, rm, outData]);\n            rm.setAjaxError(jqXHR, textStatus, errorThrown, true);\n            rm.uploadResumable();\n          };\n          fnComplete = function () {\n            self._raise(\"filetestcomplete\", [id, fm, rm, self._getOutData(fd)]);\n          };\n          self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, fd, id, rm.fileIndex, opts.testUrl);\n        },\n        pushAjax: function (index, retry) {\n          var tm = self.taskManager,\n            pool = tm.getPool(rm.id);\n          pool.addTask(pool.size() + 1, function (deferrer) {\n            // use fifo chunk stack\n            var arr = rm.stack.shift(),\n              index;\n            index = arr[0];\n            if (!rm.chunksProcessed[rm.id] || !rm.chunksProcessed[rm.id][index]) {\n              rm.sendAjax(index, arr[1], deferrer);\n            } else {\n              self._log(logs.chunkQueueError, { index: index });\n            }\n          });\n          rm.stack.push([index, retry]);\n        },\n        sendAjax: function (index, retry, deferrer) {\n          var f,\n            chunkSize = rm.chunkSize,\n            id = rm.id,\n            file = rm.file,\n            $thumb = rm.$thumb,\n            msgs = $h.logMessages,\n            $btnDelete = rm.$btnDelete,\n            logError = function (msg, tokens) {\n              if (tokens) {\n                msg = msg.setTokens(tokens);\n              }\n              msg = msgs.resumableRequestError.setTokens({ msg: msg });\n              self._log(msg);\n              deferrer.reject(msg);\n            };\n          if (rm.chunksProcessed[id] && rm.chunksProcessed[id][index]) {\n            return;\n          }\n          if (retry > opts.maxRetries) {\n            logError(msgs.resumableMaxRetriesReached, { n: opts.maxRetries });\n            rm.setProcessed(\"error\");\n            return;\n          }\n          var fd,\n            outData,\n            fnBefore,\n            fnSuccess,\n            fnError,\n            fnComplete,\n            slice = file.slice ? \"slice\" : file.mozSlice ? \"mozSlice\" : file.webkitSlice ? \"webkitSlice\" : \"slice\",\n            blob = file[slice](chunkSize * index, chunkSize * (index + 1));\n          fd = new FormData();\n          f = fm.stack[id];\n          self._setUploadData(fd, {\n            chunkCount: rm.chunkCount,\n            chunkIndex: index,\n            chunkSize: chunkSize,\n            chunkSizeStart: chunkSize * index,\n            fileBlob: [blob, rm.fileName],\n            fileId: id,\n            fileName: rm.fileName,\n            fileRelativePath: f.relativePath,\n            fileSize: file.size,\n            retryCount: retry,\n          });\n          if (rm.$progress && rm.$progress.length) {\n            rm.$progress.show();\n          }\n          fnBefore = function (jqXHR) {\n            outData = self._getOutData(fd, jqXHR);\n            if (self.showPreview) {\n              if (!$thumb.hasClass(\"file-preview-success\")) {\n                self._setThumbStatus($thumb, \"Loading\");\n                $h.addCss($thumb, \"file-uploading\");\n              }\n              $btnDelete.attr(\"disabled\", true);\n            }\n            self._raise(\"filechunkbeforesend\", [id, index, retry, fm, rm, outData]);\n          };\n          fnSuccess = function (data, textStatus, jqXHR) {\n            if (self._isAborted()) {\n              logError(msgs.resumableAborting);\n              return;\n            }\n            outData = self._getOutData(fd, jqXHR, data);\n            var paramNames = self.uploadParamNames,\n              chunkIndex = paramNames.chunkIndex || \"chunkIndex\",\n              params = [id, index, retry, fm, rm, outData];\n            if (data.error) {\n              if (opts.showErrorLog) {\n                self._log(logs.retryStatus, {\n                  retry: retry + 1,\n                  filename: rm.fileName,\n                  chunk: index,\n                });\n              }\n              self._raise(\"filechunkerror\", params);\n              rm.pushAjax(index, retry + 1);\n              rm.error = data.error;\n              logError(data.error);\n            } else {\n              rm.logs[data[chunkIndex]] = true;\n              if (!rm.chunksProcessed[id]) {\n                rm.chunksProcessed[id] = {};\n              }\n              rm.chunksProcessed[id][data[chunkIndex]] = true;\n              rm.chunksProcessed[id].data = data;\n              deferrer.resolve.call(null, data);\n              self._raise(\"filechunksuccess\", params);\n              rm.check();\n            }\n          };\n          fnError = function (jqXHR, textStatus, errorThrown) {\n            if (self._isAborted()) {\n              logError(msgs.resumableAborting);\n              return;\n            }\n            outData = self._getOutData(fd, jqXHR);\n            rm.setAjaxError(jqXHR, textStatus, errorThrown);\n            self._raise(\"filechunkajaxerror\", [id, index, retry, fm, rm, outData]);\n            rm.pushAjax(index, retry + 1); // push another task\n            logError(msgs.resumableRetryError, { n: retry - 1 }); // resolve the current task\n          };\n          fnComplete = function () {\n            if (!self._isAborted()) {\n              self._raise(\"filechunkcomplete\", [id, index, retry, fm, rm, self._getOutData(fd)]);\n            }\n          };\n          self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, fd, id, rm.fileIndex);\n        },\n      };\n      rm.reset();\n    },\n    _initTemplateDefaults: function () {\n      var self = this,\n        tMain1,\n        tMain2,\n        tPreview,\n        tFileIcon,\n        tClose,\n        tCaption,\n        tBtnDefault,\n        tBtnLink,\n        tBtnBrowse,\n        tModalMain,\n        tModal,\n        tProgress,\n        tSize,\n        tFooter,\n        tActions,\n        tActionDelete,\n        tActionUpload,\n        tActionDownload,\n        tActionZoom,\n        tActionDrag,\n        tIndicator,\n        tTagBef,\n        tTagBef1,\n        tTagBef2,\n        tTagAft,\n        tGeneric,\n        tHtml,\n        tImage,\n        tText,\n        tOffice,\n        tGdocs,\n        tVideo,\n        tAudio,\n        tFlash,\n        tObject,\n        tPdf,\n        tOther,\n        tStyle,\n        tZoomCache,\n        vDefaultDim,\n        tActionRotate,\n        tStats,\n        tModalLabel,\n        tDescClose,\n        renderObject = function (type, mime) {\n          return (\n            '<object class=\"kv-preview-data file-preview-' +\n            type +\n            '\" title=\"{caption}\" ' +\n            'data=\"{data}\" type=\"' +\n            mime +\n            '\"' +\n            tStyle +\n            \">\\n\" +\n            $h.DEFAULT_PREVIEW +\n            \"\\n</object>\\n\"\n          );\n        },\n        defBtnCss1 = \"btn btn-sm btn-kv \" + $h.defaultButtonCss();\n      tMain1 =\n        \"{preview}\\n\" +\n        '<div class=\"kv-upload-progress kv-hidden\"></div><div class=\"clearfix\"></div>\\n' +\n        '<div class=\"file-caption {class}\">\\n' +\n        '  <div class=\"input-group {inputGroupClass}\">\\n' +\n        '      {caption}\\n<span class=\"file-caption-icon\"></span>\\n' +\n        ($h.isBs(5) ? \"\" : '<div class=\"input-group-btn input-group-append\">\\n') +\n        \"      {remove}\\n\" +\n        \"      {cancel}\\n\" +\n        \"      {pause}\\n\" +\n        \"      {upload}\\n\" +\n        \"      {browse}\\n\" +\n        ($h.isBs(5) ? \"\" : \"    </div>\\n\") +\n        \"  </div>\";\n      (\"</div>\");\n      tMain2 =\n        '{preview}\\n<div class=\"kv-upload-progress kv-hidden\"></div>\\n<div class=\"clearfix\"></div>\\n' +\n        '<span class=\"{class}\">{remove}\\n{cancel}\\n{upload}\\n{browse}\\n</span>';\n      tPreview =\n        '<div class=\"file-preview {class}\">\\n' +\n        \"  {close}\" +\n        '  <div class=\"{dropClass} clearfix\">\\n' +\n        '    <div class=\"file-preview-thumbnails clearfix\">\\n' +\n        \"    </div>\\n\" +\n        '    <div class=\"file-preview-status text-center text-success\"></div>\\n' +\n        '    <div class=\"kv-fileinput-error\"></div>\\n' +\n        \"  </div>\\n\" +\n        \"</div>\";\n      tClose = $h.closeButton(\"fileinput-remove\");\n      tFileIcon = '<i class=\"glyphicon glyphicon-file\"></i>';\n      // noinspection HtmlUnknownAttribute\n      tCaption = '<input readonly class=\"file-caption-name form-control {class}\">\\n';\n      //noinspection HtmlUnknownAttribute\n      tBtnDefault =\n        '<button type=\"{type}\" title=\"{title}\" class=\"{css}\" ' + \"{status} {tabIndexConfig}>{icon} {label}</button>\";\n      //noinspection HtmlUnknownTarget,HtmlUnknownAttribute\n      tBtnLink = '<a href=\"{href}\" title=\"{title}\" class=\"{css}\" {status} {tabIndexConfig}>{icon} {label}</a>';\n      //noinspection HtmlUnknownAttribute\n      tBtnBrowse = '<div class=\"{css}\" {status} {tabIndexConfig}>{icon} {label}</div>';\n      tModalLabel = $h.MODAL_ID + \"Label\";\n      tModalMain =\n        '<div id=\"' +\n        $h.MODAL_ID +\n        '\" class=\"file-zoom-dialog modal fade\" ' +\n        'aria-labelledby=\"' +\n        tModalLabel +\n        '\" {tabIndexConfig}></div>';\n      tModal =\n        '<div class=\"modal-dialog modal-lg{rtl}\" role=\"document\">\\n' +\n        '  <div class=\"modal-content\">\\n' +\n        '    <div class=\"modal-header kv-zoom-header\">\\n' +\n        '      <h6 class=\"modal-title kv-zoom-title\" id=\"' +\n        tModalLabel +\n        '\"><span class=\"kv-zoom-caption\"></span> <span class=\"kv-zoom-size\"></span></h6>\\n' +\n        '      <div class=\"kv-zoom-actions\">{toggleheader}{fullscreen}{borderless}{close}</div>\\n' +\n        \"    </div>\\n\" +\n        '    <div class=\"floating-buttons\"></div>\\n' +\n        '    <div class=\"kv-zoom-body file-zoom-content {zoomFrameClass}\"></div>\\n' +\n        \"{prev} {next}\\n\" +\n        '    <div class=\"kv-zoom-description\"></div>\\n' +\n        \"  </div>\\n\" +\n        \"</div>\\n\";\n      tDescClose = '<button type=\"button\" class=\"kv-desc-hide\" aria-label=\"Close\">{closeIcon}</button>';\n      tProgress =\n        '<div class=\"progress\">\\n' +\n        '    <div class=\"{class}\" role=\"progressbar\"' +\n        ' aria-valuenow=\"{percent}\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width:{percent}%;\">\\n' +\n        \"        {status}\\n\" +\n        \"     </div>\\n\" +\n        \"</div>{stats}\";\n      tStats =\n        '<div class=\"text-primary file-upload-stats\">' +\n        '<span class=\"pending-time\">{pendingTime}</span> ' +\n        '<span class=\"upload-speed\">{uploadSpeed}</span>' +\n        \"</div>\";\n      tSize = \" <samp>({sizeText})</samp>\";\n      tFooter =\n        '<div class=\"file-thumbnail-footer\">\\n' +\n        '    <div class=\"file-footer-caption\" title=\"{caption}\">\\n' +\n        '        <div class=\"file-caption-info\">{caption}</div>\\n' +\n        '        <div class=\"file-size-info\">{size}</div>\\n' +\n        \"    </div>\\n\" +\n        \"    {progress}\\n{indicator}\\n{actions}\\n\" +\n        \"</div>\";\n      tActions =\n        '<div class=\"file-actions\">\\n' +\n        '    <div class=\"file-footer-buttons\">\\n' +\n        \"        {rotate} {download} {upload} {delete} {zoom} {other}\" +\n        \"    </div>\\n\" +\n        \"</div>\\n\" +\n        \"{drag}\\n\" +\n        '<div class=\"clearfix\"></div>';\n      //noinspection HtmlUnknownAttribute\n      tActionDelete =\n        '<button type=\"button\" class=\"kv-file-remove {removeClass}\" ' +\n        'title=\"{removeTitle}\" {dataUrl}{dataKey}>{removeIcon}</button>\\n';\n      tActionUpload =\n        '<button type=\"button\" class=\"kv-file-upload {uploadClass}\" title=\"{uploadTitle}\">' + \"{uploadIcon}</button>\";\n      tActionRotate =\n        '<button type=\"button\" class=\"kv-file-rotate {rotateClass}\" title=\"{rotateTitle}\">' + \"{rotateIcon}</button>\";\n      tActionDownload =\n        '<a class=\"kv-file-download {downloadClass}\" title=\"{downloadTitle}\" ' +\n        'href=\"{downloadUrl}\" download=\"{caption}\" target=\"_blank\">{downloadIcon}</a>';\n      tActionZoom =\n        '<button type=\"button\" class=\"kv-file-zoom {zoomClass}\" ' + 'title=\"{zoomTitle}\">{zoomIcon}</button>';\n      tActionDrag = '<span class=\"file-drag-handle {dragClass}\" title=\"{dragTitle}\">{dragIcon}</span>';\n      tIndicator = '<div class=\"file-upload-indicator\" title=\"{indicatorTitle}\">{indicator}</div>';\n      tTagBef =\n        '<div class=\"file-preview-frame {frameClass}\" id=\"{previewId}\" data-fileindex=\"{fileindex}\"' +\n        ' data-fileid=\"{fileid}\" data-filename=\"{filename}\" data-template=\"{template}\" data-zoom=\"{zoomData}\"';\n      tTagBef1 = tTagBef + '><div class=\"kv-file-content\">\\n';\n      tTagBef2 = tTagBef + ' title=\"{caption}\"><div class=\"kv-file-content\">\\n';\n      tTagAft = \"</div>{footer}\\n{zoomCache}</div>\\n\";\n      tGeneric = \"{content}\\n\";\n      tStyle = \" {style}\";\n      tHtml = renderObject(\"html\", \"text/html\");\n      tText = renderObject(\"text\", \"text/plain;charset=UTF-8\");\n      tPdf = renderObject(\"pdf\", \"application/pdf\");\n      tImage =\n        '<img src=\"{data}\" class=\"file-preview-image kv-preview-data\" title=\"{title}\" alt=\"{alt}\"' + tStyle + \">\\n\";\n      tOffice =\n        '<iframe class=\"kv-preview-data file-preview-office\" ' +\n        'src=\"https://view.officeapps.live.com/op/embed.aspx?src={data}\"' +\n        tStyle +\n        \"></iframe>\";\n      tGdocs =\n        '<iframe class=\"kv-preview-data file-preview-gdocs\" ' +\n        'src=\"https://docs.google.com/gview?url={data}&embedded=true\"' +\n        tStyle +\n        \"></iframe>\";\n      tVideo =\n        '<video class=\"kv-preview-data file-preview-video\" controls' +\n        tStyle +\n        \">\\n\" +\n        '<source src=\"{data}\" type=\"{type}\">\\n' +\n        $h.DEFAULT_PREVIEW +\n        \"\\n</video>\\n\";\n      tAudio =\n        '<!--suppress ALL --><audio class=\"kv-preview-data file-preview-audio\" controls' +\n        tStyle +\n        '>\\n<source src=\"{data}\" ' +\n        'type=\"{type}\">\\n' +\n        $h.DEFAULT_PREVIEW +\n        \"\\n</audio>\\n\";\n      tFlash =\n        '<embed class=\"kv-preview-data file-preview-flash\" src=\"{data}\" type=\"application/x-shockwave-flash\"' +\n        tStyle +\n        \">\\n\";\n      tObject =\n        '<object class=\"kv-preview-data file-preview-object file-object {typeCss}\" ' +\n        'data=\"{data}\" type=\"{type}\"' +\n        tStyle +\n        \">\\n\" +\n        '<param name=\"movie\" value=\"{caption}\" />\\n' +\n        $h.OBJECT_PARAMS +\n        \" \" +\n        $h.DEFAULT_PREVIEW +\n        \"\\n</object>\\n\";\n      tOther =\n        '<div class=\"kv-preview-data file-preview-other-frame\"' + tStyle + \">\\n\" + $h.DEFAULT_PREVIEW + \"\\n</div>\\n\";\n      tZoomCache = '<div class=\"kv-zoom-cache\">{zoomContent}</div>';\n      vDefaultDim = { width: \"100%\", height: \"100%\", \"min-height\": \"480px\" };\n      if (self._isPdfRendered()) {\n        tPdf = self.pdfRendererTemplate.replace(\"{renderer}\", self._encodeURI(self.pdfRendererUrl));\n      }\n      self.defaults = {\n        layoutTemplates: {\n          main1: tMain1,\n          main2: tMain2,\n          preview: tPreview,\n          close: tClose,\n          fileIcon: tFileIcon,\n          caption: tCaption,\n          modalMain: tModalMain,\n          modal: tModal,\n          descriptionClose: tDescClose,\n          progress: tProgress,\n          stats: tStats,\n          size: tSize,\n          footer: tFooter,\n          indicator: tIndicator,\n          actions: tActions,\n          actionDelete: tActionDelete,\n          actionRotate: tActionRotate,\n          actionUpload: tActionUpload,\n          actionDownload: tActionDownload,\n          actionZoom: tActionZoom,\n          actionDrag: tActionDrag,\n          btnDefault: tBtnDefault,\n          btnLink: tBtnLink,\n          btnBrowse: tBtnBrowse,\n          zoomCache: tZoomCache,\n        },\n        previewMarkupTags: {\n          tagBefore1: tTagBef1,\n          tagBefore2: tTagBef2,\n          tagAfter: tTagAft,\n        },\n        previewContentTemplates: {\n          generic: tGeneric,\n          html: tHtml,\n          image: tImage,\n          text: tText,\n          office: tOffice,\n          gdocs: tGdocs,\n          video: tVideo,\n          audio: tAudio,\n          flash: tFlash,\n          object: tObject,\n          pdf: tPdf,\n          other: tOther,\n        },\n        allowedPreviewTypes: [\"image\", \"html\", \"text\", \"video\", \"audio\", \"flash\", \"pdf\", \"object\"],\n        previewTemplates: {},\n        previewSettings: {\n          image: { width: \"auto\", height: \"auto\", \"max-width\": \"100%\", \"max-height\": \"100%\" },\n          html: { width: \"213px\", height: \"160px\" },\n          text: { width: \"213px\", height: \"160px\" },\n          office: { width: \"213px\", height: \"160px\" },\n          gdocs: { width: \"213px\", height: \"160px\" },\n          video: { width: \"213px\", height: \"160px\" },\n          audio: { width: \"100%\", height: \"30px\" },\n          flash: { width: \"213px\", height: \"160px\" },\n          object: { width: \"213px\", height: \"160px\" },\n          pdf: { width: \"100%\", height: \"160px\", position: \"relative\" },\n          other: { width: \"213px\", height: \"160px\" },\n        },\n        previewSettingsSmall: {\n          image: { width: \"auto\", height: \"auto\", \"max-width\": \"100%\", \"max-height\": \"100%\" },\n          html: { width: \"100%\", height: \"160px\" },\n          text: { width: \"100%\", height: \"160px\" },\n          office: { width: \"100%\", height: \"160px\" },\n          gdocs: { width: \"100%\", height: \"160px\" },\n          video: { width: \"100%\", height: \"auto\" },\n          audio: { width: \"100%\", height: \"30px\" },\n          flash: { width: \"100%\", height: \"auto\" },\n          object: { width: \"100%\", height: \"auto\" },\n          pdf: { width: \"100%\", height: \"160px\" },\n          other: { width: \"100%\", height: \"160px\" },\n        },\n        previewZoomSettings: {\n          image: { width: \"auto\", height: \"auto\", \"max-width\": \"100%\", \"max-height\": \"100%\" },\n          html: vDefaultDim,\n          text: vDefaultDim,\n          office: { width: \"100%\", height: \"100%\", \"max-width\": \"100%\", \"min-height\": \"480px\" },\n          gdocs: { width: \"100%\", height: \"100%\", \"max-width\": \"100%\", \"min-height\": \"480px\" },\n          video: { width: \"auto\", height: \"100%\", \"max-width\": \"100%\" },\n          audio: { width: \"100%\", height: \"30px\" },\n          flash: { width: \"auto\", height: \"480px\" },\n          object: { width: \"auto\", height: \"100%\", \"max-width\": \"100%\", \"min-height\": \"480px\" },\n          pdf: vDefaultDim,\n          other: { width: \"auto\", height: \"100%\", \"min-height\": \"480px\" },\n        },\n        mimeTypeAliases: {\n          \"video/quicktime\": \"video/mp4\",\n        },\n        fileTypeSettings: {\n          image: function (vType, vName) {\n            return (\n              ($h.compare(vType, \"image.*\") && !$h.compare(vType, /(tiff?|wmf)$/i)) ||\n              $h.compare(vName, /\\.(gif|png|jpe?g)$/i)\n            );\n          },\n          html: function (vType, vName) {\n            return $h.compare(vType, \"text/html\") || $h.compare(vName, /\\.(htm|html)$/i);\n          },\n          office: function (vType, vName) {\n            return (\n              $h.compare(vType, /(word|excel|powerpoint|office)$/i) ||\n              $h.compare(vName, /\\.(docx?|xlsx?|pptx?|pps|potx?)$/i)\n            );\n          },\n          gdocs: function (vType, vName) {\n            return (\n              $h.compare(vType, /(word|excel|powerpoint|office|iwork-pages|tiff?)$/i) ||\n              $h.compare(vName, /\\.(docx?|xlsx?|pptx?|pps|potx?|rtf|ods|odt|pages|ai|dxf|ttf|tiff?|wmf|e?ps)$/i)\n            );\n          },\n          text: function (vType, vName) {\n            return (\n              $h.compare(vType, \"text.*\") ||\n              $h.compare(vName, /\\.(xml|javascript)$/i) ||\n              $h.compare(vName, /\\.(txt|md|nfo|ini|json|php|js|css)$/i)\n            );\n          },\n          video: function (vType, vName) {\n            return (\n              $h.compare(vType, \"video.*\") &&\n              ($h.compare(vType, /(ogg|mp4|mp?g|mov|webm|3gp)$/i) ||\n                $h.compare(vName, /\\.(og?|mp4|webm|mp?g|mov|3gp)$/i))\n            );\n          },\n          audio: function (vType, vName) {\n            return (\n              $h.compare(vType, \"audio.*\") &&\n              ($h.compare(vName, /(ogg|mp3|mp?g|wav)$/i) || $h.compare(vName, /\\.(og?|mp3|mp?g|wav)$/i))\n            );\n          },\n          flash: function (vType, vName) {\n            return $h.compare(vType, \"application/x-shockwave-flash\", true) || $h.compare(vName, /\\.(swf)$/i);\n          },\n          pdf: function (vType, vName) {\n            return $h.compare(vType, \"application/pdf\", true) || $h.compare(vName, /\\.(pdf)$/i);\n          },\n          object: function () {\n            return true;\n          },\n          other: function () {\n            return true;\n          },\n        },\n        fileActionSettings: {\n          showRemove: true,\n          showUpload: true,\n          showDownload: true,\n          showZoom: true,\n          showDrag: true,\n          showRotate: false,\n          removeIcon: '<i class=\"glyphicon glyphicon-trash\"></i>',\n          removeClass: defBtnCss1,\n          removeErrorClass: \"btn btn-sm btn-kv btn-danger\",\n          removeTitle: \"Remove file\",\n          uploadIcon: '<i class=\"glyphicon glyphicon-upload\"></i>',\n          uploadClass: defBtnCss1,\n          uploadTitle: \"Upload file\",\n          uploadRetryIcon: '<i class=\"glyphicon glyphicon-repeat\"></i>',\n          uploadRetryTitle: \"Retry upload\",\n          downloadIcon: '<i class=\"glyphicon glyphicon-download\"></i>',\n          downloadClass: defBtnCss1,\n          downloadTitle: \"Download file\",\n          rotateIcon: '<i class=\"glyphicon glyphicon-repeat\"></i>',\n          rotateClass: defBtnCss1,\n          rotateTitle: \"Rotate 90 deg. clockwise\",\n          zoomIcon: '<i class=\"glyphicon glyphicon-zoom-in\"></i>',\n          zoomClass: defBtnCss1,\n          zoomTitle: \"View Details\",\n          dragIcon: '<i class=\"glyphicon glyphicon-move\"></i>',\n          dragClass: \"text-primary\",\n          dragTitle: \"Move / Rearrange\",\n          dragSettings: {},\n          indicatorNew: '<i class=\"glyphicon glyphicon-plus-sign text-warning\"></i>',\n          indicatorSuccess: '<i class=\"glyphicon glyphicon-ok-sign text-success\"></i>',\n          indicatorError: '<i class=\"glyphicon glyphicon-exclamation-sign text-danger\"></i>',\n          indicatorLoading: '<i class=\"glyphicon glyphicon-hourglass text-muted\"></i>',\n          indicatorPaused: '<i class=\"glyphicon glyphicon-pause text-primary\"></i>',\n          indicatorNewTitle: \"Not uploaded yet\",\n          indicatorSuccessTitle: \"Uploaded\",\n          indicatorErrorTitle: \"Upload Error\",\n          indicatorLoadingTitle: \"Uploading &hellip;\",\n          indicatorPausedTitle: \"Upload Paused\",\n        },\n      };\n      $.each(self.defaults, function (key, setting) {\n        if (key === \"allowedPreviewTypes\") {\n          if (self.allowedPreviewTypes === undefined) {\n            self.allowedPreviewTypes = setting;\n          }\n          return;\n        }\n        self[key] = $.extend(true, {}, setting, self[key]);\n      });\n      self._initPreviewTemplates();\n    },\n    _initPreviewTemplates: function () {\n      var self = this,\n        tags = self.previewMarkupTags,\n        tagBef,\n        tagAft = tags.tagAfter;\n      $.each(self.previewContentTemplates, function (key, value) {\n        if ($h.isEmpty(self.previewTemplates[key])) {\n          tagBef = tags.tagBefore2;\n          if (key === \"generic\" || key === \"image\") {\n            tagBef = tags.tagBefore1;\n          }\n          if (self._isPdfRendered() && key === \"pdf\") {\n            tagBef = tagBef.replace(\"kv-file-content\", \"kv-file-content kv-pdf-rendered\");\n          }\n          self.previewTemplates[key] = tagBef + value + tagAft;\n        }\n      });\n    },\n    _initPreviewCache: function () {\n      var self = this;\n      self.previewCache = {\n        data: {},\n        init: function () {\n          var content = self.initialPreview;\n          if (content.length > 0 && !$h.isArray(content)) {\n            content = content.split(self.initialPreviewDelimiter);\n          }\n          self.previewCache.data = {\n            content: content,\n            config: self.initialPreviewConfig,\n            tags: self.initialPreviewThumbTags,\n          };\n        },\n        count: function (skipNull) {\n          if (!self.previewCache.data || !self.previewCache.data.content) {\n            return 0;\n          }\n          if (skipNull) {\n            var chk = self.previewCache.data.content.filter(function (n) {\n              return n !== null;\n            });\n            return chk.length;\n          }\n          return self.previewCache.data.content.length;\n        },\n        get: function (i, isDisabled) {\n          var ind = $h.INIT_FLAG + i,\n            data = self.previewCache.data,\n            config = data.config[i],\n            content = data.content[i],\n            out,\n            $tmp,\n            cat,\n            ftr,\n            fname,\n            ftype,\n            frameClass,\n            asData = $h.ifSet(\"previewAsData\", config, self.initialPreviewAsData),\n            a = config ? { title: config.title || null, alt: config.alt || null } : { title: null, alt: null },\n            parseTemplate = function (cat, dat, fname, ftype, ftr, ind, fclass, t) {\n              var fc = \" file-preview-initial \" + $h.SORT_CSS + (fclass ? \" \" + fclass : \"\"),\n                id = self.previewInitId + \"-\" + ind,\n                fileId = (config && config.fileId) || id;\n              /** @namespace config.zoomData */\n              return self._generatePreviewTemplate(\n                cat,\n                dat,\n                fname,\n                ftype,\n                id,\n                fileId,\n                false,\n                null,\n                null,\n                fc,\n                ftr,\n                ind,\n                t,\n                a,\n                (config && config.zoomData) || dat\n              );\n            };\n          if (!content || !content.length) {\n            return \"\";\n          }\n          isDisabled = isDisabled === undefined ? true : isDisabled;\n          cat = $h.ifSet(\"type\", config, self.initialPreviewFileType || \"generic\");\n          fname = $h.ifSet(\"filename\", config, $h.ifSet(\"caption\", config));\n          ftype = $h.ifSet(\"filetype\", config, cat);\n          ftr = self.previewCache.footer(i, isDisabled, (config && config.size) || null);\n          frameClass = $h.ifSet(\"frameClass\", config);\n          if (asData) {\n            out = parseTemplate(cat, content, fname, ftype, ftr, ind, frameClass);\n          } else {\n            out = parseTemplate(\"generic\", content, fname, ftype, ftr, ind, frameClass, cat).setTokens({\n              content: data.content[i],\n            });\n          }\n          if (data.tags.length && data.tags[i]) {\n            out = $h.replaceTags(out, data.tags[i]);\n          }\n          /** @namespace config.frameAttr */\n          if (!$h.isEmpty(config) && !$h.isEmpty(config.frameAttr)) {\n            $tmp = $h.createDiv();\n            $h.setHtml($tmp, out);\n            $tmp.find(\".file-preview-initial\").attr(config.frameAttr);\n            out = $tmp.html();\n            $tmp.remove();\n          }\n          return out;\n        },\n        clean: function (data) {\n          data.content = $h.cleanArray(data.content);\n          data.config = $h.cleanArray(data.config);\n          data.tags = $h.cleanArray(data.tags);\n          self.previewCache.data = data;\n        },\n        add: function (content, config, tags, append) {\n          var data = self.previewCache.data,\n            index;\n          if (!content || !content.length) {\n            return 0;\n          }\n          index = content.length - 1;\n          if (!$h.isArray(content)) {\n            content = content.split(self.initialPreviewDelimiter);\n          }\n          if (append && data.content) {\n            index = data.content.push(content[0]) - 1;\n            data.config[index] = config;\n            data.tags[index] = tags;\n          } else {\n            data.content = content;\n            data.config = config;\n            data.tags = tags;\n          }\n          self.previewCache.clean(data);\n          return index;\n        },\n        set: function (content, config, tags, append) {\n          var data = self.previewCache.data,\n            i,\n            chk;\n          if (!content || !content.length) {\n            return;\n          }\n          if (!$h.isArray(content)) {\n            content = content.split(self.initialPreviewDelimiter);\n          }\n          chk = content.filter(function (n) {\n            return n !== null;\n          });\n          if (!chk.length) {\n            return;\n          }\n          if (data.content === undefined) {\n            data.content = [];\n          }\n          if (data.config === undefined) {\n            data.config = [];\n          }\n          if (data.tags === undefined) {\n            data.tags = [];\n          }\n          if (append) {\n            for (i = 0; i < content.length; i++) {\n              if (content[i]) {\n                data.content.push(content[i]);\n              }\n            }\n            for (i = 0; i < config.length; i++) {\n              if (config[i]) {\n                data.config.push(config[i]);\n              }\n            }\n            for (i = 0; i < tags.length; i++) {\n              if (tags[i]) {\n                data.tags.push(tags[i]);\n              }\n            }\n          } else {\n            data.content = content;\n            data.config = config;\n            data.tags = tags;\n          }\n          self.previewCache.clean(data);\n        },\n        unset: function (index) {\n          var chk = self.previewCache.count(),\n            rev = self.reversePreviewOrder;\n          if (!chk) {\n            return;\n          }\n          if (chk === 1) {\n            self.previewCache.data.content = [];\n            self.previewCache.data.config = [];\n            self.previewCache.data.tags = [];\n            self.initialPreview = [];\n            self.initialPreviewConfig = [];\n            self.initialPreviewThumbTags = [];\n            return;\n          }\n          self.previewCache.data.content = $h.spliceArray(self.previewCache.data.content, index, rev);\n          self.previewCache.data.config = $h.spliceArray(self.previewCache.data.config, index, rev);\n          self.previewCache.data.tags = $h.spliceArray(self.previewCache.data.tags, index, rev);\n          var data = $.extend(true, {}, self.previewCache.data);\n          self.previewCache.clean(data);\n        },\n        out: function () {\n          var html = \"\",\n            caption,\n            len = self.previewCache.count(),\n            i,\n            content;\n          if (len === 0) {\n            return { content: \"\", caption: \"\" };\n          }\n          for (i = 0; i < len; i++) {\n            content = self.previewCache.get(i);\n            html = self.reversePreviewOrder ? content + html : html + content;\n          }\n          caption = self._getMsgSelected(len);\n          return { content: html, caption: caption };\n        },\n        footer: function (i, isDisabled, size) {\n          var data = self.previewCache.data || {};\n          if ($h.isEmpty(data.content)) {\n            return \"\";\n          }\n          if ($h.isEmpty(data.config) || $h.isEmpty(data.config[i])) {\n            data.config[i] = {};\n          }\n          isDisabled = isDisabled === undefined ? true : isDisabled;\n          var config = data.config[i],\n            caption = $h.ifSet(\"caption\", config),\n            a,\n            width = $h.ifSet(\"width\", config, \"auto\"),\n            url = $h.ifSet(\"url\", config, false),\n            key = $h.ifSet(\"key\", config, null),\n            fileId = $h.ifSet(\"fileId\", config, null),\n            fs = self.fileActionSettings,\n            initPreviewShowDel = self.initialPreviewShowDelete || false,\n            downloadInitialUrl = !self.initialPreviewDownloadUrl\n              ? \"\"\n              : self.initialPreviewDownloadUrl + \"?key=\" + key + (fileId ? \"&fileId=\" + fileId : \"\"),\n            dUrl = config.downloadUrl || downloadInitialUrl,\n            dFil = config.filename || config.caption || \"\",\n            initPreviewShowDwl = !!dUrl,\n            sDel = $h.ifSet(\"showRemove\", config, initPreviewShowDel),\n            sRot = $h.ifSet(\"showRotate\", config, $h.ifSet(\"showRotate\", fs, true)),\n            sDwl = $h.ifSet(\"showDownload\", config, $h.ifSet(\"showDownload\", fs, initPreviewShowDwl)),\n            sZm = $h.ifSet(\"showZoom\", config, $h.ifSet(\"showZoom\", fs, true)),\n            sDrg = $h.ifSet(\"showDrag\", config, $h.ifSet(\"showDrag\", fs, true)),\n            dis = url === false && isDisabled;\n          sDwl = sDwl && config.downloadUrl !== false && !!dUrl;\n          a = self._renderFileActions(config, false, sDwl, sDel, sRot, sZm, sDrg, dis, url, key, true, dUrl, dFil);\n          return self._getLayoutTemplate(\"footer\").setTokens({\n            progress: self._renderThumbProgress(),\n            actions: a,\n            caption: caption,\n            size: self._getSize(size),\n            width: width,\n            indicator: \"\",\n          });\n        },\n      };\n      self.previewCache.init();\n    },\n    _isPdfRendered: function () {\n      var self = this,\n        useLib = self.usePdfRenderer,\n        flag = typeof useLib === \"function\" ? useLib() : !!useLib;\n      return flag && self.pdfRendererUrl;\n    },\n    _handler: function ($el, event, callback) {\n      var self = this,\n        ns = self.namespace,\n        ev = event.split(\" \").join(ns + \" \") + ns;\n      if (!$el || !$el.length) {\n        return;\n      }\n      $el.off(ev).on(ev, callback);\n    },\n    _encodeURI: function (vUrl) {\n      var self = this;\n      return self.encodeUrl ? encodeURI(vUrl) : vUrl;\n    },\n    _log: function (msg, tokens) {\n      var self = this,\n        id = self.$element.attr(\"id\");\n      if (!self.showConsoleLogs) {\n        return;\n      }\n      if (id) {\n        msg = '\"' + id + '\": ' + msg;\n      }\n      msg = \"bootstrap-fileinput: \" + msg;\n      if (typeof tokens === \"object\") {\n        msg = msg.setTokens(tokens);\n      }\n      if (window.console && typeof window.console.log !== \"undefined\") {\n        window.console.log(msg);\n      } else {\n        window.alert(msg);\n      }\n    },\n    _validate: function () {\n      var self = this,\n        status = self.$element.attr(\"type\") === \"file\";\n      if (!status) {\n        self._log($h.logMessages.badInputType);\n      }\n      return status;\n    },\n    _errorsExist: function () {\n      var self = this,\n        $err,\n        $errList = self.$errorContainer.find(\"li\");\n      if ($errList.length) {\n        return true;\n      }\n      $err = $h.createDiv();\n      $h.setHtml($err, self.$errorContainer.html());\n      $err.find(\".kv-error-close\").remove();\n      $err.find(\"ul\").remove();\n      return !!$h.trim($err.text()).length;\n    },\n    _errorHandler: function (evt, caption) {\n      var self = this,\n        err = evt.target.error,\n        showError = function (msg) {\n          self._showError(msg.replace(\"{name}\", caption));\n        };\n      /** @namespace err.NOT_FOUND_ERR */\n      /** @namespace err.SECURITY_ERR */\n      /** @namespace err.NOT_READABLE_ERR */\n      if (err.code === err.NOT_FOUND_ERR) {\n        showError(self.msgFileNotFound);\n      } else {\n        if (err.code === err.SECURITY_ERR) {\n          showError(self.msgFileSecured);\n        } else {\n          if (err.code === err.NOT_READABLE_ERR) {\n            showError(self.msgFileNotReadable);\n          } else {\n            if (err.code === err.ABORT_ERR) {\n              showError(self.msgFilePreviewAborted);\n            } else {\n              showError(self.msgFilePreviewError);\n            }\n          }\n        }\n      }\n    },\n    _addError: function (msg) {\n      var self = this,\n        $error = self.$errorContainer;\n      if (msg && $error.length) {\n        $h.setHtml($error, self.errorCloseButton + msg);\n        self._handler($error.find(\".kv-error-close\"), \"click\", function () {\n          setTimeout(function () {\n            if (self.showPreview && !self.getFrames().length) {\n              self.clear();\n            }\n            $error.fadeOut(\"slow\");\n          }, self.processDelay);\n        });\n      }\n    },\n    _setValidationError: function (css) {\n      var self = this;\n      css = (css ? css + \" \" : \"\") + \"has-error\";\n      self.$container.removeClass(css).addClass(\"has-error\");\n      $h.addCss(self.$caption, \"is-invalid\");\n    },\n    _resetErrors: function (fade) {\n      var self = this,\n        $error = self.$errorContainer,\n        history = self.resumableUploadOptions.retainErrorHistory;\n      if (self.isPersistentError || (self.enableResumableUpload && history && !self.clearInput)) {\n        return;\n      }\n      self.clearInput = false;\n      self.isError = false;\n      self.$container.removeClass(\"has-error\");\n      self.$caption.removeClass(\"is-invalid is-valid file-processing\");\n      $error.html(\"\");\n      if (fade) {\n        $error.fadeOut(\"slow\");\n      } else {\n        $error.hide();\n      }\n    },\n    _showFolderError: function (folders) {\n      var self = this,\n        $error = self.$errorContainer,\n        msg;\n      if (!folders) {\n        return;\n      }\n      if (!self.isAjaxUpload) {\n        self._clearFileInput();\n      }\n      msg = self.msgFoldersNotAllowed.replace(\"{n}\", folders);\n      self._addError(msg);\n      self._setValidationError();\n      $error.fadeIn(self.fadeDelay);\n      self._raise(\"filefoldererror\", [folders, msg]);\n    },\n    showUserError: function (msg, params, retainErrorHistory) {\n      var self = this,\n        fileName;\n      if (!self.uploadInitiated) {\n        return;\n      }\n      if (!params || !params.fileId) {\n        if (!retainErrorHistory) {\n          self.$errorContainer.html(\"\");\n        }\n      } else {\n        if (!retainErrorHistory) {\n          self.$errorContainer.find('[data-file-id=\"' + params.fileId + '\"]').remove();\n        }\n        fileName = self.fileManager.getFileName(params.fileId);\n        if (fileName) {\n          msg = \"<b>\" + fileName + \":</b> \" + msg;\n        }\n      }\n      self._showFileError(msg, params, \"fileusererror\");\n    },\n    _showFileError: function (msg, params, event) {\n      var self = this,\n        $error = self.$errorContainer,\n        ev = event || \"fileuploaderror\",\n        fId = (params && params.fileId) || \"\",\n        e =\n          params && params.id\n            ? '<li data-thumb-id=\"' + params.id + '\" data-file-id=\"' + fId + '\">' + msg + \"</li>\"\n            : \"<li>\" + msg + \"</li>\";\n\n      if ($error.find(\"ul\").length === 0) {\n        self._addError(\"<ul>\" + e + \"</ul>\");\n      } else {\n        $error.find(\"ul\").append($h.cspBuffer.stash(e));\n        $h.cspBuffer.apply($error);\n      }\n      $error.fadeIn(self.fadeDelay);\n      self._raise(ev, [params, msg]);\n      self._setValidationError(\"file-input-new\");\n      return true;\n    },\n    _showError: function (msg, params, event) {\n      var self = this,\n        $error = self.$errorContainer,\n        ev = event || \"fileerror\";\n      params = params || {};\n      params.reader = self.reader;\n      self._addError(msg);\n      $error.fadeIn(self.fadeDelay);\n      self._raise(ev, [params, msg]);\n      if (!self.isAjaxUpload) {\n        self._clearFileInput();\n      }\n      self._setValidationError(\"file-input-new\");\n      self.$btnUpload.attr(\"disabled\", true);\n      return true;\n    },\n    _noFilesError: function (params) {\n      var self = this,\n        label = self.minFileCount > 1 ? self.filePlural : self.fileSingle,\n        msg = self.msgFilesTooLess.replace(\"{n}\", self.minFileCount).replace(\"{files}\", label),\n        $error = self.$errorContainer;\n      msg = \"<li>\" + msg + \"</li>\";\n      if ($error.find(\"ul\").length === 0) {\n        self._addError(\"<ul>\" + msg + \"</ul>\");\n      } else {\n        $error.find(\"ul\").append(msg);\n      }\n      self.isError = true;\n      self._updateFileDetails(0);\n      $error.fadeIn(self.fadeDelay);\n      self._raise(\"fileerror\", [params, msg]);\n      self._clearFileInput();\n      self._setValidationError();\n    },\n    _parseError: function (operation, jqXHR, errorThrown, fileName) {\n      /** @namespace jqXHR.responseJSON */\n      var self = this,\n        errMsg = $h.trim(errorThrown + \"\"),\n        textPre,\n        errText,\n        text;\n      errText = jqXHR.responseJSON && jqXHR.responseJSON.error ? jqXHR.responseJSON.error.toString() : \"\";\n      text = errText ? errText : jqXHR.responseText;\n      if (self.cancelling && self.msgUploadAborted) {\n        errMsg = self.msgUploadAborted;\n      }\n      if (self.showAjaxErrorDetails && text) {\n        if (errText) {\n          errMsg = $h.trim(errText + \"\");\n        } else {\n          text = $h.trim(text.replace(/\\n\\s*\\n/g, \"\\n\"));\n          textPre = text.length ? \"<pre>\" + text + \"</pre>\" : \"\";\n          errMsg += errMsg ? textPre : text;\n        }\n      }\n      if (!errMsg) {\n        errMsg = self.msgAjaxError.replace(\"{operation}\", operation);\n      }\n      self.cancelling = false;\n      return fileName ? \"<b>\" + fileName + \": </b>\" + errMsg : errMsg;\n    },\n    _parseFileType: function (type, name) {\n      var self = this,\n        isValid,\n        vType,\n        cat,\n        i,\n        types = self.allowedPreviewTypes || [];\n      if (type === \"application/text-plain\") {\n        return \"text\";\n      }\n      for (i = 0; i < types.length; i++) {\n        cat = types[i];\n        isValid = self.fileTypeSettings[cat];\n        vType = isValid(type, name) ? cat : \"\";\n        if (!$h.isEmpty(vType)) {\n          return vType;\n        }\n      }\n      return \"other\";\n    },\n    _getPreviewIcon: function (fname) {\n      var self = this,\n        ext,\n        out = null;\n      if (fname && fname.indexOf(\".\") > -1) {\n        ext = fname.split(\".\").pop();\n        if (self.previewFileIconSettings) {\n          out = self.previewFileIconSettings[ext] || self.previewFileIconSettings[ext.toLowerCase()] || null;\n        }\n        if (self.previewFileExtSettings) {\n          $.each(self.previewFileExtSettings, function (key, func) {\n            if (self.previewFileIconSettings[key] && func(ext)) {\n              out = self.previewFileIconSettings[key];\n              //noinspection UnnecessaryReturnStatementJS\n              return;\n            }\n          });\n        }\n      }\n      return out || self.previewFileIcon;\n    },\n    _parseFilePreviewIcon: function (content, fname) {\n      var self = this,\n        icn = self._getPreviewIcon(fname),\n        out = content;\n      if (out.indexOf(\"{previewFileIcon}\") > -1) {\n        out = out.setTokens({ previewFileIconClass: self.previewFileIconClass, previewFileIcon: icn });\n      }\n      return out;\n    },\n    _raise: function (event, params) {\n      var self = this,\n        e = $.Event(event);\n      if (params !== undefined) {\n        self.$element.trigger(e, params);\n      } else {\n        self.$element.trigger(e);\n      }\n      var out = e.result,\n        isAborted = out === false;\n      if (e.isDefaultPrevented() || isAborted) {\n        return false;\n      }\n      if (e.type === \"filebatchpreupload\" && (out || isAborted)) {\n        self.ajaxAborted = out;\n        return false;\n      }\n      switch (event) {\n        // ignore these events\n        case \"filebatchuploadcomplete\":\n        case \"filebatchuploadsuccess\":\n        case \"fileuploaded\":\n        case \"fileclear\":\n        case \"filecleared\":\n        case \"filereset\":\n        case \"fileerror\":\n        case \"filefoldererror\":\n        case \"filecustomerror\":\n        case \"filesuccessremove\":\n          break;\n        // receive data response via `filecustomerror` event`\n        default:\n          if (!self.ajaxAborted) {\n            self.ajaxAborted = out;\n          }\n          break;\n      }\n      return true;\n    },\n    _listenFullScreen: function (isFullScreen) {\n      var self = this,\n        $modal = self.$modal,\n        $btnFull,\n        $btnBord;\n      if (!$modal || !$modal.length) {\n        return;\n      }\n      $btnFull = $modal && $modal.find(\".btn-kv-fullscreen\");\n      $btnBord = $modal && $modal.find(\".btn-kv-borderless\");\n      if (!$btnFull.length || !$btnBord.length) {\n        return;\n      }\n      $btnFull.removeClass(\"active\").attr(\"aria-pressed\", \"false\");\n      $btnBord.removeClass(\"active\").attr(\"aria-pressed\", \"false\");\n      if (isFullScreen) {\n        $btnFull.addClass(\"active\").attr(\"aria-pressed\", \"true\");\n      } else {\n        $btnBord.addClass(\"active\").attr(\"aria-pressed\", \"true\");\n      }\n      if ($modal.hasClass(\"file-zoom-fullscreen\")) {\n        self._maximizeZoomDialog();\n      } else {\n        if (isFullScreen) {\n          self._maximizeZoomDialog();\n        } else {\n          $btnBord.removeClass(\"active\").attr(\"aria-pressed\", \"false\");\n        }\n      }\n    },\n    _listen: function () {\n      var self = this,\n        $el = self.$element,\n        $form = self.$form,\n        $cont = self.$container,\n        fullScreenEv;\n      self._handler($el, \"click\", function (e) {\n        self._initFileSelected();\n        if ($el.hasClass(\"file-no-browse\")) {\n          if ($el.data(\"zoneClicked\")) {\n            $el.data(\"zoneClicked\", false);\n          } else {\n            e.preventDefault();\n          }\n        }\n      });\n      self._handler($el, \"change\", $.proxy(self._change, self));\n      self._handler(self.$caption, \"paste\", $.proxy(self.paste, self));\n      if (self.showBrowse) {\n        self._handler(self.$btnFile, \"click\", $.proxy(self._browse, self));\n        self._handler(self.$btnFile, \"keypress\", function (e) {\n          var keycode = e.keyCode || e.which;\n          if (keycode === 13) {\n            $el.trigger(\"click\");\n            self._browse(e);\n          }\n        });\n      }\n      self._handler($cont.find(\".fileinput-remove:not([disabled])\"), \"click\", $.proxy(self.clear, self));\n      self._handler($cont.find(\".fileinput-cancel\"), \"click\", $.proxy(self.cancel, self));\n      self._handler($cont.find(\".fileinput-pause\"), \"click\", $.proxy(self.pause, self));\n      self._initDragDrop();\n      self._handler($form, \"reset\", $.proxy(self.clear, self));\n      if (!self.isAjaxUpload) {\n        self._handler($form, \"submit\", $.proxy(self._submitForm, self));\n      }\n      self._handler(self.$container.find(\".fileinput-upload\"), \"click\", $.proxy(self._uploadClick, self));\n      self._handler($(window), \"resize\", function () {\n        self._listenFullScreen(screen.width === window.innerWidth && screen.height === window.innerHeight);\n      });\n      fullScreenEv = \"webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange\";\n      self._handler($(document), fullScreenEv, function () {\n        self._listenFullScreen($h.checkFullScreen());\n      });\n      self.$caption.on(\"focus\", function () {\n        self.$captionContainer.focus();\n      });\n      self._autoFitContent();\n      self._initClickable();\n      self._refreshPreview();\n    },\n    _autoFitContent: function () {\n      var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,\n        self = this,\n        config =\n          width < 400\n            ? self.previewSettingsSmall || self.defaults.previewSettingsSmall\n            : self.previewSettings || self.defaults.previewSettings,\n        sel;\n      $.each(config, function (cat, settings) {\n        sel = \".file-preview-frame .file-preview-\" + cat;\n        self.$preview.find(sel + \".kv-preview-data,\" + sel + \" .kv-preview-data\").css(settings);\n      });\n    },\n    _scanDroppedItems: function (item, files, path) {\n      path = path || \"\";\n      var self = this,\n        i,\n        dirReader,\n        readDir,\n        errorHandler = function (e) {\n          self._log($h.logMessages.badDroppedFiles);\n          self._log(e);\n        };\n      if (item.isFile) {\n        item.file(function (file) {\n          if (path) {\n            file.newPath = path + file.name;\n          }\n          files.push(file);\n        }, errorHandler);\n      } else {\n        if (item.isDirectory) {\n          dirReader = item.createReader();\n          readDir = function () {\n            dirReader.readEntries(function (entries) {\n              if (entries && entries.length > 0) {\n                for (i = 0; i < entries.length; i++) {\n                  self._scanDroppedItems(entries[i], files, path + item.name + \"/\");\n                }\n                // recursively call readDir() again, since browser can only handle first 100 entries.\n                readDir();\n              }\n              return null;\n            }, errorHandler);\n          };\n          readDir();\n        }\n      }\n    },\n    _initDragDrop: function () {\n      var self = this,\n        $zone = self.$dropZone;\n      if (self.dropZoneEnabled && self.showPreview) {\n        self._handler($zone, \"dragenter dragover\", $.proxy(self._zoneDragEnter, self));\n        self._handler($zone, \"dragleave\", $.proxy(self._zoneDragLeave, self));\n        self._handler($zone, \"drop\", $.proxy(self._zoneDrop, self));\n        self._handler($(document), \"dragenter dragover drop\", self._zoneDragDropInit);\n      }\n    },\n    _zoneDragDropInit: function (e) {\n      e.stopPropagation();\n      e.preventDefault();\n    },\n    _zoneDragEnter: function (e) {\n      var self = this,\n        dt = e.originalEvent.dataTransfer,\n        hasFiles = $.inArray(\"Files\", dt.types) > -1;\n      self._zoneDragDropInit(e);\n      if (self.isDisabled || !hasFiles) {\n        dt.effectAllowed = \"none\";\n        dt.dropEffect = \"none\";\n        return;\n      }\n      dt.dropEffect = \"copy\";\n      if (self._raise(\"fileDragEnter\", { sourceEvent: e, files: dt.types.Files })) {\n        $h.addCss(self.$dropZone, \"file-highlighted\");\n      }\n    },\n    _zoneDragLeave: function (e) {\n      var self = this;\n      self._zoneDragDropInit(e);\n      if (self.isDisabled) {\n        return;\n      }\n      if (self._raise(\"fileDragLeave\", { sourceEvent: e })) {\n        self.$dropZone.removeClass(\"file-highlighted\");\n      }\n    },\n    _dropFiles: function (e, files) {\n      var self = this,\n        $el = self.$element;\n      if (!self.isAjaxUpload) {\n        self.changeTriggered = true;\n        $el.get(0).files = files;\n        setTimeout(function () {\n          self.changeTriggered = false;\n          $el.trigger(\"change\" + self.namespace);\n        }, self.processDelay);\n      } else {\n        self._change(e, files);\n      }\n      self.$dropZone.removeClass(\"file-highlighted\");\n    },\n    _addFilesFromSystem: function (e, dt, type) {\n      var self = this,\n        files = dt.files,\n        items = dt.items,\n        folders = $h.getDragDropFolders(items);\n      e.preventDefault();\n      if (self.isDisabled || $h.isEmpty(files) || !files.length) {\n        console.log(\"No valid copied files found in clipboard for pasting.\");\n        return;\n      }\n      if (!self._raise(type, { sourceEvent: e, files: files })) {\n        return;\n      }\n      if (folders > 0) {\n        if (!self.isAjaxUpload) {\n          self._showFolderError(folders);\n          return;\n        }\n        files = [];\n        for (i = 0; i < items.length; i++) {\n          var item = items[i].webkitGetAsEntry();\n          if (item) {\n            self._scanDroppedItems(item, files);\n          }\n        }\n        setTimeout(function () {\n          self._dropFiles(e, files);\n        }, 500);\n      } else {\n        self._dropFiles(e, files);\n      }\n    },\n    _zoneDrop: function (e) {\n      /** @namespace e.originalEvent.dataTransfer */\n      var self = this,\n        i,\n        $el = self.$element,\n        dt = e.originalEvent.dataTransfer;\n      self._addFilesFromSystem(e, dt, \"fileDragDrop\");\n    },\n    _uploadClick: function (e) {\n      var self = this,\n        $btn = self.$container.find(\".fileinput-upload\"),\n        $form,\n        isEnabled = !$btn.hasClass(\"disabled\") && $h.isEmpty($btn.attr(\"disabled\"));\n      if (e && e.isDefaultPrevented()) {\n        return;\n      }\n      if (!self.isAjaxUpload) {\n        if (isEnabled && $btn.attr(\"type\") !== \"submit\") {\n          e.preventDefault();\n          $form = $btn.closest(\"form\");\n          // downgrade to normal form submit if possible\n          if ($form.length) {\n            $form.trigger(\"submit\");\n          }\n        }\n        return;\n      }\n      e.preventDefault();\n      if (isEnabled) {\n        self.upload();\n      }\n    },\n    _submitForm: function () {\n      var self = this;\n      return self._isFileSelectionValid() && !self._abort({});\n    },\n    _clearPreview: function () {\n      var self = this,\n        $thumbs = self.showUploadedThumbs ? self.getFrames(\":not(.file-preview-success)\") : self.getFrames();\n      $thumbs.each(function () {\n        var $thumb = $(this);\n        $thumb.remove();\n      });\n      if (!self.getFrames().length || !self.showPreview) {\n        self._resetUpload();\n      }\n      self._validateDefaultPreview();\n    },\n    _initSortable: function () {\n      var self = this,\n        $el = self.$preview,\n        settings,\n        selector = \".\" + $h.SORT_CSS,\n        $cont,\n        $body = $(\"body\"),\n        $html = $(\"html\"),\n        rev = self.reversePreviewOrder,\n        Sortable = window.Sortable,\n        beginGrab,\n        endGrab;\n      if (!Sortable || $el.find(selector).length === 0) {\n        return;\n      }\n      $cont = $body.length ? $body : $html.length ? $html : self.$container;\n      beginGrab = function () {\n        $cont.addClass(\"file-grabbing\");\n      };\n      endGrab = function () {\n        $cont.removeClass(\"file-grabbing\");\n      };\n      settings = {\n        handle: \".drag-handle-init\",\n        dataIdAttr: \"data-fileid\",\n        animation: 600,\n        draggable: selector,\n        scroll: false,\n        forceFallback: true,\n        onChoose: beginGrab,\n        onStart: beginGrab,\n        onUnchoose: endGrab,\n        onEnd: endGrab,\n        onSort: function (e) {\n          var oldIndex = e.oldIndex,\n            newIndex = e.newIndex,\n            i = 0,\n            len = self.initialPreviewConfig.length,\n            exceedsLast = len > 0 && newIndex >= len,\n            $item = $(e.item),\n            $first;\n          if (exceedsLast) {\n            newIndex = len - 1;\n          }\n          self.initialPreview = $h.moveArray(self.initialPreview, oldIndex, newIndex, rev);\n          self.initialPreviewConfig = $h.moveArray(self.initialPreviewConfig, oldIndex, newIndex, rev);\n          self.previewCache.init();\n          self.getFrames(\".file-preview-initial\").each(function () {\n            $(this).attr(\"data-fileindex\", $h.INIT_FLAG + i);\n            i++;\n          });\n          if (exceedsLast) {\n            $first = self.getFrames(\":not(.file-preview-initial):first\");\n            if ($first.length) {\n              $item.slideUp(function () {\n                $item.insertBefore($first).slideDown();\n              });\n            }\n          }\n          self._raise(\"filesorted\", {\n            previewId: $item.attr(\"id\"),\n            oldIndex: oldIndex,\n            newIndex: newIndex,\n            stack: self.initialPreviewConfig,\n          });\n        },\n      };\n      $.extend(true, settings, self.fileActionSettings.dragSettings);\n      if (self.sortable) {\n        self.sortable.destroy();\n      }\n      self.sortable = Sortable.create($el[0], settings);\n    },\n    _setPreviewContent: function (content) {\n      var self = this;\n      $h.setHtml(self.$preview, content);\n      self._autoFitContent();\n    },\n    _initPreviewImageOrientations: function () {\n      var self = this,\n        i = 0,\n        canOrientImage = self.canOrientImage;\n      if (!self.autoOrientImageInitial && !canOrientImage) {\n        return;\n      }\n      self.getFrames(\".file-preview-initial\").each(function () {\n        var $thumb = $(this),\n          $img,\n          $zoomImg,\n          id,\n          config = self.initialPreviewConfig[i];\n        /** @namespace config.exif */\n        if (config && config.exif && config.exif.Orientation) {\n          id = $thumb.attr(\"id\");\n          $img = $thumb.find(\">.kv-file-content img\");\n          $zoomImg = self._getZoom(id, \" >.kv-file-content img\");\n          if (canOrientImage) {\n            $img.css(\"image-orientation\", self.autoOrientImageInitial ? \"from-image\" : \"none\");\n          } else {\n            self.setImageOrientation($img, $zoomImg, config.exif.Orientation, $thumb);\n          }\n        }\n        i++;\n      });\n    },\n    _initPreview: function (isInit) {\n      var self = this,\n        cap = self.initialCaption || \"\",\n        out;\n      if (!self.previewCache.count(true)) {\n        self._clearPreview();\n        if (isInit) {\n          self._setCaption(cap);\n        } else {\n          self._initCaption();\n        }\n        return;\n      }\n      out = self.previewCache.out();\n      cap = isInit && self.initialCaption ? self.initialCaption : out.caption;\n      self._setPreviewContent(out.content);\n      self._setInitThumbAttr();\n      self._setCaption(cap);\n      self._initSortable();\n      if (!$h.isEmpty(out.content)) {\n        self.$container.removeClass(\"file-input-new\");\n      }\n      self._initPreviewImageOrientations();\n    },\n    _getZoomButton: function (type) {\n      var self = this,\n        label = self.previewZoomButtonIcons[type],\n        css = self.previewZoomButtonClasses[type],\n        title = ' title=\"' + (self.previewZoomButtonTitles[type] || \"\") + '\" ',\n        tag = $h.isBs(5) ? \"bs-\" : \"\",\n        params = title + (type === \"close\" ? \" data-\" + tag + 'dismiss=\"modal\" aria-hidden=\"true\"' : \"\");\n      if (type === \"fullscreen\" || type === \"borderless\" || type === \"toggleheader\") {\n        params += ' data-toggle=\"button\" aria-pressed=\"false\"';\n      }\n      return '<button type=\"button\" class=\"' + css + \" btn-kv-\" + type + '\"' + params + \">\" + label + \"</button>\";\n    },\n    _getModalContent: function () {\n      var self = this;\n      return self._getLayoutTemplate(\"modal\").setTokens({\n        rtl: self.rtl ? \" kv-rtl\" : \"\",\n        zoomFrameClass: self.frameClass,\n        prev: self._getZoomButton(\"prev\"),\n        next: self._getZoomButton(\"next\"),\n        rotate: self._getZoomButton(\"rotate\"),\n        toggleheader: self._getZoomButton(\"toggleheader\"),\n        fullscreen: self._getZoomButton(\"fullscreen\"),\n        borderless: self._getZoomButton(\"borderless\"),\n        close: self._getZoomButton(\"close\"),\n      });\n    },\n    _listenModalEvent: function (event) {\n      var self = this,\n        $modal = self.$modal,\n        getParams = function (e) {\n          return {\n            sourceEvent: e,\n            previewId: $modal.data(\"previewId\"),\n            modal: $modal,\n          };\n        };\n      $modal.on(event + \".bs.modal\", function (e) {\n        if (e.namespace !== \"bs.modal\") {\n          return;\n        }\n        var $btnFull = $modal.find(\".btn-fullscreen\"),\n          $btnBord = $modal.find(\".btn-borderless\");\n        if ($modal.data(\"fileinputPluginId\") === self.$element.attr(\"id\")) {\n          self._raise(\"filezoom\" + event, getParams(e));\n        }\n        if (event === \"shown\") {\n          self._handleRotation($modal, $modal.find(\".file-zoom-detail\"), $modal.data(\"angle\"));\n          $btnBord.removeClass(\"active\").attr(\"aria-pressed\", \"false\");\n          $btnFull.removeClass(\"active\").attr(\"aria-pressed\", \"false\");\n          if ($modal.hasClass(\"file-zoom-fullscreen\")) {\n            self._maximizeZoomDialog();\n            if ($h.checkFullScreen()) {\n              $btnFull.addClass(\"active\").attr(\"aria-pressed\", \"true\");\n            } else {\n              $btnBord.addClass(\"active\").attr(\"aria-pressed\", \"true\");\n            }\n          }\n        }\n      });\n    },\n    _initZoom: function () {\n      var self = this,\n        $dialog,\n        modalMain = self._getLayoutTemplate(\"modalMain\"),\n        modalId = \"#\" + $h.MODAL_ID;\n      modalMain = self._setTabIndex(\"modal\", modalMain);\n      if (!self.showPreview) {\n        return;\n      }\n      self.$modal = $(modalId);\n      if (!self.$modal || !self.$modal.length) {\n        $dialog = $h.createElement($h.cspBuffer.stash(modalMain)).insertAfter(self.$container);\n        self.$modal = $(modalId).insertBefore($dialog);\n        $h.cspBuffer.apply(self.$modal);\n        $dialog.remove();\n      }\n      $h.initModal(self.$modal);\n      self.$modal.html($h.cspBuffer.stash(self._getModalContent()));\n      $h.cspBuffer.apply(self.$modal);\n      $.each($h.MODAL_EVENTS, function (key, event) {\n        self._listenModalEvent(event);\n      });\n    },\n    _initZoomButtons: function () {\n      var self = this,\n        $modal = self.$modal,\n        previewId = $modal.data(\"previewId\") || \"\",\n        $first,\n        $last,\n        thumbs = self.getFrames().toArray(),\n        len = thumbs.length,\n        $prev = $modal.find(\".btn-kv-prev\"),\n        $next = $modal.find(\".btn-kv-next\"),\n        $rotate = $modal.find(\".btn-kv-rotate\");\n      if (thumbs.length < 2) {\n        $prev.hide();\n        $next.hide();\n        return;\n      } else {\n        $prev.show();\n        $next.show();\n      }\n      if (!len) {\n        return;\n      }\n      $first = $(thumbs[0]);\n      $last = $(thumbs[len - 1]);\n      $prev.removeAttr(\"disabled\");\n      $next.removeAttr(\"disabled\");\n      if (self.reversePreviewOrder) {\n        [$prev, $next] = [$next, $prev]; // swap\n      }\n      if ($first.length && $first.attr(\"id\") === previewId) {\n        $prev.attr(\"disabled\", true);\n      }\n      if ($last.length && $last.attr(\"id\") === previewId) {\n        $next.attr(\"disabled\", true);\n      }\n    },\n    _maximizeZoomDialog: function () {\n      var self = this,\n        $modal = self.$modal,\n        $head = $modal.find(\".modal-header:visible\"),\n        $foot = $modal.find(\".modal-footer:visible\"),\n        $body = $modal.find(\".kv-zoom-body\"),\n        h = $(window).height(),\n        diff = 0;\n      $modal.addClass(\"file-zoom-fullscreen\");\n      if ($head && $head.length) {\n        h -= $head.outerHeight(true);\n      }\n      if ($foot && $foot.length) {\n        h -= $foot.outerHeight(true);\n      }\n      if ($body && $body.length) {\n        diff = $body.outerHeight(true) - $body.height();\n        h -= diff;\n      }\n      $modal.find(\".kv-zoom-body\").height(h);\n    },\n    _resizeZoomDialog: function (fullScreen) {\n      var self = this,\n        $modal = self.$modal,\n        $btnFull = $modal.find(\".btn-kv-fullscreen\"),\n        $btnBord = $modal.find(\".btn-kv-borderless\");\n      if ($modal.hasClass(\"file-zoom-fullscreen\")) {\n        $h.toggleFullScreen(false);\n        if (!fullScreen) {\n          if (!$btnFull.hasClass(\"active\")) {\n            $modal.removeClass(\"file-zoom-fullscreen\");\n            self.$modal.find(\".kv-zoom-body\").css(\"height\", self.zoomModalHeight);\n          } else {\n            $btnFull.removeClass(\"active\").attr(\"aria-pressed\", \"false\");\n          }\n        } else {\n          if (!$btnFull.hasClass(\"active\")) {\n            $modal.removeClass(\"file-zoom-fullscreen\");\n            self._resizeZoomDialog(true);\n            if ($btnBord.hasClass(\"active\")) {\n              $btnBord.removeClass(\"active\").attr(\"aria-pressed\", \"false\");\n            }\n          }\n        }\n      } else {\n        if (!fullScreen) {\n          self._maximizeZoomDialog();\n          return;\n        }\n        $h.toggleFullScreen(true);\n      }\n      $modal.focus();\n    },\n    _setZoomContent: function ($frame, navigate) {\n      var self = this,\n        $content,\n        tmplt,\n        body,\n        $body,\n        $dataEl,\n        config,\n        previewId = $frame.attr(\"id\"),\n        $zoomPreview = self._getZoom(previewId),\n        $modal = self.$modal,\n        $tmp,\n        desc,\n        $desc,\n        $btnFull = $modal.find(\".btn-kv-fullscreen\"),\n        $btnBord = $modal.find(\".btn-kv-borderless\"),\n        cap,\n        size,\n        $btnTogh = $modal.find(\".btn-kv-toggleheader\"),\n        parsed,\n        zoomData = $frame.data(\"zoom\");\n      if (zoomData) {\n        zoomData = decodeURIComponent(zoomData);\n        parsed = $zoomPreview.html().replace(self.zoomPlaceholder, \"\").setTokens({ zoomData: zoomData });\n        $h.setHtml($zoomPreview, parsed);\n        $frame.data(\"zoom\", \"\");\n        $zoomPreview.attr(\"data-zoom\", zoomData);\n      }\n      tmplt = $zoomPreview.attr(\"data-template\") || \"generic\";\n      $content = $zoomPreview.find(\".kv-file-content\");\n      body = $content.length ? $content.html() : \"\";\n      cap = $frame.data(\"caption\") || self.msgZoomModalHeading;\n      size = $frame.data(\"size\") || \"\";\n      desc = $frame.data(\"description\") || \"\";\n      $h.setHtml($modal.find(\".kv-zoom-caption\").attr(\"title\", cap), cap);\n      $h.setHtml($modal.find(\".kv-zoom-size\"), size);\n      $desc = $modal.find(\".kv-zoom-description\").hide();\n      if (desc) {\n        if (self.showDescriptionClose) {\n          desc =\n            self._getLayoutTemplate(\"descriptionClose\").setTokens({\n              closeIcon: self.previewZoomButtonIcons.close,\n            }) +\n            \"</button>\" +\n            desc;\n        }\n        $h.setHtml($desc, desc).show();\n        if (self.showDescriptionClose) {\n          self._handler($modal.find(\".kv-desc-hide\"), \"click\", function () {\n            $(this)\n              .parent()\n              .fadeOut(\"fast\", function () {\n                $modal.focus();\n              });\n          });\n        }\n      }\n      $body = $modal.find(\".kv-zoom-body\");\n      $modal.removeClass(\"kv-single-content\");\n      if (navigate) {\n        $tmp = $body.addClass(\"file-thumb-loading\").clone().insertAfter($body);\n        $h.setHtml($body, body).hide();\n        $tmp.fadeOut(\"fast\", function () {\n          $body.fadeIn(\"fast\", function () {\n            $body.removeClass(\"file-thumb-loading\");\n          });\n          $tmp.remove();\n        });\n      } else {\n        $h.setHtml($body, body);\n      }\n      config = self.previewZoomSettings[tmplt];\n      if (config) {\n        $dataEl = $body.find(\".kv-preview-data\");\n        $h.addCss($dataEl, \"file-zoom-detail\");\n        $.each(config, function (key, value) {\n          $dataEl.css(key, value);\n          if (($dataEl.attr(\"width\") && key === \"width\") || ($dataEl.attr(\"height\") && key === \"height\")) {\n            $dataEl.removeAttr(key);\n          }\n        });\n      }\n      $modal.data(\"previewId\", previewId);\n      self._handler($modal.find(\".btn-kv-prev\"), \"click\", function () {\n        self._zoomSlideShow(\"prev\", previewId);\n      });\n      self._handler($modal.find(\".btn-kv-next\"), \"click\", function () {\n        self._zoomSlideShow(\"next\", previewId);\n      });\n      self._handler($btnFull, \"click\", function () {\n        self._resizeZoomDialog(true);\n      });\n      self._handler($btnBord, \"click\", function () {\n        self._resizeZoomDialog(false);\n      });\n      self._handler($btnTogh, \"click\", function () {\n        var $header = $modal.find(\".modal-header\"),\n          $floatBar = $modal.find(\".floating-buttons\"),\n          ht,\n          $actions = $header.find(\".kv-zoom-actions\"),\n          resize = function (height) {\n            var $body = self.$modal.find(\".kv-zoom-body\"),\n              h = self.zoomModalHeight;\n            if ($modal.hasClass(\"file-zoom-fullscreen\")) {\n              h = $body.outerHeight(true);\n              if (!height) {\n                h = h - $header.outerHeight(true);\n              }\n            }\n            $body.css(\"height\", height ? h + height : h);\n          };\n        if ($header.is(\":visible\")) {\n          ht = $header.outerHeight(true);\n          $header.slideUp(\"slow\", function () {\n            $actions.find(\".btn\").appendTo($floatBar);\n            resize(ht);\n          });\n        } else {\n          $floatBar.find(\".btn\").appendTo($actions);\n          $header.slideDown(\"slow\", function () {\n            resize();\n          });\n        }\n        $modal.focus();\n      });\n      self._handler($modal, \"keydown\", function (e) {\n        var key = e.which || e.keyCode,\n          delay = self.processDelay + 1,\n          $prev = $(this).find(\".btn-kv-prev\"),\n          $next = $(this).find(\".btn-kv-next\"),\n          vId = $(this).data(\"previewId\"),\n          vPrevKey,\n          vNextKey;\n        [vPrevKey, vNextKey] = self.rtl ? [39, 37] : [37, 39];\n        $.each({ prev: [$prev, vPrevKey], next: [$next, vNextKey] }, function (direction, config) {\n          var $btn = config[0],\n            vKey = config[1];\n          if (key === vKey && $btn.length) {\n            $modal.focus();\n            if (!$btn.attr(\"disabled\")) {\n              $btn.blur();\n              setTimeout(function () {\n                $btn.focus();\n                self._zoomSlideShow(direction, vId);\n                setTimeout(function () {\n                  if ($btn.attr(\"disabled\")) {\n                    $modal.focus();\n                  }\n                }, delay);\n              }, delay);\n            }\n          }\n        });\n      });\n    },\n    _showModal: function ($frame) {\n      var self = this,\n        $modal = self.$modal,\n        $content,\n        css,\n        angle;\n      if (!$frame || !$frame.length) {\n        return;\n      }\n      $h.initModal($modal);\n      $h.setHtml($modal, self._getModalContent());\n      self._setZoomContent($frame);\n      $modal.removeClass(\"rotatable\");\n      $modal.data({ backdrop: false, fileinputPluginId: self.$element.attr(\"id\") });\n      $modal.find(\".kv-zoom-body\").css(\"height\", self.zoomModalHeight);\n      $content = $frame.find(\".kv-file-content > :first-child\");\n      if ($content.length) {\n        css = $content.css(\"transform\");\n        if (css) {\n          $modal.find(\".file-zoom-detail\").css(\"transform\", css);\n        }\n      }\n      if ($frame.hasClass(\"rotatable\")) {\n        $modal.addClass(\"rotatable\");\n      }\n      if ($frame.data(\"angle\")) {\n        $modal.data(\"angle\", $frame.data(\"angle\"));\n      }\n      angle = $frame.data(\"angle\") || 0;\n      $modal.modal(\"show\");\n      self._initZoomButtons();\n      self._initRotateZoom($frame, $content);\n    },\n    _zoomPreview: function ($btn) {\n      var self = this,\n        $frame;\n      if (!$btn.length) {\n        throw \"Cannot zoom to detailed preview!\";\n      }\n      $frame = $btn.closest($h.FRAMES);\n      self._showModal($frame);\n    },\n    _zoomSlideShow: function (dir, previewId) {\n      var self = this,\n        $modal = self.$modal,\n        $btn = $modal.find(\".kv-zoom-actions .btn-kv-\" + dir),\n        $targFrame,\n        i,\n        $thumb,\n        thumbsData = self.getFrames().toArray(),\n        thumbs = [],\n        len = thumbsData.length,\n        out,\n        angle,\n        $content;\n      if (self.reversePreviewOrder) {\n        dir = dir === \"prev\" ? \"next\" : \"prev\";\n      }\n      if ($btn.attr(\"disabled\")) {\n        return;\n      }\n      for (i = 0; i < len; i++) {\n        $thumb = $(thumbsData[i]);\n        if ($thumb && $thumb.length && $thumb.find(\".kv-file-zoom:visible\").length) {\n          thumbs.push(thumbsData[i]);\n        }\n      }\n      len = thumbs.length;\n      for (i = 0; i < len; i++) {\n        if ($(thumbs[i]).attr(\"id\") === previewId) {\n          out = dir === \"prev\" ? i - 1 : i + 1;\n          break;\n        }\n      }\n      if (out < 0 || out >= len || !thumbs[out]) {\n        return;\n      }\n      $targFrame = $(thumbs[out]);\n      if ($targFrame.length) {\n        self._setZoomContent($targFrame, dir);\n      }\n      self._initZoomButtons();\n      if ($targFrame.length && $targFrame.hasClass(\"rotatable\")) {\n        angle = $targFrame.data(\"angle\") || 0;\n        $modal.addClass(\"rotatable\").data(\"angle\", angle);\n        $content = $targFrame.find(\".kv-file-content > :first-child\");\n        self._initRotateZoom($targFrame, $content);\n      } else {\n        $modal.removeClass(\"rotatable\").removeData(\"angle\");\n      }\n      self._raise(\"filezoom\" + dir, { previewId: previewId, modal: self.$modal });\n    },\n    _initZoomButton: function () {\n      var self = this;\n      self.$preview.find(\".kv-file-zoom\").each(function () {\n        var $el = $(this);\n        self._handler($el, \"click\", function () {\n          self._zoomPreview($el);\n        });\n      });\n    },\n    _inputFileCount: function () {\n      return this.$element[0].files.length;\n    },\n    _refreshPreview: function () {\n      var self = this,\n        files;\n      if ((!self._inputFileCount() && !self.isAjaxUpload) || !self.showPreview || !self.isPreviewable) {\n        return;\n      }\n      if (self.isAjaxUpload) {\n        if (self.fileManager.count() > 0) {\n          files = $.extend(true, [], self.getFileList());\n          self.fileManager.clear();\n          self._clearFileInput();\n        } else {\n          files = self.$element[0].files;\n        }\n      } else {\n        files = self.$element[0].files;\n      }\n      if (files && files.length) {\n        self.readFiles(files);\n      }\n    },\n    _clearObjects: function ($el) {\n      $el.find(\"video audio\").each(function () {\n        this.pause();\n        $(this).remove();\n      });\n      $el.find(\"img object div\").each(function () {\n        $(this).remove();\n      });\n    },\n    _clearFileInput: function () {\n      var self = this,\n        $el = self.$element,\n        $srcFrm,\n        $tmpFrm,\n        $tmpEl;\n      if (!self._inputFileCount()) {\n        return;\n      }\n      $srcFrm = $el.closest(\"form\");\n      $tmpFrm = $(document.createElement(\"form\"));\n      $tmpEl = $(document.createElement(\"div\"));\n      $el.before($tmpEl);\n      if ($srcFrm.length) {\n        $srcFrm.after($tmpFrm);\n      } else {\n        $tmpEl.after($tmpFrm);\n      }\n      $tmpFrm.append($el).trigger(\"reset\");\n      $tmpEl.before($el).remove();\n      $tmpFrm.remove();\n    },\n    _resetUpload: function () {\n      var self = this;\n      self.uploadInitiated = false;\n      self.uploadStartTime = $h.now();\n      self.uploadCache = [];\n      self.$btnUpload.removeAttr(\"disabled\");\n      self._setProgress(0);\n      self._hideProgress();\n      self._resetErrors(false);\n      self._initAjax();\n      self.fileManager.clearImages();\n      self._resetCanvas();\n      if (self.overwriteInitial) {\n        self.initialPreview = [];\n        self.initialPreviewConfig = [];\n        self.initialPreviewThumbTags = [];\n        self.previewCache.data = {\n          content: [],\n          config: [],\n          tags: [],\n        };\n      }\n    },\n    _resetCanvas: function () {\n      var self = this;\n      if (self.imageCanvas && self.imageCanvasContext) {\n        self.imageCanvasContext.clearRect(0, 0, self.imageCanvas.width, self.imageCanvas.height);\n      }\n    },\n    _hasInitialPreview: function () {\n      var self = this;\n      return !self.overwriteInitial && self.previewCache.count(true);\n    },\n    _resetPreview: function () {\n      var self = this,\n        out,\n        cap,\n        $div,\n        hasSuc = self.showUploadedThumbs,\n        hasErr = !self.removeFromPreviewOnError,\n        includeProcessed = (hasSuc || hasErr) && self.isDuplicateError;\n      if (self.previewCache.count(true)) {\n        out = self.previewCache.out();\n        if (includeProcessed) {\n          $div = $h.createDiv().insertAfter(self.$container);\n          self.getFrames().each(function () {\n            var $thumb = $(this);\n            if (\n              (hasSuc && $thumb.hasClass(\"file-preview-success\")) ||\n              (hasErr && $thumb.hasClass(\"file-preview-error\"))\n            ) {\n              $div.append($thumb);\n            }\n          });\n        }\n        self._setPreviewContent(out.content);\n        self._setInitThumbAttr();\n        cap = self.initialCaption ? self.initialCaption : out.caption;\n        self._setCaption(cap);\n        if (includeProcessed) {\n          $div.contents().appendTo(self.$preview);\n          $div.remove();\n        }\n      } else {\n        self._clearPreview();\n        self._initCaption();\n      }\n      if (self.showPreview) {\n        self._initZoom();\n        self._initSortable();\n      }\n      self.isDuplicateError = false;\n    },\n    _clearDefaultPreview: function () {\n      var self = this;\n      self.$preview.find(\".file-default-preview\").remove();\n    },\n    _validateDefaultPreview: function () {\n      var self = this;\n      if (!self.showPreview || $h.isEmpty(self.defaultPreviewContent)) {\n        return;\n      }\n      self._setPreviewContent('<div class=\"file-default-preview\">' + self.defaultPreviewContent + \"</div>\");\n      self.$container.removeClass(\"file-input-new\");\n      self._initClickable();\n    },\n    _resetPreviewThumbs: function (isAjax) {\n      var self = this,\n        out;\n      if (isAjax) {\n        self._clearPreview();\n        self.clearFileStack();\n        return;\n      }\n      if (self._hasInitialPreview()) {\n        out = self.previewCache.out();\n        self._setPreviewContent(out.content);\n        self._setInitThumbAttr();\n        self._setCaption(out.caption);\n        self._initPreviewActions();\n      } else {\n        self._clearPreview();\n      }\n    },\n    _getLayoutTemplate: function (t) {\n      var self = this,\n        template = self.layoutTemplates[t];\n      if ($h.isEmpty(self.customLayoutTags)) {\n        return template;\n      }\n      return $h.replaceTags(template, self.customLayoutTags);\n    },\n    _getPreviewTemplate: function (t) {\n      var self = this,\n        templates = self.previewTemplates,\n        template = templates[t] || templates.other;\n      if ($h.isEmpty(self.customPreviewTags)) {\n        return template;\n      }\n      return $h.replaceTags(template, self.customPreviewTags);\n    },\n    _getOutData: function (formdata, jqXHR, responseData, filesData) {\n      var self = this;\n      jqXHR = jqXHR || {};\n      responseData = responseData || {};\n      filesData = filesData || self.fileManager.list();\n      return {\n        formdata: formdata,\n        files: filesData,\n        filenames: self.filenames,\n        filescount: self.getFilesCount(),\n        extra: self._getExtraData(),\n        response: responseData,\n        reader: self.reader,\n        jqXHR: jqXHR,\n      };\n    },\n    _getMsgSelected: function (n, processing) {\n      var self = this,\n        strFiles = n === 1 ? self.fileSingle : self.filePlural;\n      return n > 0\n        ? self.msgSelected.replace(\"{n}\", n).replace(\"{files}\", strFiles)\n        : processing\n        ? self.msgProcessing\n        : self.msgNoFilesSelected;\n    },\n    _getFrame: function (id, skipWarning) {\n      var self = this,\n        $frame = $h.getFrameElement(self.$preview, id);\n      if (self.showPreview && !skipWarning && !$frame.length) {\n        self._log($h.logMessages.invalidThumb, { id: id });\n      }\n      return $frame;\n    },\n    _getZoom: function (id, selector) {\n      var self = this,\n        $frame = $h.getZoomElement(self.$preview, id, selector);\n      if (self.showPreview && !$frame.length) {\n        self._log($h.logMessages.invalidThumb, { id: id });\n      }\n      return $frame;\n    },\n    _getThumbs: function (css) {\n      css = css || \"\";\n      return this.getFrames(\":not(.file-preview-initial)\" + css);\n    },\n    _getThumbId: function (fileId) {\n      var self = this;\n      return self.previewInitId + \"-\" + fileId;\n    },\n    _getExtraData: function (fileId, index) {\n      var self = this,\n        data = self.uploadExtraData;\n      if (typeof self.uploadExtraData === \"function\") {\n        data = self.uploadExtraData(fileId, index);\n      }\n      return data;\n    },\n    _initXhr: function (xhrobj, fileId) {\n      var self = this,\n        fm = self.fileManager,\n        func = function (event) {\n          var pct = 0,\n            total = event.total,\n            loaded = event.loaded || event.position,\n            stats = fm.getUploadStats(fileId, loaded, total);\n          /** @namespace event.lengthComputable */\n          if (event.lengthComputable && !self.enableResumableUpload) {\n            pct = $h.round((loaded / total) * 100);\n          }\n          if (fileId) {\n            self._setFileUploadStats(fileId, pct, stats);\n          } else {\n            self._setProgress(pct, null, null, self._getStats(stats));\n          }\n          self._raise(\"fileajaxprogress\", [stats]);\n        };\n      if (xhrobj.upload) {\n        if (self.progressDelay) {\n          func = $h.debounce(func, self.progressDelay);\n        }\n        xhrobj.upload.addEventListener(\"progress\", func, false);\n      }\n      return xhrobj;\n    },\n    _initAjaxSettings: function () {\n      var self = this;\n      self._ajaxSettings = $.extend(true, {}, self.ajaxSettings);\n      self._ajaxDeleteSettings = $.extend(true, {}, self.ajaxDeleteSettings);\n    },\n    _mergeAjaxCallback: function (funcName, srcFunc, type) {\n      var self = this,\n        settings = self._ajaxSettings,\n        flag = self.mergeAjaxCallbacks,\n        targFunc;\n      if (type === \"delete\") {\n        settings = self._ajaxDeleteSettings;\n        flag = self.mergeAjaxDeleteCallbacks;\n      }\n      targFunc = settings[funcName];\n      if (flag && typeof targFunc === \"function\") {\n        if (flag === \"before\") {\n          settings[funcName] = function () {\n            targFunc.apply(this, arguments);\n            srcFunc.apply(this, arguments);\n          };\n        } else {\n          settings[funcName] = function () {\n            srcFunc.apply(this, arguments);\n            targFunc.apply(this, arguments);\n          };\n        }\n      } else {\n        settings[funcName] = srcFunc;\n      }\n    },\n    _ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError, formdata, fileId, index, vUrl) {\n      var self = this,\n        settings,\n        defaults,\n        data,\n        tm = self.taskManager;\n      if (!self._raise(\"filepreajax\", [formdata, fileId, index])) {\n        return;\n      }\n      formdata.append(\"initialPreview\", JSON.stringify(self.initialPreview));\n      formdata.append(\"initialPreviewConfig\", JSON.stringify(self.initialPreviewConfig));\n      formdata.append(\"initialPreviewThumbTags\", JSON.stringify(self.initialPreviewThumbTags));\n      self._initAjaxSettings();\n      self._mergeAjaxCallback(\"beforeSend\", fnBefore);\n      self._mergeAjaxCallback(\"success\", fnSuccess);\n      self._mergeAjaxCallback(\"complete\", fnComplete);\n      self._mergeAjaxCallback(\"error\", fnError);\n      vUrl = vUrl || self.uploadUrlThumb || self.uploadUrl;\n      if (typeof vUrl === \"function\") {\n        vUrl = vUrl();\n      }\n      data = self._getExtraData(fileId, index) || {};\n      if (typeof data === \"object\") {\n        $.each(data, function (key, value) {\n          formdata.append(key, value);\n        });\n      }\n      defaults = {\n        xhr: function () {\n          var xhrobj = $.ajaxSettings.xhr();\n          return self._initXhr(xhrobj, fileId);\n        },\n        url: self._encodeURI(vUrl),\n        type: \"POST\",\n        dataType: \"json\",\n        data: formdata,\n        cache: false,\n        processData: false,\n        contentType: false,\n      };\n      settings = $.extend(true, {}, defaults, self._ajaxSettings);\n      self.ajaxQueue.push(settings);\n      tm.addTask(fileId + \"-\" + index, function () {\n        var self = this.self,\n          config,\n          xhr;\n        config = self.ajaxQueue.shift();\n        xhr = $.ajax(config);\n        self.ajaxRequests.push(xhr);\n      }).runWithContext({ self: self });\n    },\n    _mergeArray: function (prop, content) {\n      var self = this,\n        arr1 = $h.cleanArray(self[prop]),\n        arr2 = $h.cleanArray(content);\n      self[prop] = arr1.concat(arr2);\n    },\n    _initUploadSuccess: function (out, $thumb, allFiles) {\n      var self = this,\n        append,\n        data,\n        index,\n        $div,\n        content,\n        config,\n        tags,\n        id,\n        i;\n      if (!self.showPreview || typeof out !== \"object\" || $.isEmptyObject(out)) {\n        self._resetCaption();\n        return;\n      }\n      if (out.initialPreview !== undefined && out.initialPreview.length > 0) {\n        self.hasInitData = true;\n        content = out.initialPreview || [];\n        config = out.initialPreviewConfig || [];\n        tags = out.initialPreviewThumbTags || [];\n        append = out.append === undefined || out.append;\n        if (content.length > 0 && !$h.isArray(content)) {\n          content = content.split(self.initialPreviewDelimiter);\n        }\n        if (content.length) {\n          self._mergeArray(\"initialPreview\", content);\n          self._mergeArray(\"initialPreviewConfig\", config);\n          self._mergeArray(\"initialPreviewThumbTags\", tags);\n        }\n        if ($thumb !== undefined) {\n          if (!allFiles) {\n            index = self.previewCache.add(content[0], config[0], tags[0], append);\n            data = self.previewCache.get(index, false);\n            $div = $h.createElement($h.cspBuffer.stash(data)).hide().appendTo($thumb);\n            $h.cspBuffer.apply($thumb);\n            $thumb.fadeOut(\"slow\", function () {\n              var $newThumb = $div.find(\"> .file-preview-frame\");\n              if ($newThumb && $newThumb.length) {\n                $newThumb.insertBefore($thumb).fadeIn(\"slow\").css(\"display:inline-block\");\n              }\n              self._initPreviewActions();\n              self._clearFileInput();\n              $thumb.remove();\n              $div.remove();\n              self._initSortable();\n            });\n          } else {\n            id = $thumb.attr(\"id\");\n            i = self._getUploadCacheIndex(id);\n            if (i !== null) {\n              self.uploadCache[i] = {\n                id: id,\n                content: content[0],\n                config: config[0] || [],\n                tags: tags[0] || [],\n                append: append,\n              };\n            }\n          }\n        } else {\n          self.previewCache.set(content, config, tags, append);\n          self._initPreview();\n          self._initPreviewActions();\n        }\n      }\n      self._resetCaption();\n    },\n    _getUploadCacheIndex: function (id) {\n      var self = this,\n        i,\n        len = self.uploadCache.length,\n        config;\n      for (i = 0; i < len; i++) {\n        config = self.uploadCache[i];\n        if (config.id === id) {\n          return i;\n        }\n      }\n      return null;\n    },\n    _initSuccessThumbs: function () {\n      var self = this;\n      if (!self.showPreview) {\n        return;\n      }\n      setTimeout(function () {\n        self._getThumbs($h.FRAMES + \".file-preview-success\").each(function () {\n          var $thumb = $(this),\n            $remove = $thumb.find(\".kv-file-remove\");\n          $remove.removeAttr(\"disabled\");\n          self._handler($remove, \"click\", function () {\n            var id = $thumb.attr(\"id\"),\n              out = self._raise(\"filesuccessremove\", [id, $thumb.attr(\"data-fileindex\")]);\n            $h.cleanMemory($thumb);\n            if (out === false) {\n              return;\n            }\n            self.$caption.attr(\"title\", \"\");\n            $thumb.fadeOut(\"slow\", function () {\n              var fm = self.fileManager;\n              $thumb.remove();\n              if (!self.getFrames().length) {\n                self.reset();\n              }\n            });\n          });\n        });\n      }, self.processDelay);\n    },\n    _updateInitialPreview: function () {\n      var self = this,\n        u = self.uploadCache;\n      if (self.showPreview) {\n        $.each(u, function (key, setting) {\n          self.previewCache.add(setting.content, setting.config, setting.tags, setting.append);\n        });\n        if (self.hasInitData) {\n          self._initPreview();\n          self._initPreviewActions();\n        }\n      }\n    },\n    _getThumbFileId: function ($thumb) {\n      var self = this;\n      if (self.showPreview && $thumb !== undefined) {\n        return $thumb.attr(\"data-fileid\");\n      }\n      return null;\n    },\n    _getThumbFile: function ($thumb) {\n      var self = this,\n        id = self._getThumbFileId($thumb);\n      return id ? self.fileManager.getFile(id) : null;\n    },\n    _uploadSingle: function (i, id, isBatch, deferrer) {\n      var self = this,\n        fm = self.fileManager,\n        count = fm.count(),\n        formdata = new FormData(),\n        outData,\n        previewId = self._getThumbId(id),\n        $thumb,\n        chkComplete,\n        $btnUpload,\n        $btnDelete,\n        hasPostData = count > 0 || !$.isEmptyObject(self.uploadExtraData),\n        uploadFailed,\n        $prog,\n        fnBefore,\n        errMsg,\n        fnSuccess,\n        fnComplete,\n        fnError,\n        updateUploadLog,\n        op = self.ajaxOperations.uploadThumb,\n        fileObj = fm.getFile(id),\n        params = { id: previewId, index: i, fileId: id },\n        fileName = self.fileManager.getFileName(id, true),\n        resolve = function () {\n          if (deferrer && deferrer.resolve) {\n            deferrer.resolve();\n          }\n        },\n        reject = function () {\n          if (deferrer && deferrer.reject) {\n            deferrer.reject();\n          }\n        };\n      if (self.enableResumableUpload) {\n        // not enabled for resumable uploads\n        return;\n      }\n      self.uploadInitiated = true;\n      if (self.showPreview) {\n        $thumb = fm.getThumb(id);\n        $prog = $thumb.find(\".file-thumb-progress\");\n        $btnUpload = $thumb.find(\".kv-file-upload\");\n        $btnDelete = $thumb.find(\".kv-file-remove\");\n        $prog.show();\n      }\n      if (\n        count === 0 ||\n        !hasPostData ||\n        (self.showPreview && $btnUpload && $btnUpload.hasClass(\"disabled\")) ||\n        self._abort(params)\n      ) {\n        return;\n      }\n      updateUploadLog = function () {\n        if (!uploadFailed) {\n          fm.removeFile(id);\n        } else {\n          fm.errors.push(id);\n        }\n        fm.setProcessed(id);\n        if (fm.isProcessed()) {\n          self.fileBatchCompleted = true;\n          chkComplete();\n        }\n      };\n      chkComplete = function () {\n        var $initThumbs;\n        if (!self.fileBatchCompleted) {\n          return;\n        }\n        setTimeout(function () {\n          var triggerReset = fm.count() === 0,\n            errCount = fm.errors.length;\n          self._updateInitialPreview();\n          self.unlock(triggerReset);\n          if (triggerReset) {\n            self._clearFileInput();\n          }\n          $initThumbs = self.$preview.find(\".file-preview-initial\");\n          if (self.uploadAsync && $initThumbs.length) {\n            $h.addCss($initThumbs, $h.SORT_CSS);\n            self._initSortable();\n          }\n          self._raise(\"filebatchuploadcomplete\", [fm.stack, self._getExtraData()]);\n          if (!self.retryErrorUploads || errCount === 0) {\n            fm.clear();\n          }\n          self._setProgress(101);\n          self.ajaxAborted = false;\n          self.uploadInitiated = false;\n        }, self.processDelay);\n      };\n      fnBefore = function (jqXHR) {\n        outData = self._getOutData(formdata, jqXHR);\n        fm.initStats(id);\n        self.fileBatchCompleted = false;\n        if (!isBatch) {\n          self.ajaxAborted = false;\n        }\n        if (self.showPreview) {\n          if (!$thumb.hasClass(\"file-preview-success\")) {\n            self._setThumbStatus($thumb, \"Loading\");\n            $h.addCss($thumb, \"file-uploading\");\n          }\n          $btnUpload.attr(\"disabled\", true);\n          $btnDelete.attr(\"disabled\", true);\n        }\n        if (!isBatch) {\n          self.lock();\n        }\n        if (fm.errors.indexOf(id) !== -1) {\n          delete fm.errors[id];\n        }\n        self._raise(\"filepreupload\", [outData, previewId, i, self._getThumbFileId($thumb)]);\n        $.extend(true, params, outData);\n        if (self._abort(params)) {\n          jqXHR.abort();\n\n          if (!isBatch) {\n            self._setThumbStatus($thumb, \"New\");\n            $thumb.removeClass(\"file-uploading\");\n            $btnUpload.removeAttr(\"disabled\");\n            $btnDelete.removeAttr(\"disabled\");\n          }\n          self._setProgressCancelled();\n        }\n      };\n      fnSuccess = function (data, textStatus, jqXHR) {\n        var pid = self.showPreview && $thumb.attr(\"id\") ? $thumb.attr(\"id\") : previewId;\n        outData = self._getOutData(formdata, jqXHR, data);\n        $.extend(true, params, outData);\n        setTimeout(function () {\n          if ($h.isEmpty(data) || $h.isEmpty(data.error)) {\n            if (self.showPreview) {\n              self._setThumbStatus($thumb, \"Success\");\n              $btnUpload.hide();\n              self._initUploadSuccess(data, $thumb, isBatch);\n              self._setProgress(101, $prog);\n            }\n            self._raise(\"fileuploaded\", [outData, pid, i, self._getThumbFileId($thumb)]);\n            if (!isBatch) {\n              self.fileManager.remove($thumb);\n            } else {\n              updateUploadLog();\n              resolve();\n            }\n          } else {\n            uploadFailed = true;\n            errMsg = self._parseError(op, jqXHR, self.msgUploadError, self.fileManager.getFileName(id));\n            self._showFileError(errMsg, params);\n            self._setPreviewError($thumb, true);\n            if (!self.retryErrorUploads) {\n              $btnUpload.hide();\n            }\n            if (isBatch) {\n              updateUploadLog();\n              resolve();\n            }\n            self._setProgress(101, self._getFrame(pid).find(\".file-thumb-progress\"), self.msgUploadError);\n          }\n        }, self.processDelay);\n      };\n      fnComplete = function () {\n        if (self.showPreview) {\n          $btnUpload.removeAttr(\"disabled\");\n          $btnDelete.removeAttr(\"disabled\");\n          $thumb.removeClass(\"file-uploading\");\n        }\n        if (!isBatch) {\n          self.unlock(false);\n          self._clearFileInput();\n        } else {\n          chkComplete();\n        }\n        self._initSuccessThumbs();\n      };\n      fnError = function (jqXHR, textStatus, errorThrown) {\n        errMsg = self._parseError(op, jqXHR, errorThrown, self.fileManager.getFileName(id));\n        uploadFailed = true;\n        setTimeout(function () {\n          var $prog;\n          if (isBatch) {\n            updateUploadLog();\n            reject();\n          }\n          self.fileManager.setProgress(id, 100);\n          self._setPreviewError($thumb, true);\n          if (!self.retryErrorUploads) {\n            $btnUpload.hide();\n          }\n          $.extend(true, params, self._getOutData(formdata, jqXHR));\n          self._setProgress(101, self.$progress, self.msgAjaxProgressError.replace(\"{operation}\", op));\n          $prog = self.showPreview && $thumb ? $thumb.find(\".file-thumb-progress\") : \"\";\n          self._setProgress(101, $prog, self.msgUploadError);\n          self._showFileError(errMsg, params);\n        }, self.processDelay);\n      };\n      self._setFileData(formdata, fileObj.file, fileName, id);\n      self._setUploadData(formdata, { fileId: id });\n      self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, formdata, id, i);\n    },\n    _setFileData: function (formdata, file, fileName, fileId) {\n      var self = this,\n        preProcess = self.preProcessUpload;\n      if (preProcess && typeof preProcess === \"function\") {\n        formdata.append(self.uploadFileAttr, preProcess(fileId, file));\n      } else {\n        formdata.append(self.uploadFileAttr, file, fileName);\n      }\n    },\n    _checkBatchPreupload: function (outData, jqXHR) {\n      var self = this,\n        out = self._raise(\"filebatchpreupload\", [outData]);\n      if (out) {\n        return true;\n      }\n      self._abort(outData);\n      if (jqXHR) {\n        jqXHR.abort();\n      }\n      self._getThumbs().each(function () {\n        var $thumb = $(this),\n          $btnUpload = $thumb.find(\".kv-file-upload\"),\n          $btnDelete = $thumb.find(\".kv-file-remove\");\n        if ($thumb.hasClass(\"file-preview-loading\")) {\n          self._setThumbStatus($thumb, \"New\");\n          $thumb.removeClass(\"file-uploading\");\n        }\n        $btnUpload.removeAttr(\"disabled\");\n        $btnDelete.removeAttr(\"disabled\");\n      });\n      self._setProgressCancelled();\n      return false;\n    },\n    _uploadBatch: function () {\n      var self = this,\n        fm = self.fileManager,\n        total = fm.total(),\n        params = {},\n        fnBefore,\n        fnSuccess,\n        fnError,\n        fnComplete,\n        hasPostData = total > 0 || !$.isEmptyObject(self.uploadExtraData),\n        errMsg,\n        setAllUploaded,\n        formdata = new FormData(),\n        op = self.ajaxOperations.uploadBatch;\n      if (total === 0 || !hasPostData || self._abort(params)) {\n        return;\n      }\n      setAllUploaded = function () {\n        self.fileManager.clear();\n        self._clearFileInput();\n      };\n      fnBefore = function (jqXHR) {\n        self.lock();\n        fm.initStats();\n        var outData = self._getOutData(formdata, jqXHR);\n        self.ajaxAborted = false;\n        if (self.showPreview) {\n          self._getThumbs().each(function () {\n            var $thumb = $(this),\n              $btnUpload = $thumb.find(\".kv-file-upload\"),\n              $btnDelete = $thumb.find(\".kv-file-remove\");\n            if (!$thumb.hasClass(\"file-preview-success\")) {\n              self._setThumbStatus($thumb, \"Loading\");\n              $h.addCss($thumb, \"file-uploading\");\n            }\n            $btnUpload.attr(\"disabled\", true);\n            $btnDelete.attr(\"disabled\", true);\n          });\n        }\n        self._checkBatchPreupload(outData, jqXHR);\n      };\n      fnSuccess = function (data, textStatus, jqXHR) {\n        /** @namespace data.errorkeys */\n        var outData = self._getOutData(formdata, jqXHR, data),\n          key = 0,\n          $thumbs = self._getThumbs(\":not(.file-preview-success)\"),\n          keys = $h.isEmpty(data) || $h.isEmpty(data.errorkeys) ? [] : data.errorkeys;\n\n        if ($h.isEmpty(data) || $h.isEmpty(data.error)) {\n          self._raise(\"filebatchuploadsuccess\", [outData]);\n          setAllUploaded();\n          if (self.showPreview) {\n            $thumbs.each(function () {\n              var $thumb = $(this);\n              self._setThumbStatus($thumb, \"Success\");\n              $thumb.removeClass(\"file-uploading\");\n              $thumb.find(\".kv-file-upload\").hide().removeAttr(\"disabled\");\n            });\n            self._initUploadSuccess(data);\n          } else {\n            self.reset();\n          }\n          self._setProgress(101);\n        } else {\n          if (self.showPreview) {\n            $thumbs.each(function () {\n              var $thumb = $(this);\n              $thumb.removeClass(\"file-uploading\");\n              $thumb.find(\".kv-file-upload\").removeAttr(\"disabled\");\n              $thumb.find(\".kv-file-remove\").removeAttr(\"disabled\");\n              if (keys.length === 0 || $.inArray(key, keys) !== -1) {\n                self._setPreviewError($thumb, true);\n                if (!self.retryErrorUploads) {\n                  $thumb.find(\".kv-file-upload\").hide();\n                  self.fileManager.remove($thumb);\n                }\n              } else {\n                $thumb.find(\".kv-file-upload\").hide();\n                self._setThumbStatus($thumb, \"Success\");\n                self.fileManager.remove($thumb);\n              }\n              if (!$thumb.hasClass(\"file-preview-error\") || self.retryErrorUploads) {\n                key++;\n              }\n            });\n            self._initUploadSuccess(data);\n          }\n          errMsg = self._parseError(op, jqXHR, self.msgUploadError);\n          self._showFileError(errMsg, outData, \"filebatchuploaderror\");\n          self._setProgress(101, self.$progress, self.msgUploadError);\n        }\n      };\n      fnComplete = function () {\n        self.unlock();\n        self._initSuccessThumbs();\n        self._clearFileInput();\n        self._raise(\"filebatchuploadcomplete\", [self.fileManager.stack, self._getExtraData()]);\n      };\n      fnError = function (jqXHR, textStatus, errorThrown) {\n        var outData = self._getOutData(formdata, jqXHR);\n        errMsg = self._parseError(op, jqXHR, errorThrown);\n        self._showFileError(errMsg, outData, \"filebatchuploaderror\");\n        self.uploadFileCount = total - 1;\n        if (!self.showPreview) {\n          return;\n        }\n        self._getThumbs().each(function () {\n          var $thumb = $(this);\n          $thumb.removeClass(\"file-uploading\");\n          if (self._getThumbFile($thumb)) {\n            self._setPreviewError($thumb);\n          }\n        });\n        self._getThumbs().removeClass(\"file-uploading\");\n        self._getThumbs(\" .kv-file-upload\").removeAttr(\"disabled\");\n        self._getThumbs(\" .kv-file-delete\").removeAttr(\"disabled\");\n        self._setProgress(101, self.$progress, self.msgAjaxProgressError.replace(\"{operation}\", op));\n      };\n      var ctr = 0;\n      $.each(self.fileManager.stack, function (key, data) {\n        if (!$h.isEmpty(data.file)) {\n          self._setFileData(formdata, data.file, data.nameFmt || \"untitled_\" + ctr, key);\n        }\n        ctr++;\n      });\n      self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, formdata);\n    },\n    _uploadExtraOnly: function () {\n      var self = this,\n        params = {},\n        fnBefore,\n        fnSuccess,\n        fnComplete,\n        fnError,\n        formdata = new FormData(),\n        errMsg,\n        op = self.ajaxOperations.uploadExtra;\n      fnBefore = function (jqXHR) {\n        self.lock();\n        var outData = self._getOutData(formdata, jqXHR);\n        self._setProgress(50);\n        params.data = outData;\n        params.xhr = jqXHR;\n        self._checkBatchPreupload(outData, jqXHR);\n      };\n      fnSuccess = function (data, textStatus, jqXHR) {\n        var outData = self._getOutData(formdata, jqXHR, data);\n        if ($h.isEmpty(data) || $h.isEmpty(data.error)) {\n          self._raise(\"filebatchuploadsuccess\", [outData]);\n          self._clearFileInput();\n          self._initUploadSuccess(data);\n          self._setProgress(101);\n        } else {\n          errMsg = self._parseError(op, jqXHR, self.msgUploadError);\n          self._showFileError(errMsg, outData, \"filebatchuploaderror\");\n        }\n      };\n      fnComplete = function () {\n        self.unlock();\n        self._clearFileInput();\n        self._raise(\"filebatchuploadcomplete\", [self.fileManager.stack, self._getExtraData()]);\n      };\n      fnError = function (jqXHR, textStatus, errorThrown) {\n        var outData = self._getOutData(formdata, jqXHR);\n        errMsg = self._parseError(op, jqXHR, errorThrown);\n        params.data = outData;\n        self._showFileError(errMsg, outData, \"filebatchuploaderror\");\n        self._setProgress(101, self.$progress, self.msgAjaxProgressError.replace(\"{operation}\", op));\n      };\n      self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, formdata);\n    },\n    _deleteFileIndex: function ($frame) {\n      var self = this,\n        ind = $frame.attr(\"data-fileindex\"),\n        rev = self.reversePreviewOrder;\n      if (ind.substring(0, 5) === $h.INIT_FLAG) {\n        ind = parseInt(ind.replace($h.INIT_FLAG, \"\"));\n        self.initialPreview = $h.spliceArray(self.initialPreview, ind, rev);\n        self.initialPreviewConfig = $h.spliceArray(self.initialPreviewConfig, ind, rev);\n        self.initialPreviewThumbTags = $h.spliceArray(self.initialPreviewThumbTags, ind, rev);\n        self.getFrames().each(function () {\n          var $nFrame = $(this),\n            nInd = $nFrame.attr(\"data-fileindex\");\n          if (nInd.substring(0, 5) === $h.INIT_FLAG) {\n            nInd = parseInt(nInd.replace($h.INIT_FLAG, \"\"));\n            if (nInd > ind) {\n              nInd--;\n              $nFrame.attr(\"data-fileindex\", $h.INIT_FLAG + nInd);\n            }\n          }\n        });\n      }\n    },\n    _resetCaption: function () {\n      var self = this;\n      setTimeout(function () {\n        var cap = \"\",\n          n,\n          chk = self.previewCache.count(true),\n          len = self.fileManager.count(),\n          file,\n          incomplete = \":not(.file-preview-success):not(.file-preview-error)\",\n          cfg,\n          hasThumb = self.showPreview && self.getFrames(incomplete).length;\n        if (len === 0 && chk === 0 && !hasThumb) {\n          self.reset();\n        } else {\n          n = chk + len;\n          if (n > 1) {\n            cap = self._getMsgSelected(n);\n          } else {\n            if (len === 0) {\n              cfg = self.initialPreviewConfig[0];\n              cap = \"\";\n              if (cfg) {\n                cap = cfg.caption || cfg.filename || \"\";\n              }\n              if (!cap) {\n                cap = self._getMsgSelected(n);\n              }\n            } else {\n              file = self.fileManager.getFirstFile();\n              cap = file ? file.nameFmt : \"_\";\n            }\n          }\n          self._setCaption(cap);\n        }\n      }, self.processDelay);\n    },\n    _handleRotation: function ($el, $content, angle) {\n      var self = this,\n        css,\n        newCss,\n        addCss = \"\",\n        scale = 1,\n        elContent = $content[0],\n        quadrant,\n        transform,\n        h,\n        w,\n        wNew,\n        $parent = $content.parent(),\n        hParent,\n        wParent,\n        $body = $(\"body\"),\n        bodyExists = !!$body.length;\n      if (bodyExists) {\n        $body.addClass(\"kv-overflow-hidden\");\n      }\n      if (!$content.length || $el.hasClass(\"hide-rotate\")) {\n        if (bodyExists) {\n          $body.removeClass(\"kv-overflow-hidden\");\n        }\n        return;\n      }\n      transform = $content.css(\"transform\");\n      if (transform) {\n        $content.css(\"transform\", \"none\");\n      }\n      if (transform) {\n        $content.css(\"transform\", transform);\n      }\n      angle = angle || 0;\n      quadrant = angle % 360;\n      css = \"rotate(\" + angle + \"deg)\";\n      newCss = \"rotate(\" + quadrant + \"deg)\";\n      addCss = \"\";\n      if (quadrant === 90 || quadrant === 270) {\n        w = elContent.naturalWidth || $content.outerWidth() || 0;\n        h = elContent.naturalHeight || $content.outerHeight() || 0;\n        scale = w > h && w != 0 ? (h / w).toFixed(2) : 1;\n        if ($parent.length) {\n          hParent = $parent.height();\n          wParent = $parent.width();\n          wNew = Math.min(w, wParent);\n          if (hParent > scale * wNew) {\n            scale = wNew > hParent && wNew != 0 ? (hParent / wNew).toFixed(2) : 1;\n          }\n        }\n        if (scale !== 1) {\n          addCss = \" scale(\" + scale + \")\";\n        }\n      }\n      $content.addClass(\"rotate-animate\").css(\"transform\", css + addCss);\n      setTimeout(function () {\n        $content.removeClass(\"rotate-animate\").css(\"transform\", newCss + addCss);\n        if (bodyExists) {\n          $body.removeClass(\"kv-overflow-hidden\");\n        }\n        $el.data(\"angle\", quadrant);\n      }, self.fadeDelay);\n    },\n    _initRotateButton: function () {\n      var self = this;\n      self.getFrames(\".rotatable .kv-file-rotate\").each(function () {\n        var $el = $(this),\n          $frame = $el.closest($h.FRAMES),\n          $content = $frame.find(\".kv-file-content > :first-child\");\n        self._handler($el, \"click\", function () {\n          var angle = ($frame.data(\"angle\") || 0) + 90;\n          self._handleRotation($frame, $content, angle);\n        });\n      });\n    },\n    _initRotateZoom: function ($frame, $content) {\n      var self = this,\n        $modal = self.$modal,\n        $rotate = $modal.find(\".btn-kv-rotate\"),\n        angle = $frame.data(\"angle\");\n      $modal.data(\"angle\", angle);\n      if ($rotate.length) {\n        $rotate.off(\"click\");\n        if ($modal.hasClass(\"rotatable\")) {\n          $rotate.on(\"click\", function () {\n            angle = ($modal.data(\"angle\") || 0) + 90;\n            $modal.data(\"angle\", angle);\n            self._handleRotation($modal, $modal.find(\".file-zoom-detail\"), angle);\n            self._handleRotation($frame, $content, angle);\n            if ($frame.hasClass(\"hide-rotate\")) {\n              $frame.data(\"angle\", angle);\n            }\n          });\n        }\n      }\n    },\n    _initFileActions: function () {\n      var self = this;\n      if (!self.showPreview) {\n        return;\n      }\n      self._initZoomButton();\n      self._initRotateButton();\n      self.getFrames(\" .kv-file-remove\").each(function () {\n        var $el = $(this),\n          $frame = $el.closest($h.FRAMES),\n          hasError,\n          id = $frame.attr(\"id\"),\n          ind = $frame.attr(\"data-fileindex\"),\n          status,\n          fm = self.fileManager;\n        self._handler($el, \"click\", function () {\n          status = self._raise(\"filepreremove\", [id, ind]);\n          if (status === false || !self._validateMinCount()) {\n            return false;\n          }\n          hasError = $frame.hasClass(\"file-preview-error\");\n          $h.cleanMemory($frame);\n          $frame.fadeOut(\"slow\", function () {\n            self.fileManager.remove($frame);\n            self._clearObjects($frame);\n            $frame.remove();\n            if (id && hasError) {\n              self.$errorContainer.find('li[data-thumb-id=\"' + id + '\"]').fadeOut(\"fast\", function () {\n                $(this).remove();\n                if (!self._errorsExist()) {\n                  self._resetErrors();\n                }\n              });\n            }\n            self._clearFileInput();\n            self._resetCaption();\n            self._raise(\"fileremoved\", [id, ind]);\n          });\n        });\n      });\n      self.getFrames(\" .kv-file-upload\").each(function () {\n        var $el = $(this);\n        self._handler($el, \"click\", function () {\n          var $frame = $el.closest($h.FRAMES),\n            fileId = self._getThumbFileId($frame);\n          self._hideProgress();\n          if ($frame.hasClass(\"file-preview-error\") && !self.retryErrorUploads) {\n            return;\n          }\n          self._uploadSingle(self.fileManager.getIndex(fileId), fileId, false);\n        });\n      });\n    },\n    _initPreviewActions: function () {\n      var self = this,\n        $preview = self.$preview,\n        deleteExtraData = self.deleteExtraData || {},\n        btnRemove = $h.FRAMES + \" .kv-file-remove\",\n        settings = self.fileActionSettings,\n        origClass = settings.removeClass,\n        errClass = settings.removeErrorClass,\n        resetProgress = function () {\n          var hasFiles = self.isAjaxUpload ? self.previewCache.count(true) : self._inputFileCount();\n          if (!self.getFrames().length && !hasFiles) {\n            self._setCaption(\"\");\n            self.reset();\n            self.initialCaption = \"\";\n          } else {\n            self._resetCaption();\n          }\n        };\n      self._initZoomButton();\n      self._initRotateButton();\n      $preview.find(btnRemove).each(function () {\n        var $el = $(this),\n          vUrl = $el.data(\"url\") || self.deleteUrl,\n          vKey = $el.data(\"key\"),\n          errMsg,\n          fnBefore,\n          fnSuccess,\n          fnError,\n          op = self.ajaxOperations.deleteThumb;\n        if ($h.isEmpty(vUrl) || vKey === undefined) {\n          return;\n        }\n        if (typeof vUrl === \"function\") {\n          vUrl = vUrl();\n        }\n        var $frame = $el.closest($h.FRAMES),\n          cache = self.previewCache.data,\n          settings,\n          params,\n          config,\n          fileName,\n          extraData,\n          index = $frame.attr(\"data-fileindex\");\n        index = parseInt(index.replace($h.INIT_FLAG, \"\"));\n        config = $h.isEmpty(cache.config) && $h.isEmpty(cache.config[index]) ? null : cache.config[index];\n        extraData = $h.isEmpty(config) || $h.isEmpty(config.extra) ? deleteExtraData : config.extra;\n        fileName = (config && (config.filename || config.caption)) || \"\";\n        if (typeof extraData === \"function\") {\n          extraData = extraData();\n        }\n        params = { id: $el.attr(\"id\"), key: vKey, extra: extraData };\n        fnBefore = function (jqXHR) {\n          self.ajaxAborted = false;\n          self._raise(\"filepredelete\", [vKey, jqXHR, extraData]);\n          if (self._abort()) {\n            jqXHR.abort();\n          } else {\n            $el.removeClass(errClass);\n            $h.addCss($frame, \"file-uploading\");\n            $h.addCss($el, \"disabled \" + origClass);\n          }\n        };\n        fnSuccess = function (data, textStatus, jqXHR) {\n          var n, cap;\n          if (!$h.isEmpty(data) && !$h.isEmpty(data.error)) {\n            params.jqXHR = jqXHR;\n            params.response = data;\n            errMsg = self._parseError(op, jqXHR, self.msgDeleteError, fileName);\n            self._showFileError(errMsg, params, \"filedeleteerror\");\n            $frame.removeClass(\"file-uploading\");\n            $el.removeClass(\"disabled \" + origClass).addClass(errClass);\n            resetProgress();\n            return;\n          }\n          $frame.removeClass(\"file-uploading\").addClass(\"file-deleted\");\n          $frame.fadeOut(\"slow\", function () {\n            index = parseInt($frame.attr(\"data-fileindex\").replace($h.INIT_FLAG, \"\"));\n            self.previewCache.unset(index);\n            self._deleteFileIndex($frame);\n            n = self.previewCache.count(true);\n            cap = n > 0 ? self._getMsgSelected(n) : \"\";\n            self._setCaption(cap);\n            self._raise(\"filedeleted\", [vKey, jqXHR, extraData]);\n            self._clearObjects($frame);\n            $frame.remove();\n            resetProgress();\n          });\n        };\n        fnError = function (jqXHR, textStatus, errorThrown) {\n          var errMsg = self._parseError(op, jqXHR, errorThrown, fileName);\n          params.jqXHR = jqXHR;\n          params.response = {};\n          self._showFileError(errMsg, params, \"filedeleteerror\");\n          $frame.removeClass(\"file-uploading\");\n          $el.removeClass(\"disabled \" + origClass).addClass(errClass);\n          resetProgress();\n        };\n        self._initAjaxSettings();\n        self._mergeAjaxCallback(\"beforeSend\", fnBefore, \"delete\");\n        self._mergeAjaxCallback(\"success\", fnSuccess, \"delete\");\n        self._mergeAjaxCallback(\"error\", fnError, \"delete\");\n        settings = $.extend(\n          true,\n          {},\n          {\n            url: self._encodeURI(vUrl),\n            type: \"POST\",\n            dataType: \"json\",\n            data: $.extend(true, {}, { key: vKey }, extraData),\n          },\n          self._ajaxDeleteSettings\n        );\n        self._handler($el, \"click\", function () {\n          if (!self._validateMinCount()) {\n            return false;\n          }\n          self.ajaxAborted = false;\n          self._raise(\"filebeforedelete\", [vKey, extraData]);\n          if (self.ajaxAborted instanceof Promise) {\n            self.ajaxAborted.then(function (result) {\n              if (!result) {\n                $.ajax(settings);\n              }\n            });\n          } else {\n            if (!self.ajaxAborted) {\n              $.ajax(settings);\n            }\n          }\n        });\n      });\n    },\n    _hideFileIcon: function () {\n      var self = this;\n      if (self.overwriteInitial) {\n        self.$captionContainer.removeClass(\"icon-visible\");\n      }\n    },\n    _showFileIcon: function () {\n      var self = this;\n      $h.addCss(self.$captionContainer, \"icon-visible\");\n    },\n    _getSize: function (bytes, skipTemplate, sizeUnits) {\n      var self = this,\n        size = parseFloat(bytes),\n        i = 0,\n        factor = self.bytesToKB,\n        func = self.fileSizeGetter,\n        out,\n        sizeHuman = size,\n        newSize;\n      if (!$h.isNumeric(bytes) || !$h.isNumeric(size)) {\n        return \"\";\n      }\n      if (typeof func === \"function\") {\n        out = func(size);\n      } else {\n        if (!sizeUnits) {\n          sizeUnits = self.sizeUnits;\n        }\n        if (size > 0) {\n          while (sizeHuman >= factor) {\n            sizeHuman /= factor;\n            ++i;\n          }\n          if (!sizeUnits[i]) {\n            sizeHuman = size;\n            i = 0;\n          }\n        }\n        newSize = sizeHuman.toFixed(2);\n        if (newSize == sizeHuman) {\n          newSize = sizeHuman;\n        }\n        out = newSize + \" \" + sizeUnits[i];\n      }\n      return skipTemplate ? out : self._getLayoutTemplate(\"size\").replace(\"{sizeText}\", out);\n    },\n    _getFileType: function (ftype) {\n      var self = this;\n      return self.mimeTypeAliases[ftype] || ftype;\n    },\n    _generatePreviewTemplate: function (\n      cat,\n      data,\n      fname,\n      ftype,\n      previewId,\n      fileId,\n      isError,\n      size,\n      fnameUpdated,\n      frameClass,\n      foot,\n      ind,\n      templ,\n      attrs,\n      zoomData\n    ) {\n      var self = this,\n        caption = self.slug(fname),\n        prevContent,\n        zoomContent = \"\",\n        styleAttribs = \"\",\n        filename = fnameUpdated || fname,\n        isIconic,\n        ext = filename.split(\".\").pop().toLowerCase(),\n        screenW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,\n        config,\n        title = caption,\n        alt = caption,\n        typeCss = \"type-default\",\n        getContent,\n        addFrameCss,\n        footer = foot || self._renderFileFooter(cat, caption, size, \"auto\", isError),\n        isRotatable,\n        alwaysPreview = $.inArray(ext, self.alwaysPreviewFileExtensions) !== -1,\n        forcePrevIcon = self.preferIconicPreview && !alwaysPreview,\n        forceZoomIcon = self.preferIconicZoomPreview && !alwaysPreview,\n        newCat = forcePrevIcon ? \"other\" : cat;\n      config =\n        screenW < 400\n          ? self.previewSettingsSmall[newCat] || self.defaults.previewSettingsSmall[newCat]\n          : self.previewSettings[newCat] || self.defaults.previewSettings[newCat];\n      if (config) {\n        $.each(config, function (key, val) {\n          styleAttribs += key + \":\" + val + \";\";\n        });\n      }\n      getContent = function (vCat, vData, zoom, frameCss, vZoomData) {\n        var id = zoom ? \"zoom-\" + previewId : previewId,\n          tmplt = self._getPreviewTemplate(vCat),\n          css = (frameClass || \"\") + \" \" + frameCss,\n          tokens;\n        if (self.frameClass) {\n          css = self.frameClass + \" \" + css;\n        }\n        if (zoom) {\n          css = css.replace(\" \" + $h.SORT_CSS, \"\");\n        }\n        tmplt = self._parseFilePreviewIcon(tmplt, fname);\n        if (cat === \"object\" && !ftype) {\n          $.each(self.defaults.fileTypeSettings, function (key, func) {\n            if (key === \"object\" || key === \"other\") {\n              return;\n            }\n            if (func(fname, ftype)) {\n              typeCss = \"type-\" + key;\n            }\n          });\n        }\n        if (!$h.isEmpty(attrs)) {\n          if (attrs.title !== undefined && attrs.title !== null) {\n            title = attrs.title;\n          }\n          if (attrs.alt !== undefined && attrs.alt !== null) {\n            alt = title = attrs.alt;\n          }\n        }\n        tokens = {\n          previewId: id,\n          caption: caption,\n          title: title,\n          alt: alt,\n          frameClass: css,\n          type: self._getFileType(ftype),\n          fileindex: ind,\n          fileid: fileId || \"\",\n          filename: filename,\n          typeCss: typeCss,\n          footer: footer,\n          data: vData,\n//          data: zoom && vZoomData ? self.zoomPlaceholder + \"{zoomData}\" : vData,\n          template: templ || cat,\n          style: styleAttribs ? 'style=\"' + styleAttribs + '\"' : \"\",\n          zoomData: vZoomData ? encodeURIComponent(vZoomData) : \"\",\n        };\n        if (zoom) {\n          tokens.zoomCache = \"\";\n          tokens.zoomData = \"{zoomData}\";\n        }\n        return tmplt.setTokens(tokens);\n      };\n      ind = ind || previewId.slice(previewId.lastIndexOf(\"-\") + 1);\n      isRotatable = self.fileActionSettings.showRotate && $.inArray(ext, self.rotatableFileExtensions) !== -1;\n      if (self.fileActionSettings.showZoom) {\n        addFrameCss = \"kv-zoom-thumb\";\n        if (isRotatable) {\n          addFrameCss += \" rotatable\" + (forceZoomIcon ? \" hide-rotate\" : \"\");\n        }\n        zoomContent = getContent(forceZoomIcon ? \"other\" : cat, data, true, addFrameCss, zoomData);\n      }\n      zoomContent = \"\\n\" + self._getLayoutTemplate(\"zoomCache\").replace(\"{zoomContent}\", zoomContent);\n      if (typeof self.sanitizeZoomCache === \"function\") {\n        zoomContent = self.sanitizeZoomCache(zoomContent);\n      }\n      addFrameCss = \"kv-preview-thumb\";\n      if (isRotatable) {\n        isIconic = forcePrevIcon || self.hideThumbnailContent || !!self.previewFileIconSettings[ext];\n        addFrameCss += \" rotatable\" + (isIconic ? \" hide-rotate\" : \"\");\n      }\n      prevContent = getContent(forcePrevIcon ? \"other\" : cat, data, false, addFrameCss, zoomData);\n      return prevContent.setTokens({ zoomCache: zoomContent });\n    },\n    _addToPreview: function ($preview, content) {\n      var self = this,\n        $el;\n      content = $h.cspBuffer.stash(content);\n      $el = self.reversePreviewOrder ? $preview.prepend(content) : $preview.append(content);\n      $h.cspBuffer.apply($preview);\n      return $el;\n    },\n    _previewDefault: function (file, isDisabled) {\n      var self = this,\n        $preview = self.$preview;\n      if (!self.showPreview) {\n        return;\n      }\n      var fname = $h.getFileName(file),\n        ftype = file ? file.type : \"\",\n        content,\n        size = file.size || 0,\n        caption = self._getFileName(file, \"\"),\n        isError = isDisabled === true && !self.isAjaxUpload,\n        data = $h.createObjectURL(file),\n        fileId = self.fileManager.getId(file),\n        previewId = self._getThumbId(fileId);\n      self._clearDefaultPreview();\n      content = self._generatePreviewTemplate(\"other\", data, fname, ftype, previewId, fileId, isError, size);\n      self._addToPreview($preview, content);\n      self._setThumbAttr(previewId, caption, size);\n      if (isDisabled === true && self.isAjaxUpload) {\n        self._setThumbStatus(self._getFrame(previewId), \"Error\");\n      }\n    },\n    _previewFile: function (i, file, theFile, data, fileInfo) {\n      if (!this.showPreview) {\n        return;\n      }\n      var self = this,\n        fname = $h.getFileName(file),\n        ftype = fileInfo.type,\n        content,\n        caption = fileInfo.name,\n        cat = self._parseFileType(ftype, fname),\n        $preview = self.$preview,\n        fsize = file.size || 0,\n        iData = cat === \"image\" ? theFile.target.result : data,\n        fm = self.fileManager,\n        fileId = fm.getId(file),\n        previewId = self._getThumbId(fileId);\n      /** @namespace window.DOMPurify */\n      content = self._generatePreviewTemplate(\n        cat,\n        iData,\n        fname,\n        ftype,\n        previewId,\n        fileId,\n        false,\n        fsize,\n        fileInfo.filename\n      );\n      self._clearDefaultPreview();\n      self._addToPreview($preview, content);\n      var $thumb = self._getFrame(previewId);\n      self._validateImageOrientation($thumb.find(\"img\"), file, previewId, fileId, caption, ftype, fsize, iData);\n      self._setThumbAttr(previewId, caption, fsize);\n      self._initSortable();\n    },\n    _setThumbAttr: function (id, caption, size, description) {\n      var self = this,\n        $frame = self._getFrame(id);\n      if ($frame.length) {\n        size = size && size > 0 ? self._getSize(size) : \"\";\n        $frame.data({ caption: caption, size: size, description: description || \"\" });\n      }\n    },\n    _setInitThumbAttr: function () {\n      var self = this,\n        data = self.previewCache.data,\n        len = self.previewCache.count(true),\n        config,\n        caption,\n        size,\n        description,\n        previewId;\n      if (len === 0) {\n        return;\n      }\n      for (var i = 0; i < len; i++) {\n        config = data.config[i];\n        previewId = self.previewInitId + \"-\" + $h.INIT_FLAG + i;\n        caption = $h.ifSet(\"caption\", config, $h.ifSet(\"filename\", config));\n        size = $h.ifSet(\"size\", config);\n        description = $h.ifSet(\"description\", config);\n        self._setThumbAttr(previewId, caption, size, description);\n      }\n    },\n    _slugDefault: function (text) {\n      // noinspection RegExpRedundantEscape\n      return $h.isEmpty(text, true) ? \"\" : String(text).replace(/[\\[\\]\\/\\{}:;#%=\\(\\)\\*\\+\\?\\\\\\^\\$\\|<>&\"']/g, \"_\");\n    },\n    _updateFileDetails: function (numFiles) {\n      var self = this,\n        $el = self.$element,\n        label,\n        n,\n        log,\n        nFiles,\n        file,\n        name = ($h.isIE(9) && $h.findFileName($el.val())) || ($el[0].files[0] && $el[0].files[0].name);\n      if (!name && self.fileManager.count() > 0) {\n        file = self.fileManager.getFirstFile();\n        label = file.nameFmt;\n      } else {\n        label = name ? self.slug(name) : \"_\";\n      }\n      n = self.isAjaxUpload ? self.fileManager.count() : numFiles;\n      nFiles = self.previewCache.count(true) + n;\n      log = n === 1 ? label : self._getMsgSelected(nFiles, !self.isAjaxUpload && !self.isError);\n      if (self.isError) {\n        self.$previewContainer.removeClass(\"file-thumb-loading\");\n        self._initCapStatus();\n        self.$previewStatus.html(\"\");\n        self.$captionContainer.removeClass(\"icon-visible\");\n      } else {\n        self._showFileIcon();\n      }\n      self._setCaption(log, self.isError);\n      self.$container.removeClass(\"file-input-new file-input-ajax-new\");\n      self._raise(\"fileselect\", [numFiles, label]);\n      if (self.previewCache.count(true)) {\n        self._initPreviewActions();\n      }\n    },\n    _setThumbStatus: function ($thumb, status) {\n      var self = this;\n      if (!self.showPreview) {\n        return;\n      }\n      var icon = \"indicator\" + status,\n        msg = icon + \"Title\",\n        css = \"file-preview-\" + status.toLowerCase(),\n        $indicator = $thumb.find(\".file-upload-indicator\"),\n        config = self.fileActionSettings;\n      $thumb.removeClass(\"file-preview-success file-preview-error file-preview-paused file-preview-loading\");\n      if (status === \"Success\") {\n        $thumb.find(\".file-drag-handle\").remove();\n      }\n      $h.setHtml($indicator, config[icon]);\n      $indicator.attr(\"title\", config[msg]);\n      $thumb.addClass(css);\n      if (status === \"Error\" && !self.retryErrorUploads) {\n        $thumb.find(\".kv-file-upload\").attr(\"disabled\", true);\n      }\n    },\n    _setProgressCancelled: function () {\n      var self = this;\n      self._setProgress(101, self.$progress, self.msgCancelled);\n    },\n    _setProgress: function (p, $el, error, stats) {\n      var self = this;\n      $el = $el || self.$progress;\n      if (!$el.length) {\n        return;\n      }\n      var pct = Math.min(p, 100),\n        out,\n        pctLimit = self.progressUploadThreshold,\n        t = p <= 100 ? self.progressTemplate : self.progressCompleteTemplate,\n        template =\n          pct < 100\n            ? self.progressTemplate\n            : error\n            ? self.paused\n              ? self.progressPauseTemplate\n              : self.progressErrorTemplate\n            : t;\n      if (p >= 100) {\n        stats = \"\";\n      }\n      if (!$h.isEmpty(template)) {\n        if (pctLimit && pct > pctLimit && p <= 100) {\n          out = template.setTokens({ percent: pctLimit, status: self.msgUploadThreshold });\n        } else {\n          out = template.setTokens({ percent: pct, status: p > 100 ? self.msgUploadEnd : pct + \"%\" });\n        }\n        stats = stats || \"\";\n        out = out.setTokens({ stats: stats });\n        $h.setHtml($el, out);\n        if (error) {\n          $h.setHtml($el.find('[role=\"progressbar\"]'), error);\n        }\n      }\n    },\n    _hasFiles: function () {\n      var el = this.$element[0];\n      return !!(el && el.files && el.files.length);\n    },\n    _setFileDropZoneTitle: function () {\n      var self = this,\n        $zone = self.$container.find(\".file-drop-zone\"),\n        title = self.dropZoneTitle,\n        strFiles;\n      if (self.isClickable) {\n        strFiles = $h.isEmpty(self.$element.attr(\"multiple\")) ? self.fileSingle : self.filePlural;\n        title += self.dropZoneClickTitle.replace(\"{files}\", strFiles);\n      }\n      $zone.find(\".\" + self.dropZoneTitleClass).remove();\n      if (\n        !self.showPreview ||\n        $zone.length === 0 ||\n        self.fileManager.count() > 0 ||\n        !self.dropZoneEnabled ||\n        self.previewCache.count() > 0 ||\n        (!self.isAjaxUpload && self._hasFiles())\n      ) {\n        return;\n      }\n      if ($zone.find($h.FRAMES).length === 0 && $h.isEmpty(self.defaultPreviewContent)) {\n        $zone.prepend($h.cspBuffer.stash('<div class=\"' + self.dropZoneTitleClass + '\">' + title + \"</div>\"));\n        $h.cspBuffer.apply($zone);\n      }\n      self.$container.removeClass(\"file-input-new\");\n      if (self.isAjaxUpload) {\n        $h.addCss(self.$container, \"file-input-ajax-new\");\n      }\n    },\n    _getStats: function (stats) {\n      var self = this,\n        pendingTime,\n        t;\n      if (!self.showUploadStats || !stats || !stats.bitrate) {\n        return \"\";\n      }\n      t = self._getLayoutTemplate(\"stats\");\n      pendingTime =\n        !stats.elapsed || !stats.bps\n          ? self.msgCalculatingTime\n          : self.msgPendingTime.setTokens({ time: $h.getElapsed(Math.ceil(stats.pendingBytes / stats.bps)) });\n\n      return t.setTokens({\n        uploadSpeed: stats.bitrate,\n        pendingTime: pendingTime,\n      });\n    },\n    _setResumableProgress: function (pct, stats, $thumb) {\n      var self = this,\n        rm = self.resumableManager,\n        obj = $thumb ? rm : self,\n        $prog = $thumb ? $thumb.find(\".file-thumb-progress\") : null;\n      if (obj.lastProgress === 0) {\n        obj.lastProgress = pct;\n      }\n      if (pct < obj.lastProgress) {\n        pct = obj.lastProgress;\n      }\n      self._setProgress(pct, $prog, null, self._getStats(stats));\n      obj.lastProgress = pct;\n    },\n    _toggleResumableProgress: function (template, message) {\n      var self = this,\n        $progress = self.$progress;\n      if ($progress && $progress.length) {\n        $h.setHtml(\n          $progress,\n          template.setTokens({\n            percent: 101,\n            status: message,\n            stats: \"\",\n          })\n        );\n      }\n    },\n    _setFileUploadStats: function (id, pct, stats) {\n      var self = this,\n        $prog = self.$progress;\n      if (!self.showPreview && (!$prog || !$prog.length)) {\n        return;\n      }\n      var fm = self.fileManager,\n        rm = self.resumableManager,\n        $thumb = fm.getThumb(id),\n        pctTot,\n        totUpSize = 0,\n        totSize = fm.getTotalSize(),\n        totStats = $.extend(true, {}, stats);\n      if (self.enableResumableUpload) {\n        var loaded = stats.loaded,\n          currUplSize = rm.getUploadedSize(),\n          currTotSize = rm.file.size,\n          totLoaded;\n        loaded += currUplSize;\n        totLoaded = fm.uploadedSize + loaded;\n        pct = $h.round((100 * loaded) / currTotSize);\n        stats.pendingBytes = currTotSize - currUplSize;\n        self._setResumableProgress(pct, stats, $thumb);\n        pctTot = Math.floor((100 * totLoaded) / totSize);\n        totStats.pendingBytes = totSize - totLoaded;\n        self._setResumableProgress(pctTot, totStats);\n      } else {\n        fm.setProgress(id, pct);\n        $prog = $thumb && $thumb.length ? $thumb.find(\".file-thumb-progress\") : null;\n        self._setProgress(pct, $prog, null, self._getStats(stats));\n        $.each(fm.stats, function (id, cfg) {\n          totUpSize += cfg.loaded;\n        });\n        totStats.pendingBytes = totSize - totUpSize;\n        pctTot = $h.round((totUpSize / totSize) * 100);\n        self._setProgress(pctTot, null, null, self._getStats(totStats));\n      }\n    },\n    _validateMinCount: function () {\n      var self = this,\n        len = self.isAjaxUpload ? self.fileManager.count() : self._inputFileCount();\n      if (self.validateInitialCount && self.minFileCount > 0 && self._getFileCount(len - 1) < self.minFileCount) {\n        self._noFilesError({});\n        return false;\n      }\n      return true;\n    },\n    _getFileCount: function (fileCount, includeInitial) {\n      var self = this,\n        addCount = 0;\n      if (includeInitial === undefined) {\n        includeInitial = self.validateInitialCount && !self.overwriteInitial;\n      }\n      if (includeInitial) {\n        addCount = self.previewCache.count(true);\n        fileCount += addCount;\n      }\n      return fileCount;\n    },\n    _getFileId: function (file) {\n      return $h.getFileId(file, this.generateFileId);\n    },\n    _getFileName: function (file, defaultValue) {\n      var self = this,\n        fileName = $h.getFileName(file);\n      return fileName ? self.slug(fileName) : defaultValue;\n    },\n    _getFileNames: function (skipNull) {\n      var self = this;\n      return self.filenames.filter(function (n) {\n        return skipNull ? n !== undefined : n !== undefined && n !== null;\n      });\n    },\n    _setPreviewError: function ($thumb, keepFile) {\n      var self = this,\n        removeFrame = self.removeFromPreviewOnError && !self.retryErrorUploads;\n      if (!keepFile || removeFrame) {\n        self.fileManager.remove($thumb);\n      }\n      if (!self.showPreview) {\n        return;\n      }\n      if (removeFrame) {\n        $thumb.remove();\n        return;\n      } else {\n        self._setThumbStatus($thumb, \"Error\");\n      }\n      self._refreshUploadButton($thumb);\n    },\n    _refreshUploadButton: function ($thumb) {\n      var self = this,\n        $btn = $thumb.find(\".kv-file-upload\"),\n        cfg = self.fileActionSettings,\n        icon = cfg.uploadIcon,\n        title = cfg.uploadTitle;\n      if (!$btn.length) {\n        return;\n      }\n      if (self.retryErrorUploads) {\n        icon = cfg.uploadRetryIcon;\n        title = cfg.uploadRetryTitle;\n      }\n      $btn.attr(\"title\", title);\n      $h.setHtml($btn, icon);\n    },\n    _isValidSize: function (size, type, $image, $thumb, filename, params) {\n      var self = this,\n        msg,\n        dim,\n        $img,\n        tag = size === \"Small\" ? \"min\" : \"max\",\n        limit = self[tag + \"Image\" + type];\n      if ($h.isEmpty(limit) || !$image.length) {\n        return true;\n      }\n      $img = $image[0];\n      dim = type === \"Width\" ? $img.naturalWidth || $img.width : $img.naturalHeight || $img.height;\n      if (size === \"Small\" ? dim >= limit : dim <= limit) {\n        return true;\n      }\n      msg = self[\"msgImage\" + type + size] || 'Image \"{name}\" has a size validation error (limit \"{size}\").';\n      self._showFileError(msg.setTokens({ name: filename, size: limit, dimension: dim }), params);\n      self._setPreviewError($thumb);\n      self.fileManager.remove($thumb);\n      self._clearFileInput();\n      return false;\n    },\n    _getExifObj: function (data) {\n      var self = this,\n        exifObj,\n        error = $h.logMessages.exifWarning;\n      if (data.slice(0, 23) !== \"data:image/jpeg;base64,\" && data.slice(0, 22) !== \"data:image/jpg;base64,\") {\n        exifObj = null;\n        return;\n      }\n      try {\n        exifObj = window.piexif ? window.piexif.load(data) : null;\n      } catch (err) {\n        exifObj = null;\n        error = (err && err.message) || \"\";\n      }\n      if (!exifObj && self.showExifErrorLog) {\n        self._log($h.logMessages.badExifParser, { details: error });\n      }\n      return exifObj;\n    },\n    setImageOrientation: function ($img, $zoomImg, value, $thumb) {\n      var self = this,\n        invalidImg = !$img || !$img.length,\n        invalidZoomImg = !$zoomImg || !$zoomImg.length,\n        $mark,\n        isHidden = false,\n        $div,\n        zoomOnly = invalidImg && $thumb && $thumb.attr(\"data-template\") === \"image\",\n        ev;\n      if (invalidImg && invalidZoomImg) {\n        return;\n      }\n      ev = \"load.fileinputimageorient\";\n      if (zoomOnly) {\n        $img = $zoomImg;\n        $zoomImg = null;\n        $img.css(self.previewSettings.image);\n        $div = $h.createDiv().appendTo($thumb.find(\".kv-file-content\"));\n        $mark = $(document.createElement(\"span\")).insertBefore($img);\n        $img.css(\"visibility\", \"hidden\").removeClass(\"file-zoom-detail\").appendTo($div);\n      } else {\n        isHidden = !$img.is(\":visible\");\n      }\n      $img.off(ev).on(ev, function () {\n        if (isHidden) {\n          self.$preview.removeClass(\"hide-content\");\n          $thumb.find(\".kv-file-content\").css(\"visibility\", \"hidden\");\n        }\n        var img = $img[0],\n          zoomImg = $zoomImg && $zoomImg.length ? $zoomImg[0] : null,\n          h = img.offsetHeight,\n          w = img.offsetWidth,\n          r = $h.getRotation(value);\n        if (isHidden) {\n          $thumb.find(\".kv-file-content\").css(\"visibility\", \"visible\");\n          self.$preview.addClass(\"hide-content\");\n        }\n        $img.data(\"orientation\", value);\n        if (zoomImg) {\n          $zoomImg.data(\"orientation\", value);\n        }\n        if (value < 5) {\n          $h.setTransform(img, r);\n          $h.setTransform(zoomImg, r);\n          return;\n        }\n        var offsetAngle = Math.atan(w / h),\n          origFactor = Math.sqrt(Math.pow(h, 2) + Math.pow(w, 2)),\n          scale = !origFactor ? 1 : h / Math.cos(Math.PI / 2 + offsetAngle) / origFactor,\n          s = \" scale(\" + Math.abs(scale) + \")\";\n        $h.setTransform(img, r + s);\n        $h.setTransform(zoomImg, r + s);\n        if (zoomOnly) {\n          $img.css(\"visibility\", \"visible\").insertAfter($mark).addClass(\"file-zoom-detail\");\n          $mark.remove();\n          $div.remove();\n        }\n      });\n    },\n    _validateImageOrientation: function ($img, file, previewId, fileId, caption, ftype, fsize, iData) {\n      var self = this,\n        exifObj = null,\n        value,\n        autoOrientImage = self.autoOrientImage,\n        selector;\n      exifObj = self._getExifObj(iData);\n      if (self.canOrientImage) {\n        $img.css(\"image-orientation\", autoOrientImage ? \"from-image\" : \"none\");\n        self._validateImage(previewId, fileId, caption, ftype, fsize, iData, exifObj);\n        return;\n      }\n      selector = $h.getZoomSelector(previewId, \" img\");\n      value = exifObj ? exifObj[\"0th\"][piexif.ImageIFD.Orientation] : null; // jshint ignore:line\n      if (!value) {\n        self._validateImage(previewId, fileId, caption, ftype, fsize, iData, exifObj);\n        return;\n      }\n      self.setImageOrientation($img, $(selector), value, self._getFrame(previewId));\n      self._raise(\"fileimageoriented\", { $img: $img, file: file });\n      self._validateImage(previewId, fileId, caption, ftype, fsize, iData, exifObj);\n    },\n    _validateImage: function (previewId, fileId, fname, ftype, fsize, iData, exifObj) {\n      var self = this,\n        $preview = self.$preview,\n        params,\n        w1,\n        w2,\n        $thumb = self._getFrame(previewId),\n        i = $thumb.attr(\"data-fileindex\"),\n        $img = $thumb.find(\"img\");\n      fname = fname || \"Untitled\";\n      $img\n        .one(\"load\", function () {\n          if ($img.data(\"validated\")) {\n            return;\n          }\n          $img.data(\"validated\", true);\n          w1 = $thumb.width();\n          w2 = $preview.width();\n          if (w1 > w2) {\n            $img.css(\"width\", \"100%\");\n          }\n          params = { ind: i, id: previewId, fileId: fileId };\n          setTimeout(function () {\n            var isValidWidth, isValidHeight;\n            isValidWidth = self._isValidSize(\"Small\", \"Width\", $img, $thumb, fname, params);\n            isValidHeight = self._isValidSize(\"Small\", \"Height\", $img, $thumb, fname, params);\n            if (!self.resizeImage) {\n              isValidWidth = isValidWidth && self._isValidSize(\"Large\", \"Width\", $img, $thumb, fname, params);\n              isValidHeight = isValidHeight && self._isValidSize(\"Large\", \"Height\", $img, $thumb, fname, params);\n            }\n            self._raise(\"fileimageloaded\", [previewId]);\n            $thumb.data(\"exif\", exifObj);\n            if (isValidWidth && isValidHeight) {\n              self.fileManager.addImage(fileId, {\n                ind: i,\n                img: $img,\n                thumb: $thumb,\n                pid: previewId,\n                typ: ftype,\n                siz: fsize,\n                validated: false,\n                imgData: iData,\n                exifObj: exifObj,\n              });\n              self._validateAllImages();\n            }\n          }, self.processDelay);\n        })\n        .one(\"error\", function () {\n          self._raise(\"fileimageloaderror\", [previewId]);\n        });\n    },\n    _validateAllImages: function () {\n      var self = this,\n        counter = { val: 0 },\n        numImgs = self.fileManager.getImageCount(),\n        fsize,\n        minSize = self.resizeIfSizeMoreThan;\n      if (numImgs !== self.fileManager.totalImages) {\n        return;\n      }\n      self._raise(\"fileimagesloaded\");\n      if (!self.resizeImage) {\n        return;\n      }\n      $.each(self.fileManager.loadedImages, function (id, config) {\n        if (!config.validated) {\n          fsize = config.siz;\n          if (fsize && fsize > minSize * self.bytesToKB) {\n            self._getResizedImage(id, config, counter, numImgs);\n          }\n          config.validated = true;\n        }\n      });\n    },\n    _getResizedImage: function (id, config, counter, numImgs) {\n      var self = this,\n        img = $(config.img)[0],\n        width = img.naturalWidth,\n        height = img.naturalHeight,\n        blob,\n        ratio = 1,\n        maxWidth = self.maxImageWidth || width,\n        maxHeight = self.maxImageHeight || height,\n        isValidImage = !!(width && height),\n        chkWidth,\n        chkHeight,\n        canvas = self.imageCanvas,\n        dataURI,\n        context = self.imageCanvasContext,\n        type = config.typ,\n        pid = config.pid,\n        ind = config.ind,\n        $thumb = config.thumb,\n        throwError,\n        msg,\n        exifObj = config.exifObj,\n        exifStr,\n        file,\n        params,\n        evParams;\n      throwError = function (msg, params, ev) {\n        if (self.isAjaxUpload) {\n          self._showFileError(msg, params, ev);\n        } else {\n          self._showError(msg, params, ev);\n        }\n        self._setPreviewError($thumb);\n      };\n      file = self.fileManager.getFile(id);\n      params = { id: pid, index: ind, fileId: id };\n      evParams = [id, pid, ind];\n      if (!file || !isValidImage || (width <= maxWidth && height <= maxHeight)) {\n        if (isValidImage && file) {\n          self._raise(\"fileimageresized\", evParams);\n        }\n        counter.val++;\n        if (counter.val === numImgs) {\n          self._raise(\"fileimagesresized\");\n        }\n        if (!isValidImage) {\n          throwError(self.msgImageResizeError, params, \"fileimageresizeerror\");\n          return;\n        }\n      }\n      type = type || self.resizeDefaultImageType;\n      chkWidth = width > maxWidth;\n      chkHeight = height > maxHeight;\n      if (self.resizePreference === \"width\") {\n        ratio = chkWidth ? maxWidth / width : chkHeight ? maxHeight / height : 1;\n      } else {\n        ratio = chkHeight ? maxHeight / height : chkWidth ? maxWidth / width : 1;\n      }\n      self._resetCanvas();\n      width *= ratio;\n      height *= ratio;\n      canvas.width = width;\n      canvas.height = height;\n      try {\n        context.drawImage(img, 0, 0, width, height);\n        dataURI = canvas.toDataURL(type, self.resizeQuality);\n        if (exifObj) {\n          exifStr = window.piexif.dump(exifObj);\n          dataURI = window.piexif.insert(exifStr, dataURI);\n        }\n        blob = $h.dataURI2Blob(dataURI);\n        self.fileManager.setFile(id, blob);\n        self._raise(\"fileimageresized\", evParams);\n        counter.val++;\n        if (counter.val === numImgs) {\n          self._raise(\"fileimagesresized\", [undefined, undefined]);\n        }\n        if (!(blob instanceof Blob)) {\n          throwError(self.msgImageResizeError, params, \"fileimageresizeerror\");\n        }\n      } catch (err) {\n        counter.val++;\n        if (counter.val === numImgs) {\n          self._raise(\"fileimagesresized\", [undefined, undefined]);\n        }\n        msg = self.msgImageResizeException.replace(\"{errors}\", err.message);\n        throwError(msg, params, \"fileimageresizeexception\");\n      }\n    },\n    _showProgress: function () {\n      var self = this;\n      if (self.$progress && self.$progress.length) {\n        self.$progress.show();\n      }\n    },\n    _hideProgress: function () {\n      var self = this;\n      if (self.$progress && self.$progress.length) {\n        self.$progress.hide();\n      }\n    },\n    _initBrowse: function ($container) {\n      var self = this,\n        $el = self.$element;\n      if (self.showBrowse) {\n        self.$btnFile = $container.find(\".btn-file\").append($el);\n      } else {\n        $el.appendTo($container).attr(\"tabindex\", -1);\n        $h.addCss($el, \"file-no-browse\");\n      }\n    },\n    _initClickable: function () {\n      var self = this,\n        $zone,\n        $tmpZone;\n      if (!self.isClickable) {\n        return;\n      }\n      $zone = self.$dropZone;\n      if (!self.isAjaxUpload) {\n        $tmpZone = self.$preview.find(\".file-default-preview\");\n        if ($tmpZone.length) {\n          $zone = $tmpZone;\n        }\n      }\n\n      $h.addCss($zone, \"clickable\");\n      $zone.attr(\"tabindex\", -1);\n      self._handler($zone, \"click\", function (e) {\n        var $tar = $(e.target);\n        if (\n          !self.$errorContainer.is(\":visible\") &&\n          (!$tar.parents(\".file-preview-thumbnails\").length || $tar.parents(\".file-default-preview\").length)\n        ) {\n          self.$element.data(\"zoneClicked\", true).trigger(\"click\");\n          $zone.blur();\n        }\n      });\n    },\n    _initCaption: function () {\n      var self = this,\n        cap = self.initialCaption || \"\";\n      if (self.overwriteInitial || $h.isEmpty(cap)) {\n        self.$caption.val(\"\");\n        return false;\n      }\n      self._setCaption(cap);\n      return true;\n    },\n    _setCaption: function (content, isError) {\n      var self = this,\n        title,\n        out,\n        icon,\n        n,\n        cap,\n        file;\n      if (!self.$caption.length) {\n        return;\n      }\n      self.$captionContainer.removeClass(\"icon-visible\");\n      if (isError) {\n        title = $(\"<div>\" + self.msgValidationError + \"</div>\").text();\n        n = self.fileManager.count();\n        if (n) {\n          file = self.fileManager.getFirstFile();\n          cap = n === 1 && file ? file.nameFmt : self._getMsgSelected(n);\n        } else {\n          cap = self._getMsgSelected(self.msgNo);\n        }\n        out = $h.isEmpty(content) ? cap : content;\n        icon = '<span class=\"' + self.msgValidationErrorClass + '\">' + self.msgValidationErrorIcon + \"</span>\";\n      } else {\n        if ($h.isEmpty(content)) {\n          self.$caption.attr(\"title\", \"\");\n          return;\n        }\n        title = $(\"<div>\" + content + \"</div>\").text();\n        out = title;\n        icon = self._getLayoutTemplate(\"fileIcon\");\n      }\n      self.$captionContainer.addClass(\"icon-visible\");\n      self.$caption.attr(\"title\", title).val(out);\n      $h.setHtml(self.$captionIcon, icon);\n    },\n    _createContainer: function () {\n      var self = this,\n        attribs = { class: \"file-input file-input-new\" + (self.rtl ? \" kv-rtl\" : \"\") },\n        $container = $h.createElement($h.cspBuffer.stash(self._renderMain()));\n      $h.cspBuffer.apply($container);\n      $container.insertBefore(self.$element).attr(attribs);\n      self._initBrowse($container);\n      if (self.theme) {\n        $container.addClass(\"theme-\" + self.theme);\n      }\n      return $container;\n    },\n    _refreshContainer: function () {\n      var self = this,\n        $container = self.$container,\n        $el = self.$element;\n      $el.insertAfter($container);\n      $h.setHtml($container, self._renderMain());\n      self._initBrowse($container);\n      self._validateDisabled();\n    },\n    _validateDisabled: function () {\n      var self = this;\n      self.$caption.attr({ readonly: self.isDisabled });\n    },\n    _setTabIndex: function (type, html) {\n      var self = this,\n        index = self.tabIndexConfig[type];\n      return html.setTokens({\n        tabIndexConfig: index === undefined || index === null ? \"\" : 'tabindex=\"' + index + '\"',\n      });\n    },\n    _renderMain: function () {\n      var self = this,\n        dropCss = self.dropZoneEnabled ? \" file-drop-zone\" : \"file-drop-disabled\",\n        close = !self.showClose ? \"\" : self._getLayoutTemplate(\"close\"),\n        preview = !self.showPreview\n          ? \"\"\n          : self._getLayoutTemplate(\"preview\").setTokens({ class: self.previewClass, dropClass: dropCss }),\n        css = self.isDisabled ? self.captionClass + \" file-caption-disabled\" : self.captionClass,\n        caption = self.captionTemplate.setTokens({ class: css + \" kv-fileinput-caption\" });\n      caption = self._setTabIndex(\"caption\", caption);\n      return self.mainTemplate.setTokens({\n        class: self.mainClass + (!self.showBrowse && self.showCaption ? \" no-browse\" : \"\"),\n        inputGroupClass: self.inputGroupClass,\n        preview: preview,\n        close: close,\n        caption: caption,\n        upload: self._renderButton(\"upload\"),\n        remove: self._renderButton(\"remove\"),\n        cancel: self._renderButton(\"cancel\"),\n        pause: self._renderButton(\"pause\"),\n        browse: self._renderButton(\"browse\"),\n      });\n    },\n    _renderButton: function (type) {\n      var self = this,\n        tmplt = self._getLayoutTemplate(\"btnDefault\"),\n        css = self[type + \"Class\"],\n        title = self[type + \"Title\"],\n        icon = self[type + \"Icon\"],\n        label = self[type + \"Label\"],\n        status = self.isDisabled ? \" disabled\" : \"\",\n        btnType = \"button\";\n      switch (type) {\n        case \"remove\":\n          if (!self.showRemove) {\n            return \"\";\n          }\n          break;\n        case \"cancel\":\n          if (!self.showCancel) {\n            return \"\";\n          }\n          css += \" kv-hidden\";\n          break;\n        case \"pause\":\n          if (!self.showPause) {\n            return \"\";\n          }\n          css += \" kv-hidden\";\n          break;\n        case \"upload\":\n          if (!self.showUpload) {\n            return \"\";\n          }\n          if (self.isAjaxUpload && !self.isDisabled) {\n            tmplt = self._getLayoutTemplate(\"btnLink\").replace(\"{href}\", self.uploadUrl);\n          } else {\n            btnType = \"submit\";\n          }\n          break;\n        case \"browse\":\n          if (!self.showBrowse) {\n            return \"\";\n          }\n          tmplt = self._getLayoutTemplate(\"btnBrowse\");\n          break;\n        default:\n          return \"\";\n      }\n      tmplt = self._setTabIndex(type, tmplt);\n\n      css += type === \"browse\" ? \" btn-file\" : \" fileinput-\" + type + \" fileinput-\" + type + \"-button\";\n      if (!$h.isEmpty(label)) {\n        label = ' <span class=\"' + self.buttonLabelClass + '\">' + label + \"</span>\";\n      }\n      return tmplt.setTokens({\n        type: btnType,\n        css: css,\n        title: title,\n        status: status,\n        icon: icon,\n        label: label,\n      });\n    },\n    _renderThumbProgress: function () {\n      var self = this;\n      return (\n        '<div class=\"file-thumb-progress kv-hidden\">' +\n        self.progressInfoTemplate.setTokens({ percent: 101, status: self.msgUploadBegin, stats: \"\" }) +\n        \"</div>\"\n      );\n    },\n    _renderFileFooter: function (cat, caption, size, width, isError) {\n      var self = this,\n        config = self.fileActionSettings,\n        rem = config.showRemove,\n        drg = config.showDrag,\n        upl = config.showUpload,\n        rot = config.showRotate,\n        zoom = config.showZoom,\n        out,\n        params,\n        template = self._getLayoutTemplate(\"footer\"),\n        tInd = self._getLayoutTemplate(\"indicator\"),\n        ind = isError ? config.indicatorError : config.indicatorNew,\n        title = isError ? config.indicatorErrorTitle : config.indicatorNewTitle,\n        indicator = tInd.setTokens({ indicator: ind, indicatorTitle: title });\n      size = self._getSize(size);\n      params = { type: cat, caption: caption, size: size, width: width, progress: \"\", indicator: indicator };\n      if (self.isAjaxUpload) {\n        params.progress = self._renderThumbProgress();\n        params.actions = self._renderFileActions(params, upl, false, rem, rot, zoom, drg, false, false, false);\n      } else {\n        params.actions = self._renderFileActions(params, false, false, false, false, zoom, drg, false, false, false);\n      }\n      out = template.setTokens(params);\n      out = $h.replaceTags(out, self.previewThumbTags);\n      return out;\n    },\n    _renderFileActions: function (\n      cfg,\n      showUpl,\n      showDwn,\n      showDel,\n      showRot,\n      showZoom,\n      showDrag,\n      disabled,\n      url,\n      key,\n      isInit,\n      dUrl,\n      dFile\n    ) {\n      var self = this;\n      if (!cfg.type && isInit) {\n        cfg.type = \"image\";\n      }\n      if (self.enableResumableUpload) {\n        showUpl = false;\n      } else {\n        if (typeof showUpl === \"function\") {\n          showUpl = showUpl(cfg);\n        }\n      }\n      if (typeof showDwn === \"function\") {\n        showDwn = showDwn(cfg);\n      }\n      if (typeof showDel === \"function\") {\n        showDel = showDel(cfg);\n      }\n      if (typeof showZoom === \"function\") {\n        showZoom = showZoom(cfg);\n      }\n      if (typeof showDrag === \"function\") {\n        showDrag = showDrag(cfg);\n      }\n      if (typeof showRot === \"function\") {\n        showRot = showRot(cfg);\n      }\n      if (!showUpl && !showDwn && !showDel && !showRot && !showZoom && !showDrag) {\n        return \"\";\n      }\n      var vUrl = url === false ? \"\" : ' data-url=\"' + url + '\"',\n        btnZoom = \"\",\n        btnDrag = \"\",\n        btnRotate = \"\",\n        css,\n        vKey = key === false ? \"\" : ' data-key=\"' + key + '\"',\n        btnDelete = \"\",\n        btnUpload = \"\",\n        btnDownload = \"\",\n        template = self._getLayoutTemplate(\"actions\"),\n        config = self.fileActionSettings,\n        otherButtons = self.otherActionButtons.setTokens({ dataKey: vKey, key: key }),\n        removeClass = disabled ? config.removeClass + \" disabled\" : config.removeClass;\n      if (showDel) {\n        btnDelete = self._getLayoutTemplate(\"actionDelete\").setTokens({\n          removeClass: removeClass,\n          removeIcon: config.removeIcon,\n          removeTitle: config.removeTitle,\n          dataUrl: vUrl,\n          dataKey: vKey,\n          key: key,\n        });\n      }\n      if (showRot) {\n        btnRotate = self._getLayoutTemplate(\"actionRotate\").setTokens({\n          rotateClass: config.rotateClass,\n          rotateIcon: config.rotateIcon,\n          rotateTitle: config.rotateTitle,\n        });\n      }\n      if (showUpl) {\n        btnUpload = self._getLayoutTemplate(\"actionUpload\").setTokens({\n          uploadClass: config.uploadClass,\n          uploadIcon: config.uploadIcon,\n          uploadTitle: config.uploadTitle,\n        });\n      }\n      if (showDwn) {\n        btnDownload = self._getLayoutTemplate(\"actionDownload\").setTokens({\n          downloadClass: config.downloadClass,\n          downloadIcon: config.downloadIcon,\n          downloadTitle: config.downloadTitle,\n          downloadUrl: dUrl || self.initialPreviewDownloadUrl,\n        });\n        btnDownload = btnDownload.setTokens({ filename: dFile, key: key });\n      }\n      if (showZoom) {\n        btnZoom = self._getLayoutTemplate(\"actionZoom\").setTokens({\n          zoomClass: config.zoomClass,\n          zoomIcon: config.zoomIcon,\n          zoomTitle: config.zoomTitle,\n        });\n      }\n      if (showDrag && isInit) {\n        css = \"drag-handle-init \" + config.dragClass;\n        btnDrag = self._getLayoutTemplate(\"actionDrag\").setTokens({\n          dragClass: css,\n          dragTitle: config.dragTitle,\n          dragIcon: config.dragIcon,\n        });\n      }\n      return template.setTokens({\n        delete: btnDelete,\n        upload: btnUpload,\n        download: btnDownload,\n        rotate: btnRotate,\n        zoom: btnZoom,\n        drag: btnDrag,\n        other: otherButtons,\n      });\n    },\n    _browse: function (e) {\n      var self = this;\n      if ((e && e.isDefaultPrevented()) || !self._raise(\"filebrowse\")) {\n        return;\n      }\n      if (self.isError && !self.isAjaxUpload) {\n        self.clear();\n      }\n      if (self.focusCaptionOnBrowse) {\n        self.$captionContainer.focus();\n      }\n    },\n    _change: function (e) {\n      var self = this;\n      $(document.body).off(\"focusin.fileinput focusout.fileinput\");\n      if (self.changeTriggered) {\n        self._toggleLoading(\"hide\");\n        return;\n      }\n      self._toggleLoading(\"show\");\n      var $el = self.$element,\n        isDragDrop = arguments.length > 1,\n        isAjaxUpload = self.isAjaxUpload,\n        tfiles,\n        files = isDragDrop ? arguments[1] : $el[0].files,\n        ctr = self.fileManager.count(),\n        total,\n        initCount,\n        len,\n        isSingleUpl = $h.isEmpty($el.attr(\"multiple\")),\n        maxCount = !isAjaxUpload && isSingleUpl ? 1 : self.maxFileCount,\n        maxTotCount = self.maxTotalFileCount,\n        inclAll = maxTotCount > 0 && maxTotCount > maxCount,\n        flagSingle = isSingleUpl && ctr > 0,\n        throwError = function (mesg, file, previewId, index) {\n          var p1 = $.extend(true, {}, self._getOutData(null, {}, {}, files), { id: previewId, index: index }),\n            p2 = { id: previewId, index: index, file: file, files: files };\n          self.isPersistentError = true;\n          self._toggleLoading(\"hide\");\n          return isAjaxUpload ? self._showFileError(mesg, p1) : self._showError(mesg, p2);\n        },\n        maxCountCheck = function (n, m, all) {\n          var msg = all ? self.msgTotalFilesTooMany : self.msgFilesTooMany;\n          msg = msg.replace(\"{m}\", m).replace(\"{n}\", n);\n          self.isError = throwError(msg, null, null, null);\n          self.$captionContainer.removeClass(\"icon-visible\");\n          self._setCaption(\"\", true);\n          self.$container.removeClass(\"file-input-new file-input-ajax-new\");\n        };\n      self.reader = null;\n      self._resetUpload();\n      self._hideFileIcon();\n      if (self.dropZoneEnabled) {\n        self.$container.find(\".file-drop-zone .\" + self.dropZoneTitleClass).remove();\n      }\n      if (!isAjaxUpload) {\n        if (e.target && e.target.files === undefined) {\n          files = e.target.value ? [{ name: e.target.value.replace(/^.+\\\\/, \"\") }] : [];\n        } else {\n          files = e.target.files || {};\n        }\n      }\n      tfiles = files;\n      if ($h.isEmpty(tfiles) || tfiles.length === 0) {\n        if (!isAjaxUpload) {\n          self.clear();\n        }\n        self._raise(\"fileselectnone\");\n        return;\n      }\n      self._resetErrors();\n      len = tfiles.length;\n      initCount = isAjaxUpload ? self.fileManager.count() + len : len;\n      total = self._getFileCount(initCount, inclAll ? false : undefined);\n      if (maxCount > 0 && total > maxCount) {\n        if (!self.autoReplace || len > maxCount) {\n          maxCountCheck(self.autoReplace && len > maxCount ? len : total, maxCount);\n          return;\n        }\n        if (total > maxCount) {\n          self._resetPreviewThumbs(isAjaxUpload);\n        }\n      } else {\n        if (inclAll) {\n          total = self._getFileCount(initCount, true);\n          if (maxTotCount > 0 && total > maxTotCount) {\n            if (!self.autoReplace || len > maxCount) {\n              maxCountCheck(self.autoReplace && len > maxTotCount ? len : total, maxTotCount, true);\n              return;\n            }\n            if (total > maxCount) {\n              self._resetPreviewThumbs(isAjaxUpload);\n            }\n          }\n        }\n        if (!isAjaxUpload || flagSingle) {\n          self._resetPreviewThumbs(false);\n          if (flagSingle) {\n            self.clearFileStack();\n          }\n        } else {\n          if (isAjaxUpload && ctr === 0 && (!self.previewCache.count(true) || self.overwriteInitial)) {\n            self._resetPreviewThumbs(true);\n          }\n        }\n      }\n      if (self.autoReplace) {\n        self._getThumbs().each(function () {\n          var $thumb = $(this);\n          if ($thumb.hasClass(\"file-preview-success\") || $thumb.hasClass(\"file-preview-error\")) {\n            $thumb.remove();\n          }\n        });\n      }\n      self.readFiles(tfiles);\n      self._toggleLoading(\"hide\");\n    },\n    _abort: function (params) {\n      var self = this,\n        data;\n      if (self.ajaxAborted && typeof self.ajaxAborted === \"object\" && self.ajaxAborted.message !== undefined) {\n        data = $.extend(true, {}, self._getOutData(null), params);\n        data.abortData = self.ajaxAborted.data || {};\n        data.abortMessage = self.ajaxAborted.message;\n        self._setProgress(101, self.$progress, self.msgCancelled);\n        self._showFileError(self.ajaxAborted.message, data, \"filecustomerror\");\n        self.cancel();\n        self.unlock();\n        return true;\n      }\n      return !!self.ajaxAborted;\n    },\n    _resetFileStack: function () {\n      var self = this,\n        i = 0;\n      self._getThumbs().each(function () {\n        var $thumb = $(this),\n          ind = $thumb.attr(\"data-fileindex\"),\n          pid = $thumb.attr(\"id\");\n        if (ind === \"-1\" || ind === -1) {\n          return;\n        }\n        if (!self._getThumbFile($thumb)) {\n          $thumb.attr({ \"data-fileindex\": i });\n          i++;\n        } else {\n          $thumb.attr({ \"data-fileindex\": \"-1\" });\n        }\n        self._getZoom(pid).attr({\n          \"data-fileindex\": $thumb.attr(\"data-fileindex\"),\n        });\n      });\n    },\n    _isFileSelectionValid: function (cnt) {\n      var self = this;\n      cnt = cnt || 0;\n      if (self.required && !self.getFilesCount()) {\n        self.$errorContainer.html(\"\");\n        self._showFileError(self.msgFileRequired);\n        return false;\n      }\n      if (self.minFileCount > 0 && self._getFileCount(cnt) < self.minFileCount) {\n        self._noFilesError({});\n        return false;\n      }\n      return true;\n    },\n    _canPreview: function (file) {\n      var self = this;\n      if (!file || !self.showPreview || !self.$preview || !self.$preview.length) {\n        return false;\n      }\n      var name = file.name || \"\",\n        type = file.type || \"\",\n        size = (file.size || 0) / self.bytesToKB,\n        cat = self._parseFileType(type, name),\n        allowedTypes,\n        allowedMimes,\n        allowedExts,\n        skipPreview,\n        types = self.allowedPreviewTypes,\n        mimes = self.allowedPreviewMimeTypes,\n        exts = self.allowedPreviewExtensions || [],\n        dTypes = self.disabledPreviewTypes,\n        dMimes = self.disabledPreviewMimeTypes,\n        dExts = self.disabledPreviewExtensions || [],\n        maxSize = (self.maxFilePreviewSize && parseFloat(self.maxFilePreviewSize)) || 0,\n        expAllExt = new RegExp(\"\\\\.(\" + exts.join(\"|\") + \")$\", \"i\"),\n        expDisExt = new RegExp(\"\\\\.(\" + dExts.join(\"|\") + \")$\", \"i\");\n      allowedTypes = !types || types.indexOf(cat) !== -1;\n      allowedMimes = !mimes || mimes.indexOf(type) !== -1;\n      allowedExts = !exts.length || $h.compare(name, expAllExt);\n      skipPreview =\n        (dTypes && dTypes.indexOf(cat) !== -1) ||\n        (dMimes && dMimes.indexOf(type) !== -1) ||\n        (dExts.length && $h.compare(name, expDisExt)) ||\n        (maxSize && !isNaN(maxSize) && size > maxSize);\n      return !skipPreview && (allowedTypes || allowedMimes || allowedExts);\n    },\n    addToStack: function (file, id) {\n      var self = this;\n      self.stackIsUpdating = true;\n      self.fileManager.add(file, id);\n      self._refreshPreview();\n      self.stackIsUpdating = false;\n    },\n    clearFileStack: function () {\n      var self = this;\n      self.fileManager.clear();\n      self._initResumableUpload();\n      if (self.enableResumableUpload) {\n        if (self.showPause === null) {\n          self.showPause = true;\n        }\n        if (self.showCancel === null) {\n          self.showCancel = false;\n        }\n      } else {\n        self.showPause = false;\n        if (self.showCancel === null) {\n          self.showCancel = true;\n        }\n      }\n      return self.$element;\n    },\n    getFileStack: function () {\n      return this.fileManager.stack;\n    },\n    getFileList: function () {\n      return this.fileManager.list();\n    },\n    getFilesSize: function () {\n      return this.fileManager.getTotalSize();\n    },\n    getFilesCount: function (includeInitial) {\n      var self = this,\n        len = self.isAjaxUpload ? self.fileManager.count() : self._inputFileCount();\n      if (includeInitial) {\n        len += self.previewCache.count(true);\n      }\n      return self._getFileCount(len);\n    },\n    _initCapStatus: function (status) {\n      var self = this,\n        $cap = self.$caption;\n      $cap.removeClass(\"is-valid file-processing\");\n      if (!status) {\n        return;\n      }\n      if (status === \"processing\") {\n        $cap.addClass(\"file-processing\");\n      } else {\n        $cap.addClass(\"is-valid\");\n      }\n    },\n    _toggleLoading: function (type) {\n      var self = this;\n      $h.setHtml(self.$previewStatus, type === \"hide\" ? \"\" : self.msgProcessing);\n      self.$container.removeClass(\"file-thumb-loading\");\n      self._initCapStatus(type === \"hide\" ? \"\" : \"processing\");\n      if (type !== \"hide\") {\n        if (self.dropZoneEnabled) {\n          self.$container.find(\".file-drop-zone .\" + self.dropZoneTitleClass).remove();\n        }\n        self.$container.addClass(\"file-thumb-loading\");\n      }\n    },\n    _initFileSelected: function () {\n      var self = this,\n        $el = self.$element,\n        $body = $(document.body),\n        ev = \"focusin.fileinput focusout.fileinput\";\n      if ($body.length) {\n        $body\n          .off(ev)\n          .on(\"focusout.fileinput\", function () {\n            self._toggleLoading(\"show\");\n          })\n          .on(\"focusin.fileinput\", function () {\n            setTimeout(function () {\n              if (!$el.val()) {\n                self._setFileDropZoneTitle();\n              }\n              $body.off(ev);\n              self._toggleLoading(\"hide\");\n            }, 2500);\n          });\n      } else {\n        self._toggleLoading(\"hide\");\n      }\n    },\n    readFiles: function (files) {\n      this.reader = new FileReader();\n      var self = this,\n        reader = self.reader,\n        $container = self.$previewContainer,\n        $status = self.$previewStatus,\n        msgLoading = self.msgLoading,\n        msgProgress = self.msgProgress,\n        previewInitId = self.previewInitId,\n        numFiles = files.length,\n        settings = self.fileTypeSettings,\n        readFile,\n        fileTypes = self.allowedFileTypes,\n        typLen = fileTypes ? fileTypes.length : 0,\n        fileExt = self.allowedFileExtensions,\n        strExt = $h.isEmpty(fileExt) ? \"\" : fileExt.join(\", \"),\n        throwError = function (msg, file, previewId, index, fileId) {\n          var $thumb,\n            p1 = $.extend(true, {}, self._getOutData(null, {}, {}, files), {\n              id: previewId,\n              index: index,\n              fileId: fileId,\n            }),\n            p2 = { id: previewId, index: index, fileId: fileId, file: file, files: files };\n          Object.values(files).forEach((x) => {\n            self._previewDefault(x, true);\n          });\n          $thumb = self._getFrame(previewId, true);\n          self._toggleLoading(\"hide\");\n          if (self.isAjaxUpload) {\n            setTimeout(function () {\n              readFile(index + 1);\n            }, self.processDelay);\n          } else {\n            self.unlock();\n            numFiles = 0;\n          }\n          if (self.removeFromPreviewOnError && $thumb.length) {\n            $thumb.remove();\n          } else {\n            self._initFileActions();\n            $thumb.find(\".kv-file-upload\").remove();\n          }\n          self.isPersistentError = true;\n          self.isError = self.isAjaxUpload ? self._showFileError(msg, p1) : self._showError(msg, p2);\n          self._updateFileDetails(numFiles);\n        };\n      self.fileManager.clearImages();\n      $.each(files, function (key, file) {\n        var func = self.fileTypeSettings.image;\n        if (func && func(file.type)) {\n          self.fileManager.totalImages++;\n        }\n      });\n      readFile = function (i) {\n        var $error = self.$errorContainer,\n          errors,\n          fm = self.fileManager;\n        if (i >= numFiles) {\n          self.unlock();\n          if (self.duplicateErrors.length) {\n            errors = \"<li>\" + self.duplicateErrors.join(\"</li><li>\") + \"</li>\";\n            if ($error.find(\"ul\").length === 0) {\n              $h.setHtml($error, self.errorCloseButton + \"<ul>\" + errors + \"</ul>\");\n            } else {\n              $error.find(\"ul\").append($h.cspBuffer.stash(errors));\n              $h.cspBuffer.apply($error);\n            }\n            $error.fadeIn(self.fadeDelay);\n            self._handler($error.find(\".kv-error-close\"), \"click\", function () {\n              $error.fadeOut(self.fadeDelay);\n            });\n            self.duplicateErrors = [];\n          }\n          if (self.isAjaxUpload) {\n            self._raise(\"filebatchselected\", [fm.stack]);\n            if (fm.count() === 0 && !self.isError) {\n              self.reset();\n            }\n          } else {\n            self._raise(\"filebatchselected\", [files]);\n          }\n          $container.removeClass(\"file-thumb-loading\");\n          self._initCapStatus(\"valid\");\n          $status.html(\"\");\n          return;\n        }\n        self.lock(true);\n        var file = files[i],\n          id,\n          previewId,\n          fileProcessed,\n          fSize = (file && file.size) || 0,\n          sizeHuman = self._getSize(fSize, true),\n          j,\n          msg,\n          fnImage = settings.image,\n          chk,\n          typ,\n          typ1,\n          typ2,\n          caption,\n          fileSize = fSize / self.bytesToKB,\n          fileExtExpr = \"\",\n          previewData,\n          fileCount = 0,\n          strTypes = \"\",\n          fileId,\n          canLoad,\n          fileReaderAborted = false,\n          func,\n          knownTypes = 0,\n          isImage,\n          processFileLoaded,\n          initFileData;\n        initFileData = function (dataSource) {\n          dataSource = dataSource || file;\n          id = fileId = self._getFileId(file);\n          previewId = previewInitId + \"-\" + id;\n          previewData = $h.createObjectURL(dataSource);\n          caption = self._getFileName(file, \"\");\n        };\n        processFileLoaded = function () {\n          var isImageResized = !!fm.loadedImages[id],\n            msg = msgProgress.setTokens({\n              index: i + 1,\n              files: numFiles,\n              percent: 50,\n              name: caption,\n            });\n          setTimeout(function () {\n            $h.setHtml($status, msg);\n            self._updateFileDetails(numFiles);\n            if (self.getFilesCount(true) > 0 && self.getFrames(\":visible\")) {\n              self.$dropZone.find(\".\" + self.dropZoneTitleClass).remove();\n            }\n            readFile(i + 1);\n          }, self.processDelay);\n          if (self._raise(\"fileloaded\", [file, previewId, id, i, reader]) && self.isAjaxUpload) {\n            if (!isImageResized) {\n              fm.add(file);\n            }\n          } else {\n            if (isImageResized) {\n              fm.removeFile(id);\n            }\n          }\n        };\n        if (!file) {\n          return;\n        }\n        initFileData();\n\n        if (typLen > 0) {\n          for (j = 0; j < typLen; j++) {\n            typ1 = fileTypes[j];\n            typ2 = self.msgFileTypes[typ1] || typ1;\n            strTypes += j === 0 ? typ2 : \", \" + typ2;\n          }\n        }\n        if (caption === false) {\n          readFile(i + 1);\n          return;\n        }\n        if (caption.length === 0) {\n          msg = self.msgInvalidFileName.replace(\"{name}\", $h.htmlEncode($h.getFileName(file), \"[unknown]\"));\n          throwError(msg, file, previewId, i, fileId);\n          return;\n        }\n        if (!$h.isEmpty(fileExt)) {\n          fileExtExpr = new RegExp(\"\\\\.(\" + fileExt.join(\"|\") + \")$\", \"i\");\n        }\n        if ((self.isAjaxUpload && fm.exists(fileId)) || self._getFrame(previewId, true).length) {\n          var p2 = { id: previewId, index: i, fileId: fileId, file: file, files: files };\n          msg = self.msgDuplicateFile.setTokens({ name: caption, size: sizeHuman });\n          if (self.isAjaxUpload) {\n            if (!self.stackIsUpdating) {\n              self.duplicateErrors.push(msg);\n              self.isDuplicateError = true;\n              self._raise(\"fileduplicateerror\", [file, fileId, caption, sizeHuman, previewId, i]);\n            }\n            readFile(i + 1);\n            self._updateFileDetails(numFiles);\n          } else {\n            self._showError(msg, p2);\n            self.unlock();\n            numFiles = 0;\n            self._clearFileInput();\n            self.reset();\n            self._updateFileDetails(numFiles);\n          }\n          return;\n        }\n\n        if (self.maxMultipleFileSize > 0 && files.length > 1) {\n          var captionGroup = [];\n          var fileSizeGroup = 0;\n          Object.values(files).forEach((file) => {\n            fileSizeGroup = fileSizeGroup + file.size / self.bytesToKB;\n            captionGroup.push(file.name);\n          });\n\n          if (fileSizeGroup > self.maxMultipleFileSize) {\n            msg = self.msgMultipleSizeTooLarge.setTokens({\n              name: captionGroup,\n              size: self._getSize(fileSizeGroup, true),\n              maxSize: self._getSize(self.maxMultipleFileSize * self.bytesToKB, true),\n            });\n\n            throwError(msg, file, previewId, i, fileId);\n            return;\n          }\n        } else if (self.maxFileSize > 0 && fileSize > self.maxFileSize) {\n          msg = self.msgSizeTooLarge.setTokens({\n            name: caption,\n            size: sizeHuman,\n            maxSize: self._getSize(self.maxFileSize * self.bytesToKB, true),\n          });\n          throwError(msg, file, previewId, i, fileId);\n          return;\n        }\n        if (self.minFileSize !== null && fileSize <= $h.getNum(self.minFileSize)) {\n          msg = self.msgSizeTooSmall.setTokens({\n            name: caption,\n            size: sizeHuman,\n            minSize: self._getSize(self.minFileSize * self.bytesToKB, true),\n          });\n          throwError(msg, file, previewId, i, fileId);\n          return;\n        }\n        if (!$h.isEmpty(fileTypes) && $h.isArray(fileTypes)) {\n          for (j = 0; j < fileTypes.length; j += 1) {\n            typ = fileTypes[j];\n            func = settings[typ];\n            fileCount += !func || typeof func !== \"function\" ? 0 : func(file.type, $h.getFileName(file)) ? 1 : 0;\n          }\n          if (fileCount === 0) {\n            msg = self.msgInvalidFileType.setTokens({ name: caption, types: strTypes });\n            throwError(msg, file, previewId, i, fileId);\n            return;\n          }\n        }\n        if (fileCount === 0 && !$h.isEmpty(fileExt) && $h.isArray(fileExt) && !$h.isEmpty(fileExtExpr)) {\n          chk = $h.compare(caption, fileExtExpr);\n          fileCount += $h.isEmpty(chk) ? 0 : chk.length;\n          if (fileCount === 0) {\n            msg = self.msgInvalidFileExtension.setTokens({ name: caption, extensions: strExt });\n            throwError(msg, file, previewId, i, fileId);\n            return;\n          }\n        }\n        if (!self._canPreview(file)) {\n          canLoad = self._raise(\"filebeforeload\", [file, i, reader]);\n          if (self.isAjaxUpload && canLoad) {\n            fm.add(file);\n          }\n          if (self.showPreview && canLoad) {\n            $container.addClass(\"file-thumb-loading\");\n            self._initCapStatus(\"processing\");\n            self._previewDefault(file);\n            self._initFileActions();\n          }\n          setTimeout(function () {\n            if (canLoad) {\n              self._updateFileDetails(numFiles);\n            }\n            readFile(i + 1);\n            self._raise(\"fileloaded\", [file, previewId, id, i]);\n          }, 10);\n          return;\n        }\n        isImage = fnImage(file.type, caption);\n        $h.setHtml($status, msgLoading.replace(\"{index}\", i + 1).replace(\"{files}\", numFiles));\n        $container.addClass(\"file-thumb-loading\");\n        self._initCapStatus(\"processing\");\n        reader.onerror = function (evt) {\n          self._errorHandler(evt, caption);\n        };\n        reader.onload = function (theFile) {\n          var hex,\n            fileInfo,\n            fileData,\n            byte,\n            bytes = [],\n            contents,\n            mime,\n            processPreview = function (fType, ext) {\n              if ($h.isEmpty(fType)) {\n                // look for ascii text content\n                contents = $h.arrayBuffer2String(reader.result);\n                fType = $h.isSvg(contents) ? \"image/svg+xml\" : $h.getMimeType(hex, contents, file.type);\n              }\n              fileInfo = { name: caption, type: fType || \"\" };\n              if (ext && typeof File !== \"undefined\") {\n                try {\n                  var fName = (fileInfo.filename = caption + \".\" + ext);\n                  fileProcessed = new File([file], fName, { type: fileInfo.type });\n                  initFileData(fileProcessed);\n                } catch (err) {}\n              }\n              isImage = fnImage(fType, \"\");\n              if (isImage) {\n                var newReader = new FileReader();\n                newReader.onerror = function (theFileNew) {\n                  self._errorHandler(theFileNew, caption);\n                };\n                newReader.onload = function (theFileNew) {\n                  if (self.isAjaxUpload && !self._raise(\"filebeforeload\", [file, i, reader])) {\n                    fileReaderAborted = true;\n                    self._resetCaption();\n                    reader.abort();\n                    $status.html(\"\");\n                    $container.removeClass(\"file-thumb-loading\");\n                    self._initCapStatus(\"valid\");\n                    self.enable();\n                    return;\n                  }\n                  self._previewFile(i, file, theFileNew, previewData, fileInfo);\n                  self._initFileActions();\n                  processFileLoaded();\n                };\n                newReader.readAsDataURL(file);\n                return;\n              }\n              if (self.isAjaxUpload && !self._raise(\"filebeforeload\", [file, i, reader])) {\n                fileReaderAborted = true;\n                self._resetCaption();\n                reader.abort();\n                $status.html(\"\");\n                $container.removeClass(\"file-thumb-loading\");\n                self._initCapStatus(\"valid\");\n                self.enable();\n                return;\n              }\n              self._previewFile(i, file, theFile, previewData, fileInfo);\n              self._initFileActions();\n              processFileLoaded();\n            };\n          mime = file.type;\n          fileInfo = { name: caption, type: mime };\n          $.each(settings, function (k, f) {\n            if (k !== \"object\" && k !== \"other\" && typeof f === \"function\" && f(mime, caption)) {\n              knownTypes++;\n            }\n          });\n          if (typeof FileTypeParser !== \"undefined\") {\n            fileData = new Uint8Array(theFile.target.result);\n            new FileTypeParser().parse(fileData).then(function (result) {\n              processPreview((result && result.mime) || mime, (result && result.ext) || \"\");\n            });\n          } else {\n            if (knownTypes === 0) {\n              // auto detect mime types from content if no known file types detected\n              fileData = new Uint8Array(theFile.target.result);\n              for (j = 0; j < fileData.length; j++) {\n                byte = fileData[j].toString(16);\n                bytes.push(byte);\n              }\n              hex = bytes.join(\"\").toLowerCase().substring(0, 8);\n              mime = $h.getMimeType(hex, \"\", \"\");\n            }\n            processPreview(mime);\n          }\n        };\n        reader.onprogress = function (data) {\n          if (data.lengthComputable) {\n            var fact = (data.loaded / data.total) * 100,\n              progress = Math.ceil(fact);\n            msg = msgProgress.setTokens({\n              index: i + 1,\n              files: numFiles,\n              percent: progress,\n              name: caption,\n            });\n            setTimeout(function () {\n              if (!fileReaderAborted) {\n                $h.setHtml($status, msg);\n              }\n            }, self.processDelay);\n          }\n        };\n        reader.readAsArrayBuffer(file);\n      };\n\n      readFile(0);\n      self._updateFileDetails(numFiles);\n    },\n    lock: function (selectMode) {\n      var self = this,\n        $container = self.$container;\n      self._resetErrors();\n      self.disable();\n      if (!selectMode && self.showCancel) {\n        $container.find(\".fileinput-cancel\").show();\n      }\n      if (!selectMode && self.showPause) {\n        $container.find(\".fileinput-pause\").show();\n      }\n      self._initCapStatus(\"processing\");\n      self._raise(\"filelock\", [self.fileManager.stack, self._getExtraData()]);\n      return self.$element;\n    },\n    unlock: function (reset) {\n      var self = this,\n        $container = self.$container;\n      if (reset === undefined) {\n        reset = true;\n      }\n      self.enable();\n      $container.removeClass(\"is-locked\");\n      if (self.showCancel) {\n        $container.find(\".fileinput-cancel\").hide();\n      }\n      if (self.showPause) {\n        $container.find(\".fileinput-pause\").hide();\n      }\n      if (reset) {\n        self._resetFileStack();\n      }\n      self._initCapStatus();\n      self._raise(\"fileunlock\", [self.fileManager.stack, self._getExtraData()]);\n      return self.$element;\n    },\n    resume: function () {\n      var self = this,\n        fm = self.fileManager,\n        flag = false,\n        rm = self.resumableManager;\n      fm.bpsLog = [];\n      fm.bps = 0;\n      if (!self.enableResumableUpload) {\n        return self.$element;\n      }\n      if (self.paused) {\n        self._toggleResumableProgress(self.progressPauseTemplate, self.msgUploadResume);\n      } else {\n        flag = true;\n      }\n      self.paused = false;\n      if (flag) {\n        self._toggleResumableProgress(self.progressInfoTemplate, self.msgUploadBegin);\n      }\n      setTimeout(function () {\n        rm.upload();\n      }, self.processDelay);\n      return self.$element;\n    },\n    paste: function (e) {\n      var self = this,\n        dt = e.clipboardData || e.originalEvent.clipboardData;\n      self._addFilesFromSystem(e, dt, \"filePaste\");\n      return self.$element;\n    },\n    pause: function () {\n      var self = this,\n        rm = self.resumableManager,\n        xhr = self.ajaxRequests,\n        len = xhr.length,\n        i,\n        pct = rm.getProgress(),\n        actions = self.fileActionSettings,\n        tm = self.taskManager,\n        pool = tm.getPool(rm.id);\n      if (!self.enableResumableUpload) {\n        return self.$element;\n      } else {\n        if (pool) {\n          pool.cancel();\n        }\n      }\n      self._raise(\"fileuploadpaused\", [self.fileManager, rm]);\n      if (len > 0) {\n        for (i = 0; i < len; i += 1) {\n          self.paused = true;\n          xhr[i].abort();\n        }\n      }\n      if (self.showPreview) {\n        self._getThumbs().each(function () {\n          var $thumb = $(this),\n            t = self._getLayoutTemplate(\"stats\"),\n            stats,\n            $indicator = $thumb.find(\".file-upload-indicator\");\n          $thumb.removeClass(\"file-uploading\");\n          if ($indicator.attr(\"title\") === actions.indicatorLoadingTitle) {\n            self._setThumbStatus($thumb, \"Paused\");\n            stats = t.setTokens({ pendingTime: self.msgPaused, uploadSpeed: \"\" });\n            self.paused = true;\n            self._setProgress(pct, $thumb.find(\".file-thumb-progress\"), pct + \"%\", stats);\n          }\n          if (!self._getThumbFile($thumb)) {\n            $thumb.find(\".kv-file-remove\").removeClass(\"disabled\").removeAttr(\"disabled\");\n          }\n        });\n      }\n      self._setProgress(101, self.$progress, self.msgPaused);\n      return self.$element;\n    },\n    cancel: function () {\n      var self = this,\n        xhr = self.ajaxRequests,\n        rm = self.resumableManager,\n        tm = self.taskManager,\n        pool = rm ? tm.getPool(rm.id) : undefined,\n        len = xhr.length,\n        i;\n      if (self.enableResumableUpload && pool) {\n        pool.cancel().done(function () {\n          self._setProgressCancelled();\n        });\n        rm.reset();\n        self._raise(\"fileuploadcancelled\", [self.fileManager, rm]);\n      } else {\n        if (self.ajaxPool) {\n          self.ajaxPool.cancel();\n        }\n        self._raise(\"fileuploadcancelled\", [self.fileManager]);\n      }\n      self._initAjax();\n      if (len > 0) {\n        for (i = 0; i < len; i += 1) {\n          self.cancelling = true;\n          xhr[i].abort();\n        }\n      }\n      self._getThumbs().each(function () {\n        var $thumb = $(this),\n          $prog = $thumb.find(\".file-thumb-progress\");\n        $thumb.removeClass(\"file-uploading\");\n        self._setProgress(0, $prog);\n        $prog.hide();\n        if (!self._getThumbFile($thumb)) {\n          $thumb.find(\".kv-file-upload\").removeClass(\"disabled\").removeAttr(\"disabled\");\n          $thumb.find(\".kv-file-remove\").removeClass(\"disabled\").removeAttr(\"disabled\");\n        }\n        self.unlock();\n      });\n      setTimeout(function () {\n        self._setProgressCancelled();\n      }, self.processDelay);\n      return self.$element;\n    },\n    clear: function () {\n      var self = this,\n        cap;\n      if (!self._raise(\"fileclear\")) {\n        return;\n      }\n      self.clearInput = true;\n      self.$btnUpload.removeAttr(\"disabled\");\n      self\n        ._getThumbs()\n        .find(\"video,audio,img\")\n        .each(function () {\n          $h.cleanMemory($(this));\n        });\n      self._clearFileInput();\n      self._resetUpload();\n      self.clearFileStack();\n      self.isDuplicateError = false;\n      self.isPersistentError = false;\n      self._resetErrors(true);\n      if (self._hasInitialPreview()) {\n        self._showFileIcon();\n        self._resetPreview();\n        self._initPreviewActions();\n        self.$container.removeClass(\"file-input-new\");\n      } else {\n        self._getThumbs().each(function () {\n          self._clearObjects($(this));\n        });\n        if (self.isAjaxUpload) {\n          self.previewCache.data = {};\n        }\n        self.$preview.html(\"\");\n        cap = !self.overwriteInitial && self.initialCaption.length > 0 ? self.initialCaption : \"\";\n        self.$caption.attr(\"title\", \"\").val(cap);\n        $h.addCss(self.$container, \"file-input-new\");\n        self._validateDefaultPreview();\n      }\n      if (self.$container.find($h.FRAMES).length === 0) {\n        if (!self._initCaption()) {\n          self.$captionContainer.removeClass(\"icon-visible\");\n        }\n      }\n      self._hideFileIcon();\n      if (self.focusCaptionOnClear) {\n        self.$captionContainer.focus();\n      }\n      self._setFileDropZoneTitle();\n      self._raise(\"filecleared\");\n      return self.$element;\n    },\n    reset: function () {\n      var self = this;\n      if (!self._raise(\"filereset\")) {\n        return;\n      }\n      self.lastProgress = 0;\n      self._resetPreview();\n      self.$container.find(\".fileinput-filename\").text(\"\");\n      $h.addCss(self.$container, \"file-input-new\");\n      if (self.getFrames().length) {\n        self.$container.removeClass(\"file-input-new\");\n      }\n      self.clearFileStack();\n      self._setFileDropZoneTitle();\n      return self.$element;\n    },\n    disable: function () {\n      var self = this,\n        $container = self.$container;\n      self.isDisabled = true;\n      self._raise(\"filedisabled\");\n      self.$element.attr(\"disabled\", \"disabled\");\n      $container.addClass(\"is-locked\");\n      $h.addCss($container.find(\".btn-file\"), \"disabled\");\n      $container.find(\".kv-fileinput-caption\").addClass(\"file-caption-disabled\");\n      $container.find(\".fileinput-remove, .fileinput-upload, .file-preview-frame button\").attr(\"disabled\", true);\n      self._initDragDrop();\n      return self.$element;\n    },\n    enable: function () {\n      var self = this,\n        $container = self.$container;\n      self.isDisabled = false;\n      self._raise(\"fileenabled\");\n      self.$element.removeAttr(\"disabled\");\n      $container.removeClass(\"is-locked\");\n      $container.find(\".kv-fileinput-caption\").removeClass(\"file-caption-disabled\");\n      $container.find(\".fileinput-remove, .fileinput-upload, .file-preview-frame button\").removeAttr(\"disabled\");\n      $container.find(\".btn-file\").removeClass(\"disabled\");\n      self._initDragDrop();\n      return self.$element;\n    },\n    upload: function () {\n      var self = this,\n        fm = self.fileManager,\n        totLen = fm.count(),\n        i,\n        outData,\n        tm = self.taskManager,\n        hasExtraData = !$.isEmptyObject(self._getExtraData());\n      fm.bpsLog = [];\n      fm.bps = 0;\n      if (!self.isAjaxUpload || self.isDisabled || !self._isFileSelectionValid(totLen)) {\n        return;\n      }\n      self.lastProgress = 0;\n      self._resetUpload();\n      if (totLen === 0 && !hasExtraData) {\n        self._showFileError(self.msgUploadEmpty);\n        return;\n      }\n      self.cancelling = false;\n      self.uploadInitiated = true;\n      self._showProgress();\n      self.lock();\n      if (totLen === 0 && hasExtraData) {\n        self._setProgress(2);\n        self._uploadExtraOnly();\n        return;\n      }\n      if (self.enableResumableUpload) {\n        return self.resume();\n      }\n      if (self.uploadAsync || self.enableResumableUpload) {\n        outData = self._getOutData(null);\n        if (!self._checkBatchPreupload(outData)) {\n          return;\n        }\n        self.fileBatchCompleted = false;\n        self.uploadCache = [];\n        $.each(self.getFileStack(), function (id) {\n          var previewId = self._getThumbId(id);\n          self.uploadCache.push({ id: previewId, content: null, config: null, tags: null, append: true });\n        });\n        self.$preview.find(\".file-preview-initial\").removeClass($h.SORT_CSS);\n        self._initSortable();\n      }\n      self._setProgress(2);\n      self.hasInitData = false;\n      if (self.uploadAsync) {\n        i = 0;\n        var pool = (self.ajaxPool = tm.addPool($h.uniqId()));\n        $.each(self.getFileStack(), function (id) {\n          pool.addTask(id + i, function (deferrer) {\n            self._uploadSingle(i, id, true, deferrer);\n          });\n          i++;\n        });\n\n        pool\n          .run(self.maxAjaxThreads)\n          .done(function () {\n            self._log(\"Async upload batch completed successfully.\");\n            self._raise(\"filebatchuploadsuccess\", [fm.stack, self._getExtraData()]);\n          })\n          .fail(function () {\n            self._log(\"Async upload batch completed with errors.\");\n            self._raise(\"filebatchuploaderror\", [fm.stack, self._getExtraData()]);\n          });\n        return;\n      }\n      self._uploadBatch();\n      return self.$element;\n    },\n    destroy: function () {\n      var self = this,\n        $form = self.$form,\n        $cont = self.$container,\n        $el = self.$element,\n        ns = self.namespace;\n      $(document).off(ns);\n      $(window).off(ns);\n      if ($form && $form.length) {\n        $form.off(ns);\n      }\n      if (self.isAjaxUpload) {\n        self._clearFileInput();\n      }\n      self._cleanup();\n      self._initPreviewCache();\n      $el.insertBefore($cont).off(ns).removeData();\n      $cont.off().remove();\n      return $el;\n    },\n    refresh: function (options) {\n      var self = this,\n        $el = self.$element;\n      if (typeof options !== \"object\" || $h.isEmpty(options)) {\n        options = self.options;\n      } else {\n        options = $.extend(true, {}, self.options, options);\n      }\n      self._init(options, true);\n      self._listen();\n      return $el;\n    },\n    zoom: function (frameId) {\n      var self = this,\n        $frame = self._getFrame(frameId);\n      self._showModal($frame);\n    },\n    getExif: function (frameId) {\n      var self = this,\n        $frame = self._getFrame(frameId);\n      return ($frame && $frame.data(\"exif\")) || null;\n    },\n    getFrames: function (cssFilter) {\n      var self = this,\n        $frames;\n      cssFilter = cssFilter || \"\";\n      $frames = self.$preview.find($h.FRAMES + cssFilter);\n      if (self.reversePreviewOrder) {\n        $frames = $($frames.get().reverse());\n      }\n      return $frames;\n    },\n    getPreview: function () {\n      var self = this;\n      return {\n        content: self.initialPreview,\n        config: self.initialPreviewConfig,\n        tags: self.initialPreviewThumbTags,\n      };\n    },\n  };\n\n  $.fn.fileinput = function (option) {\n    if (!$h.hasFileAPISupport() && !$h.isIE(9)) {\n      return;\n    }\n    var args = Array.apply(null, arguments),\n      retvals = [];\n    args.shift();\n    this.each(function () {\n      var options = {}, optObj = {};\n      if (typeof option === \"object\") {\n        options = $.extend(true, {}, $.fn.fileinput.defaults, option);\n        optObj = option;\n      } \n      var self = $(this),\n        data = self.data(\"fileinput\"),\n        theme = options.theme || self.data(\"theme\") || $.fn.fileinput.defaults.theme,\n        l = {},\n        t = {},\n        lang = options.language || self.data(\"language\") || $.fn.fileinput.defaults.language || \"en\",\n        opt;\n      if (!data) {\n        if (theme) {\n          t = $.fn.fileinputThemes[theme] || {};\n        }\n        if (lang !== \"en\" && !$h.isEmpty($.fn.fileinputLocales[lang])) {\n          l = $.fn.fileinputLocales[lang] || {};\n        }\n        opt = $.extend(true, {}, $.fn.fileinput.defaults, t, $.fn.fileinputLocales.en, l, optObj, self.data());\n        data = new FileInput(this, opt);\n        self.data(\"fileinput\", data);\n      }\n\n      if (typeof option === \"string\") {\n        retvals.push(data[option].apply(data, args));\n      }\n    });\n    switch (retvals.length) {\n      case 0:\n        return this;\n      case 1:\n        return retvals[0];\n      default:\n        return retvals;\n    }\n  };\n\n  var IFRAME_ATTRIBS = 'class=\"kv-preview-data file-preview-pdf\" src=\"{renderer}?file={data}\" {style}',\n    defBtnCss1 = \"btn btn-sm btn-kv \" + $h.defaultButtonCss(),\n    defBtnCss2 = \"btn \" + $h.defaultButtonCss();\n\n  $.fn.fileinput.defaults = {\n    language: \"zh\",\n    bytesToKB: 1024,\n    showCaption: true,\n    showBrowse: true,\n    showPreview: true,\n    showRemove: true,\n    showUpload: true,\n    showUploadStats: true,\n    showCancel: null,\n    showPause: null,\n    showClose: true,\n    showUploadedThumbs: true,\n    showConsoleLogs: false,\n    browseOnZoneClick: false,\n    autoReplace: false,\n    showDescriptionClose: true,\n    autoOrientImage: function () {\n      // applicable for JPEG images only and non ios safari\n      var ua = window.navigator.userAgent,\n        webkit = !!ua.match(/WebKit/i),\n        iOS = !!ua.match(/iP(od|ad|hone)/i),\n        iOSSafari = iOS && webkit && !ua.match(/CriOS/i);\n      return !iOSSafari;\n    },\n    autoOrientImageInitial: true,\n    showExifErrorLog: false,\n    required: false,\n    rtl: false,\n    hideThumbnailContent: false,\n    encodeUrl: true,\n    focusCaptionOnBrowse: true,\n    focusCaptionOnClear: true,\n    generateFileId: null,\n    previewClass: \"\",\n    captionClass: \"\",\n    frameClass: \"krajee-default\",\n    mainClass: \"\",\n    inputGroupClass: \"\",\n    mainTemplate: null,\n    fileSizeGetter: null,\n    initialCaption: \"\",\n    initialPreview: [],\n    initialPreviewDelimiter: \"*$$*\",\n    initialPreviewAsData: false,\n    initialPreviewFileType: \"image\",\n    initialPreviewConfig: [],\n    initialPreviewThumbTags: [],\n    previewThumbTags: {},\n    initialPreviewShowDelete: true,\n    initialPreviewDownloadUrl: \"\",\n    removeFromPreviewOnError: false,\n    deleteUrl: \"\",\n    deleteExtraData: {},\n    overwriteInitial: true,\n    sanitizeZoomCache: function (content) {\n      var $container = $h.createDiv();\n      $h.setHtml($container, content);\n      $container.find(\"input,textarea,select,datalist,form,.file-thumbnail-footer\").remove();\n      return $container.html();\n    },\n    previewZoomButtonIcons: {\n      prev: '<i class=\"glyphicon glyphicon-triangle-left\"></i>',\n      next: '<i class=\"glyphicon glyphicon-triangle-right\"></i>',\n      toggleheader: '<i class=\"glyphicon glyphicon-resize-vertical\"></i>',\n      fullscreen: '<i class=\"glyphicon glyphicon-fullscreen\"></i>',\n      borderless: '<i class=\"glyphicon glyphicon-resize-full\"></i>',\n      close: '<i class=\"glyphicon glyphicon-remove\"></i>'\n    },\n    previewZoomButtonClasses: {\n      prev: \"btn btn-default btn-outline-secondary btn-navigate\",\n      next: \"btn btn-default btn-outline-secondary btn-navigate\",\n      rotate: defBtnCss1,\n      toggleheader: defBtnCss1,\n      fullscreen: defBtnCss1,\n      borderless: defBtnCss1,\n      close: defBtnCss1,\n    },\n    previewTemplates: {},\n    previewContentTemplates: {},\n    preferIconicPreview: false,\n    preferIconicZoomPreview: false,\n    alwaysPreviewFileExtensions: [],\n    rotatableFileExtensions: [\"jpg\", \"jpeg\", \"png\", \"gif\"],\n    allowedFileTypes: null,\n    allowedFileExtensions: null,\n    allowedPreviewTypes: undefined,\n    allowedPreviewMimeTypes: null,\n    allowedPreviewExtensions: null,\n    disabledPreviewTypes: undefined,\n    disabledPreviewExtensions: [\"msi\", \"exe\", \"com\", \"zip\", \"rar\", \"app\", \"vb\", \"scr\"],\n    disabledPreviewMimeTypes: null,\n    defaultPreviewContent: null,\n    customLayoutTags: {},\n    customPreviewTags: {},\n    previewFileIcon: '<i class=\"bi-file-earmark-fill\"></i>',\n    previewFileIconClass: \"file-other-icon\",\n    previewFileIconSettings: {},\n    previewFileExtSettings: {},\n    buttonLabelClass: \"hidden-xs\",\n    browseIcon: '<i class=\"bi-folder2-open\"></i> ',\n    browseClass: \"btn btn-primary\",\n    removeIcon: '<i class=\"bi-trash\"></i>',\n    removeClass: defBtnCss2,\n    cancelIcon: '<i class=\"bi-slash-circle\"></i>',\n    cancelClass: defBtnCss2,\n    pauseIcon: '<i class=\"bi-pause-fill\"></i>',\n    pauseClass: defBtnCss2,\n    uploadIcon: '<i class=\"bi-upload\"></i>',\n    uploadClass: defBtnCss2,\n    uploadUrl: null,\n    uploadUrlThumb: null,\n    uploadAsync: true,\n    uploadParamNames: {\n      chunkCount: \"chunkCount\",\n      chunkIndex: \"chunkIndex\",\n      chunkSize: \"chunkSize\",\n      chunkSizeStart: \"chunkSizeStart\",\n      chunksUploaded: \"chunksUploaded\",\n      fileBlob: \"fileBlob\",\n      fileId: \"fileId\",\n      fileName: \"fileName\",\n      fileRelativePath: \"fileRelativePath\",\n      fileSize: \"fileSize\",\n      retryCount: \"retryCount\",\n    },\n    maxAjaxThreads: 5,\n    fadeDelay: 800,\n    processDelay: 100,\n    bitrateUpdateDelay: 500,\n    queueDelay: 10, // must be lesser than process delay\n    progressDelay: 0, // must be lesser than process delay\n    enableResumableUpload: false,\n    resumableUploadOptions: {\n      fallback: null,\n      testUrl: null, // used for checking status of chunks/ files previously / partially uploaded\n      chunkSize: 2048, // in KB\n      maxThreads: 4,\n      maxRetries: 3,\n      showErrorLog: true,\n      retainErrorHistory: false, // when set to true, display complete error history always unless user explicitly resets upload\n      skipErrorsAndProceed: false, // when set to true, files with errors will be skipped and upload will continue with other files\n    },\n    uploadExtraData: {},\n    zoomModalHeight: 485, // 5px more than the default preview content heights set for text, html, pdf etc.\n    minImageWidth: null,\n    minImageHeight: null,\n    maxImageWidth: null,\n    maxImageHeight: null,\n    resizeImage: false,\n    resizePreference: \"width\",\n    resizeQuality: 0.92,\n    resizeDefaultImageType: \"image/jpeg\",\n    resizeIfSizeMoreThan: 0, // in KB\n    minFileSize: -1,\n    maxFileSize: 0,\n    maxMultipleFileSize: 0,\n    maxFilePreviewSize: 25600, // 25 MB\n    minFileCount: 0,\n    maxFileCount: 0,\n    maxTotalFileCount: 0,\n    validateInitialCount: false,\n    msgValidationErrorClass: \"text-danger\",\n    msgValidationErrorIcon: '<i class=\"glyphicon glyphicon-exclamation-sign\"></i> ',\n    msgErrorClass: \"file-error-message\",\n    progressThumbClass: \"progress-bar progress-bar-striped active progress-bar-animated\",\n    progressClass: \"progress-bar bg-success progress-bar-success progress-bar-striped active progress-bar-animated\",\n    progressInfoClass: \"progress-bar bg-info progress-bar-info progress-bar-striped active progress-bar-animated\",\n    progressCompleteClass: \"progress-bar bg-success progress-bar-success\",\n    progressPauseClass:\n      \"progress-bar bg-primary progress-bar-primary progress-bar-striped active progress-bar-animated\",\n    progressErrorClass: \"progress-bar bg-danger progress-bar-danger\",\n    progressUploadThreshold: 99,\n    previewFileType: \"image\",\n    elCaptionContainer: null,\n    elCaptionText: null,\n    elPreviewContainer: null,\n    elPreviewImage: null,\n    elPreviewStatus: null,\n    elErrorContainer: null,\n    errorCloseButton: undefined,\n    slugCallback: null,\n    dropZoneEnabled: true,\n    dropZoneTitleClass: \"file-drop-zone-title\",\n    fileActionSettings: {},\n    otherActionButtons: \"\",\n    textEncoding: \"UTF-8\",\n    preProcessUpload: null,\n    ajaxSettings: { headers: {\n        \"X-CSRF-Token\": document.querySelector('meta[name=\"csrf-token\"]').content\n    }},\n    ajaxDeleteSettings: {},\n    showAjaxErrorDetails: true,\n    mergeAjaxCallbacks: false,\n    mergeAjaxDeleteCallbacks: false,\n    retryErrorUploads: true,\n    reversePreviewOrder: false,\n    usePdfRenderer: function () {\n      var isIE11 = !!window.MSInputMethodContext && !!document.documentMode;\n      return !!navigator.userAgent.match(/(iPod|iPhone|iPad|Android)/i) || isIE11;\n    },\n    pdfRendererUrl: \"\",\n    pdfRendererTemplate: \"<iframe \" + IFRAME_ATTRIBS + \"></iframe>\",\n    tabIndexConfig: {\n      browse: 500,\n      remove: 500,\n      upload: 500,\n      cancel: null,\n      pause: null,\n      modal: -1,\n    },\n  };\n\n  // noinspection HtmlUnknownAttribute\n  $.fn.fileinputLocales.en = {\n    sizeUnits: [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"],\n    bitRateUnits: [\"B/s\", \"KB/s\", \"MB/s\", \"GB/s\", \"TB/s\", \"PB/s\", \"EB/s\", \"ZB/s\", \"YB/s\"],\n    fileSingle: \"file\",\n    filePlural: \"files\",\n    browseLabel: \"Browse &hellip;\",\n    removeLabel: \"Remove\",\n    removeTitle: \"Clear all unprocessed files\",\n    cancelLabel: \"Cancel\",\n    cancelTitle: \"Abort ongoing upload\",\n    pauseLabel: \"Pause\",\n    pauseTitle: \"Pause ongoing upload\",\n    uploadLabel: \"Upload\",\n    uploadTitle: \"Upload selected files\",\n    msgNo: \"No\",\n    msgNoFilesSelected: \"No files selected\",\n    msgCancelled: \"Cancelled\",\n    msgPaused: \"Paused\",\n    msgPlaceholder: \"Select {files} ...\",\n    msgZoomModalHeading: \"Detailed Preview\",\n    msgFileRequired: \"You must select a file to upload.\",\n    msgSizeTooSmall: 'File \"{name}\" (<b>{size}</b>) is too small and must be larger than <b>{minSize}</b>.',\n    msgSizeTooLarge: 'File \"{name}\" (<b>{size}</b>) exceeds maximum allowed upload size of <b>{maxSize}</b>.',\n    msgMultipleSizeTooLarge: 'Files \"{name}\" (<b>{size}</b>) exceeds maximum allowed upload size of <b>{maxSize}</b>.',\n    msgFilesTooLess: \"You must select at least <b>{n}</b> {files} to upload.\",\n    msgFilesTooMany: \"Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.\",\n    msgTotalFilesTooMany: \"You can upload a maximum of <b>{m}</b> files (<b>{n}</b> files detected).\",\n    msgFileNotFound: 'File \"{name}\" not found!',\n    msgFileSecured: 'Security restrictions prevent reading the file \"{name}\".',\n    msgFileNotReadable: 'File \"{name}\" is not readable.',\n    msgFilePreviewAborted: 'File preview aborted for \"{name}\".',\n    msgFilePreviewError: 'An error occurred while reading the file \"{name}\".',\n    msgInvalidFileName: 'Invalid or unsupported characters in file name \"{name}\".',\n    msgInvalidFileType: 'Invalid type for file \"{name}\". Only \"{types}\" files are supported.',\n    msgInvalidFileExtension: 'Invalid extension for file \"{name}\". Only \"{extensions}\" files are supported.',\n    msgFileTypes: {\n      image: \"image\",\n      html: \"HTML\",\n      text: \"text\",\n      video: \"video\",\n      audio: \"audio\",\n      flash: \"flash\",\n      pdf: \"PDF\",\n      object: \"object\",\n    },\n    msgUploadAborted: \"The file upload was aborted\",\n    msgUploadThreshold: \"Processing &hellip;\",\n    msgUploadBegin: \"Initializing &hellip;\",\n    msgUploadEnd: \"Done\",\n    msgUploadResume: \"Resuming upload &hellip;\",\n    msgUploadEmpty: \"No valid data available for upload.\",\n    msgUploadError: \"Upload Error\",\n    msgDeleteError: \"Delete Error\",\n    msgProgressError: \"Error\",\n    msgValidationError: \"Validation Error\",\n    msgLoading: \"Loading file {index} of {files} &hellip;\",\n    msgProgress: \"Loading file {index} of {files} - {name} - {percent}% completed.\",\n    msgSelected: \"{n} {files} selected\",\n    msgProcessing: \"Processing ...\",\n    msgFoldersNotAllowed: \"Drag & drop files only! {n} folder(s) dropped were skipped.\",\n    msgImageWidthSmall:\n      'Width of image file \"{name}\" must be at least <b>{size} px</b> (detected <b>{dimension} px</b>).',\n    msgImageHeightSmall:\n      'Height of image file \"{name}\" must be at least <b>{size} px</b> (detected <b>{dimension} px</b>).',\n    msgImageWidthLarge: 'Width of image file \"{name}\" cannot exceed <b>{size} px</b> (detected <b>{dimension} px</b>).',\n    msgImageHeightLarge:\n      'Height of image file \"{name}\" cannot exceed <b>{size} px</b> (detected <b>{dimension} px</b>).',\n    msgImageResizeError: \"Could not get the image dimensions to resize.\",\n    msgImageResizeException: \"Error while resizing the image.<pre>{errors}</pre>\",\n    msgAjaxError: \"Something went wrong with the {operation} operation. Please try again later!\",\n    msgAjaxProgressError: \"{operation} failed\",\n    msgDuplicateFile:\n      'File \"{name}\" of same size \"{size}\" has already been selected earlier. Skipping duplicate selection.',\n    msgResumableUploadRetriesExceeded:\n      \"Upload aborted beyond <b>{max}</b> retries for file <b>{file}</b>! Error Details: <pre>{error}</pre>\",\n    msgPendingTime: \"{time} remaining\",\n    msgCalculatingTime: \"calculating time remaining\",\n    ajaxOperations: {\n      deleteThumb: \"file delete\",\n      uploadThumb: \"file upload\",\n      uploadBatch: \"batch file upload\",\n      uploadExtra: \"form data upload\",\n    },\n    dropZoneTitle: \"Drag & drop files here &hellip;\",\n    dropZoneClickTitle: \"<br>(or click to select {files})\",\n    previewZoomButtonTitles: {\n      prev: \"View previous file\",\n      next: \"View next file\",\n      rotate: \"Rotate 90 deg. clockwise\",\n      toggleheader: \"Toggle header\",\n      fullscreen: \"Toggle full screen\",\n      borderless: \"Toggle borderless mode\",\n      close: \"Close detailed preview\",\n    },\n  };\n  \n  $.fn.fileinputLocales.zh = {\n    sizeUnits: ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], \n    bitRateUnits: ['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s', 'PB/s', 'EB/s', 'ZB/s', 'YB/s'],\n    fileSingle: '文件',\n    filePlural: '个文件',\n    browseLabel: '选择 &hellip;',\n    removeLabel: '移除',\n    removeTitle: '清除选中文件',\n    cancelLabel: '取消',\n    cancelTitle: '取消进行中的上传',\n    pauseLabel: '暂停',\n    pauseTitle: '暂停上传',\n    uploadLabel: '上传',\n    uploadTitle: '上传选中文件',\n    msgNo: '没有',\n    msgNoFilesSelected: '未选择文件',\n    msgPaused: '已暂停',\n    msgCancelled: '取消',\n    msgPlaceholder: '选择 {files} ...',\n    msgZoomModalHeading: '详细预览',\n    msgFileRequired: '必须选择一个文件上传.',\n    msgSizeTooSmall: '文件 \"{name}\" (<b>{size}</b>) 必须大于限定大小 <b>{minSize}</b>.',\n    msgSizeTooLarge: '文件 \"{name}\" (<b>{size}</b>) 超过了允许大小 <b>{maxSize}</b>.',\n    msgMultipleSizeTooLarge: '文件 \"{name}\" (<b>{size}</b>) 超过了允许大小 <b>{maxSize}</b>.',\n    msgFilesTooLess: '你必须选择最少 <b>{n}</b> {files} 来上传. ',\n    msgFilesTooMany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>.',\n    msgTotalFilesTooMany: '你最多可以上传 <b>{m}</b> 个文件 (当前有<b>{n}</b> 个文件).',\n    msgFileNotFound: '文件 \"{name}\" 未找到!',\n    msgFileSecured: '安全限制，为了防止读取文件 \"{name}\".',\n    msgFileNotReadable: '文件 \"{name}\" 不可读.',\n    msgFilePreviewAborted: '取消 \"{name}\" 的预览.',\n    msgFilePreviewError: '读取 \"{name}\" 时出现了一个错误.',\n    msgInvalidFileName: '文件名 \"{name}\" 包含非法字符.',\n    msgInvalidFileType: '不正确的类型 \"{name}\". 只支持 \"{types}\" 类型的文件.',\n    msgInvalidFileExtension: '不正确的文件扩展名 \"{name}\". 只支持 \"{extensions}\" 的文件扩展名.',\n    msgFileTypes: {\n      'image': 'image',\n      'html': 'HTML',\n      'text': 'text',\n      'video': 'video',\n      'audio': 'audio',\n      'flash': 'flash',\n      'pdf': 'PDF',\n      'object': 'object'\n    },\n    msgUploadAborted: '该文件上传被中止',\n    msgUploadThreshold: '处理中 &hellip;',\n    msgUploadBegin: '正在初始化 &hellip;',\n    msgUploadEnd: '完成',\n    msgUploadResume: '继续上传 &hellip;',\n    msgUploadEmpty: '无效的文件上传.',\n    msgUploadError: '上传出错',\n    msgDeleteError: '删除出错',\n    msgProgressError: '上传出错',\n    msgValidationError: '验证错误',\n    msgLoading: '加载第 {index} 文件 共 {files} &hellip;',\n    msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.',\n    msgSelected: '{n} {files} 选中',\n    msgProcessing: '处理中 ...',\n    msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.',\n    msgImageWidthSmall: '图像文件的\"{name}\"的宽度必须是至少{size}像素.',\n    msgImageHeightSmall: '图像文件的\"{name}\"的高度必须至少为{size}像素.',\n    msgImageWidthLarge: '图像文件\"{name}\"的宽度不能超过{size}像素.',\n    msgImageHeightLarge: '图像文件\"{name}\"的高度不能超过{size}像素.',\n    msgImageResizeError: '无法获取的图像尺寸调整。',\n    msgImageResizeException: '调整图像大小时发生错误。<pre>{errors}</pre>',\n    msgAjaxError: '{operation} 发生错误. 请重试!',\n    msgAjaxProgressError: '{operation} 失败',\n    msgDuplicateFile: '文件 \"{name}\",大小 \"{size}\" 已经被选中.忽略相同的文件.',\n    msgResumableUploadRetriesExceeded:  '文件 <b>{file}</b> 上传失败超过 <b>{max}</b> 次重试 ! 错误详情: <pre>{error}</pre>',\n    msgPendingTime: '{time} 剩余',\n    msgCalculatingTime: '计算剩余时间',\n    ajaxOperations: {\n      deleteThumb: '删除文件',\n      uploadThumb: '上传文件',\n      uploadBatch: '批量上传',\n      uploadExtra: '表单数据上传'\n    },\n    dropZoneTitle: '拖拽文件到这里 &hellip;<br>支持多文件同时上传',\n    dropZoneClickTitle: '<br>(或点击{files}按钮选择文件)',\n    fileActionSettings: {\n      removeTitle: '删除文件',\n      uploadTitle: '上传文件',\n      downloadTitle: '下载文件',\n      uploadRetryTitle: '重试',\n      rotateTitle: '顺时针旋转90度',\n      zoomTitle: '查看详情',\n      dragTitle: '移动 / 重置',\n      indicatorNewTitle: '没有上传',\n      indicatorSuccessTitle: '上传',\n      indicatorErrorTitle: '上传错误',\n      indicatorPausedTitle: '上传已暂停',\n      indicatorLoadingTitle:  '上传 &hellip;'\n    },\n    previewZoomButtonTitles: {\n      prev: '预览上一个文件',\n      next: '预览下一个文件',\n      rotate: '顺时针旋转90度',\n      toggleheader: '缩放',\n      fullscreen: '全屏',\n      borderless: '无边界模式',\n      close: '关闭当前预览'\n    }\n  };\n\n  $.fn.fileinput.Constructor = FileInput;\n\n  /**\n   * Convert automatically file inputs with class 'file' into a bootstrap fileinput control.\n   */\n  $(document).ready(function () {\n    var $input = $(\"input.file[type=file]\");\n    if ($input.length) {\n      $input.fileinput();\n    }\n  });\n});\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-select/bootstrap-select.css",
    "content": "/*!\r\n * Bootstrap-select v1.13.18 (https://developer.snapappointments.com/bootstrap-select)\r\n *\r\n * Copyright 2012-2020 SnapAppointments, LLC\r\n * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)\r\n */\r\n\r\n@-webkit-keyframes bs-notify-fadeOut {\r\n  0% {\r\n    opacity: 0.9;\r\n  }\r\n  100% {\r\n    opacity: 0;\r\n  }\r\n}\r\n@-o-keyframes bs-notify-fadeOut {\r\n  0% {\r\n    opacity: 0.9;\r\n  }\r\n  100% {\r\n    opacity: 0;\r\n  }\r\n}\r\n@keyframes bs-notify-fadeOut {\r\n  0% {\r\n    opacity: 0.9;\r\n  }\r\n  100% {\r\n    opacity: 0;\r\n  }\r\n}\r\nselect.bs-select-hidden,\r\n.bootstrap-select > select.bs-select-hidden,\r\nselect.selectpicker {\r\n  display: none !important;\r\n}\r\n.bootstrap-select {\r\n  width: 220px \\0;\r\n  /*IE9 and below*/\r\n  vertical-align: middle;\r\n}\r\n.bootstrap-select > .dropdown-toggle {\r\n  position: relative;\r\n  width: 100%;\r\n  text-align: right;\r\n  white-space: nowrap;\r\n  display: -webkit-inline-box;\r\n  display: -webkit-inline-flex;\r\n  display: -ms-inline-flexbox;\r\n  display: inline-flex;\r\n  -webkit-box-align: center;\r\n  -webkit-align-items: center;\r\n      -ms-flex-align: center;\r\n          align-items: center;\r\n  -webkit-box-pack: justify;\r\n  -webkit-justify-content: space-between;\r\n      -ms-flex-pack: justify;\r\n          justify-content: space-between;\r\n}\r\n.bootstrap-select > .dropdown-toggle:after {\r\n  margin-top: -1px;\r\n}\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder:hover,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder:focus,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder:active {\r\n  color: #999;\r\n}\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:hover,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:hover,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:hover,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:hover,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:hover,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:hover,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:focus,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:focus,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:focus,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:focus,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:focus,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:focus,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:active,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:active,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:active,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:active,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:active,\r\n.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:active {\r\n  color: rgba(255, 255, 255, 0.5);\r\n}\r\n.bootstrap-select > select {\r\n  position: absolute !important;\r\n  bottom: 0;\r\n  left: 50%;\r\n  display: block !important;\r\n  width: 0.5px !important;\r\n  height: 100% !important;\r\n  padding: 0 !important;\r\n  opacity: 0 !important;\r\n  border: none;\r\n  z-index: 0 !important;\r\n}\r\n.bootstrap-select > select.mobile-device {\r\n  top: 0;\r\n  left: 0;\r\n  display: block !important;\r\n  width: 100% !important;\r\n  z-index: 2 !important;\r\n}\r\n.has-error .bootstrap-select .dropdown-toggle,\r\n.error .bootstrap-select .dropdown-toggle,\r\n.bootstrap-select.is-invalid .dropdown-toggle,\r\n.was-validated .bootstrap-select select:invalid + .dropdown-toggle {\r\n  border-color: #b94a48;\r\n}\r\n.bootstrap-select.is-valid .dropdown-toggle,\r\n.was-validated .bootstrap-select select:valid + .dropdown-toggle {\r\n  border-color: #28a745;\r\n}\r\n.bootstrap-select.fit-width {\r\n  width: auto !important;\r\n}\r\n.bootstrap-select:not([class*=\"col-\"]):not([class*=\"form-control\"]):not(.input-group-btn) {\r\n  width: 220px;\r\n}\r\n.bootstrap-select > select.mobile-device:focus + .dropdown-toggle,\r\n.bootstrap-select .dropdown-toggle:focus {\r\n  outline: thin dotted #333333 !important;\r\n  outline: 5px auto -webkit-focus-ring-color !important;\r\n  outline-offset: -2px;\r\n}\r\n.bootstrap-select.form-control {\r\n  margin-bottom: 0;\r\n  padding: 0;\r\n  border: none;\r\n  height: auto;\r\n}\r\n:not(.input-group) > .bootstrap-select.form-control:not([class*=\"col-\"]) {\r\n  width: 100%;\r\n}\r\n.bootstrap-select.form-control.input-group-btn {\r\n  float: none;\r\n  z-index: auto;\r\n}\r\n.form-inline .bootstrap-select,\r\n.form-inline .bootstrap-select.form-control:not([class*=\"col-\"]) {\r\n  width: auto;\r\n}\r\n.bootstrap-select:not(.input-group-btn),\r\n.bootstrap-select[class*=\"col-\"] {\r\n  float: none;\r\n  display: inline-block;\r\n  margin-left: 0;\r\n}\r\n.bootstrap-select.dropdown-menu-right,\r\n.bootstrap-select[class*=\"col-\"].dropdown-menu-right,\r\n.row .bootstrap-select[class*=\"col-\"].dropdown-menu-right {\r\n  float: right;\r\n}\r\n.form-inline .bootstrap-select,\r\n.form-horizontal .bootstrap-select,\r\n.form-group .bootstrap-select {\r\n  margin-bottom: 0;\r\n}\r\n.form-group-lg .bootstrap-select.form-control,\r\n.form-group-sm .bootstrap-select.form-control {\r\n  padding: 0;\r\n}\r\n.form-group-lg .bootstrap-select.form-control .dropdown-toggle,\r\n.form-group-sm .bootstrap-select.form-control .dropdown-toggle {\r\n  height: 100%;\r\n  font-size: inherit;\r\n  line-height: inherit;\r\n  border-radius: inherit;\r\n}\r\n.bootstrap-select.form-control-sm .dropdown-toggle,\r\n.bootstrap-select.form-control-lg .dropdown-toggle {\r\n  font-size: inherit;\r\n  line-height: inherit;\r\n  border-radius: inherit;\r\n}\r\n.bootstrap-select.form-control-sm .dropdown-toggle {\r\n  padding: 0.25rem 0.5rem;\r\n}\r\n.bootstrap-select.form-control-lg .dropdown-toggle {\r\n  padding: 0.5rem 1rem;\r\n}\r\n.form-inline .bootstrap-select .form-control {\r\n  width: 100%;\r\n}\r\n.bootstrap-select.disabled,\r\n.bootstrap-select > .disabled {\r\n  cursor: not-allowed;\r\n}\r\n.bootstrap-select.disabled:focus,\r\n.bootstrap-select > .disabled:focus {\r\n  outline: none !important;\r\n}\r\n.bootstrap-select.bs-container {\r\n  position: absolute;\r\n  top: 0;\r\n  left: 0;\r\n  height: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n.bootstrap-select.bs-container .dropdown-menu {\r\n  z-index: 1060;\r\n}\r\n.bootstrap-select .dropdown-toggle .filter-option {\r\n  position: static;\r\n  top: 0;\r\n  left: 0;\r\n  float: left;\r\n  height: 100%;\r\n  width: 100%;\r\n  text-align: left;\r\n  overflow: hidden;\r\n  -webkit-box-flex: 0;\r\n  -webkit-flex: 0 1 auto;\r\n      -ms-flex: 0 1 auto;\r\n          flex: 0 1 auto;\r\n}\r\n.bs3.bootstrap-select .dropdown-toggle .filter-option {\r\n  padding-right: inherit;\r\n}\r\n.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option {\r\n  position: absolute;\r\n  padding-top: inherit;\r\n  padding-bottom: inherit;\r\n  padding-left: inherit;\r\n  float: none;\r\n}\r\n.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option .filter-option-inner {\r\n  padding-right: inherit;\r\n}\r\n.bootstrap-select .dropdown-toggle .filter-option-inner-inner {\r\n  overflow: hidden;\r\n}\r\n.bootstrap-select .dropdown-toggle .filter-expand {\r\n  width: 0 !important;\r\n  float: left;\r\n  opacity: 0 !important;\r\n  overflow: hidden;\r\n}\r\n.bootstrap-select .dropdown-toggle .caret {\r\n  position: absolute;\r\n  top: 50%;\r\n  right: 12px;\r\n  margin-top: -2px;\r\n  vertical-align: middle;\r\n}\r\n.input-group .bootstrap-select.form-control .dropdown-toggle {\r\n  border-radius: inherit;\r\n}\r\n.bootstrap-select[class*=\"col-\"] .dropdown-toggle {\r\n  width: 100%;\r\n}\r\n.bootstrap-select .dropdown-menu {\r\n  min-width: 100%;\r\n  -webkit-box-sizing: border-box;\r\n     -moz-box-sizing: border-box;\r\n          box-sizing: border-box;\r\n}\r\n.bootstrap-select .dropdown-menu > .inner:focus {\r\n  outline: none !important;\r\n}\r\n.bootstrap-select .dropdown-menu.inner {\r\n  position: static;\r\n  float: none;\r\n  border: 0;\r\n  padding: 0;\r\n  margin: 0;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: none;\r\n          box-shadow: none;\r\n}\r\n.bootstrap-select .dropdown-menu li {\r\n  position: relative;\r\n}\r\n.bootstrap-select .dropdown-menu li.active small {\r\n  color: rgba(255, 255, 255, 0.5) !important;\r\n}\r\n.bootstrap-select .dropdown-menu li.disabled a {\r\n  cursor: not-allowed;\r\n}\r\n.bootstrap-select .dropdown-menu li a {\r\n  cursor: pointer;\r\n  -webkit-user-select: none;\r\n     -moz-user-select: none;\r\n      -ms-user-select: none;\r\n          user-select: none;\r\n}\r\n.bootstrap-select .dropdown-menu li a.opt {\r\n  position: relative;\r\n  padding-left: 2.25em;\r\n}\r\n.bootstrap-select .dropdown-menu li a span.check-mark {\r\n  display: none;\r\n}\r\n.bootstrap-select .dropdown-menu li a span.text {\r\n  display: inline-block;\r\n}\r\n.bootstrap-select .dropdown-menu li small {\r\n  padding-left: 0.5em;\r\n}\r\n.bootstrap-select .dropdown-menu .notify {\r\n  position: absolute;\r\n  bottom: 5px;\r\n  width: 96%;\r\n  margin: 0 2%;\r\n  min-height: 26px;\r\n  padding: 3px 5px;\r\n  background: #f5f5f5;\r\n  border: 1px solid #e3e3e3;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\r\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\r\n  pointer-events: none;\r\n  opacity: 0.9;\r\n  -webkit-box-sizing: border-box;\r\n     -moz-box-sizing: border-box;\r\n          box-sizing: border-box;\r\n}\r\n.bootstrap-select .dropdown-menu .notify.fadeOut {\r\n  -webkit-animation: 300ms linear 750ms forwards bs-notify-fadeOut;\r\n       -o-animation: 300ms linear 750ms forwards bs-notify-fadeOut;\r\n          animation: 300ms linear 750ms forwards bs-notify-fadeOut;\r\n}\r\n.bootstrap-select .no-results {\r\n  padding: 3px;\r\n  background: #f5f5f5;\r\n  margin: 0 5px;\r\n  white-space: nowrap;\r\n}\r\n.bootstrap-select.fit-width .dropdown-toggle .filter-option {\r\n  position: static;\r\n  display: inline;\r\n  padding: 0;\r\n}\r\n.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner,\r\n.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner-inner {\r\n  display: inline;\r\n}\r\n.bootstrap-select.fit-width .dropdown-toggle .bs-caret:before {\r\n  content: '\\00a0';\r\n}\r\n.bootstrap-select.fit-width .dropdown-toggle .caret {\r\n  position: static;\r\n  top: auto;\r\n  margin-top: -1px;\r\n}\r\n.bootstrap-select.show-tick .dropdown-menu .selected span.check-mark {\r\n  position: absolute;\r\n  display: inline-block;\r\n  right: 15px;\r\n  top: 5px;\r\n}\r\n.bootstrap-select.show-tick .dropdown-menu li a span.text {\r\n  margin-right: 34px;\r\n}\r\n.bootstrap-select .bs-ok-default:after {\r\n  content: '';\r\n  display: block;\r\n  width: 0.5em;\r\n  height: 1em;\r\n  border-style: solid;\r\n  border-width: 0 0.26em 0.26em 0;\r\n  -webkit-transform-style: preserve-3d;\r\n          transform-style: preserve-3d;\r\n  -webkit-transform: rotate(45deg);\r\n      -ms-transform: rotate(45deg);\r\n       -o-transform: rotate(45deg);\r\n          transform: rotate(45deg);\r\n}\r\n.bootstrap-select.show-menu-arrow.open > .dropdown-toggle,\r\n.bootstrap-select.show-menu-arrow.show > .dropdown-toggle {\r\n  z-index: 1061;\r\n}\r\n.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:before {\r\n  content: '';\r\n  border-left: 7px solid transparent;\r\n  border-right: 7px solid transparent;\r\n  border-bottom: 7px solid rgba(204, 204, 204, 0.2);\r\n  position: absolute;\r\n  bottom: -4px;\r\n  left: 9px;\r\n  display: none;\r\n}\r\n.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:after {\r\n  content: '';\r\n  border-left: 6px solid transparent;\r\n  border-right: 6px solid transparent;\r\n  border-bottom: 6px solid white;\r\n  position: absolute;\r\n  bottom: -4px;\r\n  left: 10px;\r\n  display: none;\r\n}\r\n.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:before {\r\n  bottom: auto;\r\n  top: -4px;\r\n  border-top: 7px solid rgba(204, 204, 204, 0.2);\r\n  border-bottom: 0;\r\n}\r\n.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:after {\r\n  bottom: auto;\r\n  top: -4px;\r\n  border-top: 6px solid white;\r\n  border-bottom: 0;\r\n}\r\n.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:before {\r\n  right: 12px;\r\n  left: auto;\r\n}\r\n.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:after {\r\n  right: 13px;\r\n  left: auto;\r\n}\r\n.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:before,\r\n.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:before,\r\n.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:after,\r\n.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:after {\r\n  display: block;\r\n}\r\n.bs-searchbox,\r\n.bs-actionsbox,\r\n.bs-donebutton {\r\n  padding: 4px 8px;\r\n}\r\n.bs-actionsbox {\r\n  width: 100%;\r\n  -webkit-box-sizing: border-box;\r\n     -moz-box-sizing: border-box;\r\n          box-sizing: border-box;\r\n}\r\n.bs-actionsbox .btn-group button {\r\n  width: 50%;\r\n}\r\n.bs-donebutton {\r\n  float: left;\r\n  width: 100%;\r\n  -webkit-box-sizing: border-box;\r\n     -moz-box-sizing: border-box;\r\n          box-sizing: border-box;\r\n}\r\n.bs-donebutton .btn-group button {\r\n  width: 100%;\r\n}\r\n.bs-searchbox + .bs-actionsbox {\r\n  padding: 0 8px 4px;\r\n}\r\n.bs-searchbox .form-control {\r\n  margin-bottom: 0;\r\n  width: 100%;\r\n  float: none;\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-select/bootstrap-select.js",
    "content": "/*!\r\n * Bootstrap-select v1.13.18 (https://developer.snapappointments.com/bootstrap-select)\r\n *\r\n * Copyright 2012-2020 SnapAppointments, LLC\r\n * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)\r\n */\r\n\r\n(function (root, factory) {\r\n  if (root === undefined && window !== undefined) root = window;\r\n  if (typeof define === 'function' && define.amd) {\r\n    // AMD. Register as an anonymous module unless amdModuleId is set\r\n    define([\"jquery\"], function (a0) {\r\n      return (factory(a0));\r\n    });\r\n  } else if (typeof module === 'object' && module.exports) {\r\n    // Node. Does not work with strict CommonJS, but\r\n    // only CommonJS-like environments that support module.exports,\r\n    // like Node.\r\n    module.exports = factory(require(\"jquery\"));\r\n  } else {\r\n    factory(root[\"jQuery\"]);\r\n  }\r\n}(this, function (jQuery) {\r\n\r\n(function ($) {\r\n  'use strict';\r\n\r\n  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];\r\n\r\n  var uriAttrs = [\r\n    'background',\r\n    'cite',\r\n    'href',\r\n    'itemtype',\r\n    'longdesc',\r\n    'poster',\r\n    'src',\r\n    'xlink:href'\r\n  ];\r\n\r\n  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\r\n\r\n  var DefaultWhitelist = {\r\n    // Global attributes allowed on any supplied element below.\r\n    '*': ['class', 'dir', 'id', 'lang', 'role', 'tabindex', 'style', ARIA_ATTRIBUTE_PATTERN],\r\n    a: ['target', 'href', 'title', 'rel'],\r\n    area: [],\r\n    b: [],\r\n    br: [],\r\n    col: [],\r\n    code: [],\r\n    div: [],\r\n    em: [],\r\n    hr: [],\r\n    h1: [],\r\n    h2: [],\r\n    h3: [],\r\n    h4: [],\r\n    h5: [],\r\n    h6: [],\r\n    i: [],\r\n    img: ['src', 'alt', 'title', 'width', 'height'],\r\n    li: [],\r\n    ol: [],\r\n    p: [],\r\n    pre: [],\r\n    s: [],\r\n    small: [],\r\n    span: [],\r\n    sub: [],\r\n    sup: [],\r\n    strong: [],\r\n    u: [],\r\n    ul: []\r\n  }\r\n\r\n  /**\r\n   * A pattern that recognizes a commonly useful subset of URLs that are safe.\r\n   *\r\n   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\r\n   */\r\n  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;\r\n\r\n  /**\r\n   * A pattern that matches safe data URLs. Only matches image, video and audio types.\r\n   *\r\n   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\r\n   */\r\n  var DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;\r\n\r\n  function allowedAttribute (attr, allowedAttributeList) {\r\n    var attrName = attr.nodeName.toLowerCase()\r\n\r\n    if ($.inArray(attrName, allowedAttributeList) !== -1) {\r\n      if ($.inArray(attrName, uriAttrs) !== -1) {\r\n        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))\r\n      }\r\n\r\n      return true\r\n    }\r\n\r\n    var regExp = $(allowedAttributeList).filter(function (index, value) {\r\n      return value instanceof RegExp\r\n    })\r\n\r\n    // Check if a regular expression validates the attribute.\r\n    for (var i = 0, l = regExp.length; i < l; i++) {\r\n      if (attrName.match(regExp[i])) {\r\n        return true\r\n      }\r\n    }\r\n\r\n    return false\r\n  }\r\n\r\n  function sanitizeHtml (unsafeElements, whiteList, sanitizeFn) {\r\n    if (sanitizeFn && typeof sanitizeFn === 'function') {\r\n      return sanitizeFn(unsafeElements);\r\n    }\r\n\r\n    var whitelistKeys = Object.keys(whiteList);\r\n\r\n    for (var i = 0, len = unsafeElements.length; i < len; i++) {\r\n      var elements = unsafeElements[i].querySelectorAll('*');\r\n\r\n      for (var j = 0, len2 = elements.length; j < len2; j++) {\r\n        var el = elements[j];\r\n        var elName = el.nodeName.toLowerCase();\r\n\r\n        if (whitelistKeys.indexOf(elName) === -1) {\r\n          el.parentNode.removeChild(el);\r\n\r\n          continue;\r\n        }\r\n\r\n        var attributeList = [].slice.call(el.attributes);\r\n        var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);\r\n\r\n        for (var k = 0, len3 = attributeList.length; k < len3; k++) {\r\n          var attr = attributeList[k];\r\n\r\n          if (!allowedAttribute(attr, whitelistedAttributes)) {\r\n            el.removeAttribute(attr.nodeName);\r\n          }\r\n        }\r\n      }\r\n    }\r\n  }\r\n\r\n  // Polyfill for browsers with no classList support\r\n  // Remove in v2\r\n  if (!('classList' in document.createElement('_'))) {\r\n    (function (view) {\r\n      if (!('Element' in view)) return;\r\n\r\n      var classListProp = 'classList',\r\n          protoProp = 'prototype',\r\n          elemCtrProto = view.Element[protoProp],\r\n          objCtr = Object,\r\n          classListGetter = function () {\r\n            var $elem = $(this);\r\n\r\n            return {\r\n              add: function (classes) {\r\n                classes = Array.prototype.slice.call(arguments).join(' ');\r\n                return $elem.addClass(classes);\r\n              },\r\n              remove: function (classes) {\r\n                classes = Array.prototype.slice.call(arguments).join(' ');\r\n                return $elem.removeClass(classes);\r\n              },\r\n              toggle: function (classes, force) {\r\n                return $elem.toggleClass(classes, force);\r\n              },\r\n              contains: function (classes) {\r\n                return $elem.hasClass(classes);\r\n              }\r\n            }\r\n          };\r\n\r\n      if (objCtr.defineProperty) {\r\n        var classListPropDesc = {\r\n          get: classListGetter,\r\n          enumerable: true,\r\n          configurable: true\r\n        };\r\n        try {\r\n          objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);\r\n        } catch (ex) { // IE 8 doesn't support enumerable:true\r\n          // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36\r\n          // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected\r\n          if (ex.number === undefined || ex.number === -0x7FF5EC54) {\r\n            classListPropDesc.enumerable = false;\r\n            objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);\r\n          }\r\n        }\r\n      } else if (objCtr[protoProp].__defineGetter__) {\r\n        elemCtrProto.__defineGetter__(classListProp, classListGetter);\r\n      }\r\n    }(window));\r\n  }\r\n\r\n  var testElement = document.createElement('_');\r\n\r\n  testElement.classList.add('c1', 'c2');\r\n\r\n  if (!testElement.classList.contains('c2')) {\r\n    var _add = DOMTokenList.prototype.add,\r\n        _remove = DOMTokenList.prototype.remove;\r\n\r\n    DOMTokenList.prototype.add = function () {\r\n      Array.prototype.forEach.call(arguments, _add.bind(this));\r\n    }\r\n\r\n    DOMTokenList.prototype.remove = function () {\r\n      Array.prototype.forEach.call(arguments, _remove.bind(this));\r\n    }\r\n  }\r\n\r\n  testElement.classList.toggle('c3', false);\r\n\r\n  // Polyfill for IE 10 and Firefox <24, where classList.toggle does not\r\n  // support the second argument.\r\n  if (testElement.classList.contains('c3')) {\r\n    var _toggle = DOMTokenList.prototype.toggle;\r\n\r\n    DOMTokenList.prototype.toggle = function (token, force) {\r\n      if (1 in arguments && !this.contains(token) === !force) {\r\n        return force;\r\n      } else {\r\n        return _toggle.call(this, token);\r\n      }\r\n    };\r\n  }\r\n\r\n  testElement = null;\r\n\r\n  // shallow array comparison\r\n  function isEqual (array1, array2) {\r\n    return array1.length === array2.length && array1.every(function (element, index) {\r\n      return element === array2[index];\r\n    });\r\n  };\r\n\r\n  // <editor-fold desc=\"Shims\">\r\n  if (!String.prototype.startsWith) {\r\n    (function () {\r\n      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`\r\n      var defineProperty = (function () {\r\n        // IE 8 only supports `Object.defineProperty` on DOM elements\r\n        try {\r\n          var object = {};\r\n          var $defineProperty = Object.defineProperty;\r\n          var result = $defineProperty(object, object, object) && $defineProperty;\r\n        } catch (error) {\r\n        }\r\n        return result;\r\n      }());\r\n      var toString = {}.toString;\r\n      var startsWith = function (search) {\r\n        if (this == null) {\r\n          throw new TypeError();\r\n        }\r\n        var string = String(this);\r\n        if (search && toString.call(search) == '[object RegExp]') {\r\n          throw new TypeError();\r\n        }\r\n        var stringLength = string.length;\r\n        var searchString = String(search);\r\n        var searchLength = searchString.length;\r\n        var position = arguments.length > 1 ? arguments[1] : undefined;\r\n        // `ToInteger`\r\n        var pos = position ? Number(position) : 0;\r\n        if (pos != pos) { // better `isNaN`\r\n          pos = 0;\r\n        }\r\n        var start = Math.min(Math.max(pos, 0), stringLength);\r\n        // Avoid the `indexOf` call if no match is possible\r\n        if (searchLength + start > stringLength) {\r\n          return false;\r\n        }\r\n        var index = -1;\r\n        while (++index < searchLength) {\r\n          if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {\r\n            return false;\r\n          }\r\n        }\r\n        return true;\r\n      };\r\n      if (defineProperty) {\r\n        defineProperty(String.prototype, 'startsWith', {\r\n          'value': startsWith,\r\n          'configurable': true,\r\n          'writable': true\r\n        });\r\n      } else {\r\n        String.prototype.startsWith = startsWith;\r\n      }\r\n    }());\r\n  }\r\n\r\n  if (!Object.keys) {\r\n    Object.keys = function (\r\n      o, // object\r\n      k, // key\r\n      r  // result array\r\n    ) {\r\n      // initialize object and result\r\n      r = [];\r\n      // iterate over object keys\r\n      for (k in o) {\r\n        // fill result array with non-prototypical keys\r\n        r.hasOwnProperty.call(o, k) && r.push(k);\r\n      }\r\n      // return result\r\n      return r;\r\n    };\r\n  }\r\n\r\n  if (HTMLSelectElement && !HTMLSelectElement.prototype.hasOwnProperty('selectedOptions')) {\r\n    Object.defineProperty(HTMLSelectElement.prototype, 'selectedOptions', {\r\n      get: function () {\r\n        return this.querySelectorAll(':checked');\r\n      }\r\n    });\r\n  }\r\n\r\n  function getSelectedOptions (select, ignoreDisabled) {\r\n    var selectedOptions = select.selectedOptions,\r\n        options = [],\r\n        opt;\r\n\r\n    if (ignoreDisabled) {\r\n      for (var i = 0, len = selectedOptions.length; i < len; i++) {\r\n        opt = selectedOptions[i];\r\n\r\n        if (!(opt.disabled || opt.parentNode.tagName === 'OPTGROUP' && opt.parentNode.disabled)) {\r\n          options.push(opt);\r\n        }\r\n      }\r\n\r\n      return options;\r\n    }\r\n\r\n    return selectedOptions;\r\n  }\r\n\r\n  // much faster than $.val()\r\n  function getSelectValues (select, selectedOptions) {\r\n    var value = [],\r\n        options = selectedOptions || select.selectedOptions,\r\n        opt;\r\n\r\n    for (var i = 0, len = options.length; i < len; i++) {\r\n      opt = options[i];\r\n\r\n      if (!(opt.disabled || opt.parentNode.tagName === 'OPTGROUP' && opt.parentNode.disabled)) {\r\n        value.push(opt.value);\r\n      }\r\n    }\r\n\r\n    if (!select.multiple) {\r\n      return !value.length ? null : value[0];\r\n    }\r\n\r\n    return value;\r\n  }\r\n\r\n  // set data-selected on select element if the value has been programmatically selected\r\n  // prior to initialization of bootstrap-select\r\n  // * consider removing or replacing an alternative method *\r\n  var valHooks = {\r\n    useDefault: false,\r\n    _set: $.valHooks.select.set\r\n  };\r\n\r\n  $.valHooks.select.set = function (elem, value) {\r\n    if (value && !valHooks.useDefault) $(elem).data('selected', true);\r\n\r\n    return valHooks._set.apply(this, arguments);\r\n  };\r\n\r\n  var changedArguments = null;\r\n\r\n  var EventIsSupported = (function () {\r\n    try {\r\n      new Event('change');\r\n      return true;\r\n    } catch (e) {\r\n      return false;\r\n    }\r\n  })();\r\n\r\n  $.fn.triggerNative = function (eventName) {\r\n    var el = this[0],\r\n        event;\r\n\r\n    if (el.dispatchEvent) { // for modern browsers & IE9+\r\n      if (EventIsSupported) {\r\n        // For modern browsers\r\n        event = new Event(eventName, {\r\n          bubbles: true\r\n        });\r\n      } else {\r\n        // For IE since it doesn't support Event constructor\r\n        event = document.createEvent('Event');\r\n        event.initEvent(eventName, true, false);\r\n      }\r\n\r\n      el.dispatchEvent(event);\r\n    } else if (el.fireEvent) { // for IE8\r\n      event = document.createEventObject();\r\n      event.eventType = eventName;\r\n      el.fireEvent('on' + eventName, event);\r\n    } else {\r\n      // fall back to jQuery.trigger\r\n      this.trigger(eventName);\r\n    }\r\n  };\r\n  // </editor-fold>\r\n\r\n  function stringSearch (li, searchString, method, normalize) {\r\n    var stringTypes = [\r\n          'display',\r\n          'subtext',\r\n          'tokens'\r\n        ],\r\n        searchSuccess = false;\r\n\r\n    for (var i = 0; i < stringTypes.length; i++) {\r\n      var stringType = stringTypes[i],\r\n          string = li[stringType];\r\n\r\n      if (string) {\r\n        string = string.toString();\r\n\r\n        // Strip HTML tags. This isn't perfect, but it's much faster than any other method\r\n        if (stringType === 'display') {\r\n          string = string.replace(/<[^>]+>/g, '');\r\n        }\r\n\r\n        if (normalize) string = normalizeToBase(string);\r\n        string = string.toUpperCase();\r\n\r\n        if (method === 'contains') {\r\n          searchSuccess = string.indexOf(searchString) >= 0;\r\n        } else {\r\n          searchSuccess = string.startsWith(searchString);\r\n        }\r\n\r\n        if (searchSuccess) break;\r\n      }\r\n    }\r\n\r\n    return searchSuccess;\r\n  }\r\n\r\n  function toInteger (value) {\r\n    return parseInt(value, 10) || 0;\r\n  }\r\n\r\n  // Borrowed from Lodash (_.deburr)\r\n  /** Used to map Latin Unicode letters to basic Latin letters. */\r\n  var deburredLetters = {\r\n    // Latin-1 Supplement block.\r\n    '\\xc0': 'A',  '\\xc1': 'A', '\\xc2': 'A', '\\xc3': 'A', '\\xc4': 'A', '\\xc5': 'A',\r\n    '\\xe0': 'a',  '\\xe1': 'a', '\\xe2': 'a', '\\xe3': 'a', '\\xe4': 'a', '\\xe5': 'a',\r\n    '\\xc7': 'C',  '\\xe7': 'c',\r\n    '\\xd0': 'D',  '\\xf0': 'd',\r\n    '\\xc8': 'E',  '\\xc9': 'E', '\\xca': 'E', '\\xcb': 'E',\r\n    '\\xe8': 'e',  '\\xe9': 'e', '\\xea': 'e', '\\xeb': 'e',\r\n    '\\xcc': 'I',  '\\xcd': 'I', '\\xce': 'I', '\\xcf': 'I',\r\n    '\\xec': 'i',  '\\xed': 'i', '\\xee': 'i', '\\xef': 'i',\r\n    '\\xd1': 'N',  '\\xf1': 'n',\r\n    '\\xd2': 'O',  '\\xd3': 'O', '\\xd4': 'O', '\\xd5': 'O', '\\xd6': 'O', '\\xd8': 'O',\r\n    '\\xf2': 'o',  '\\xf3': 'o', '\\xf4': 'o', '\\xf5': 'o', '\\xf6': 'o', '\\xf8': 'o',\r\n    '\\xd9': 'U',  '\\xda': 'U', '\\xdb': 'U', '\\xdc': 'U',\r\n    '\\xf9': 'u',  '\\xfa': 'u', '\\xfb': 'u', '\\xfc': 'u',\r\n    '\\xdd': 'Y',  '\\xfd': 'y', '\\xff': 'y',\r\n    '\\xc6': 'Ae', '\\xe6': 'ae',\r\n    '\\xde': 'Th', '\\xfe': 'th',\r\n    '\\xdf': 'ss',\r\n    // Latin Extended-A block.\r\n    '\\u0100': 'A',  '\\u0102': 'A', '\\u0104': 'A',\r\n    '\\u0101': 'a',  '\\u0103': 'a', '\\u0105': 'a',\r\n    '\\u0106': 'C',  '\\u0108': 'C', '\\u010a': 'C', '\\u010c': 'C',\r\n    '\\u0107': 'c',  '\\u0109': 'c', '\\u010b': 'c', '\\u010d': 'c',\r\n    '\\u010e': 'D',  '\\u0110': 'D', '\\u010f': 'd', '\\u0111': 'd',\r\n    '\\u0112': 'E',  '\\u0114': 'E', '\\u0116': 'E', '\\u0118': 'E', '\\u011a': 'E',\r\n    '\\u0113': 'e',  '\\u0115': 'e', '\\u0117': 'e', '\\u0119': 'e', '\\u011b': 'e',\r\n    '\\u011c': 'G',  '\\u011e': 'G', '\\u0120': 'G', '\\u0122': 'G',\r\n    '\\u011d': 'g',  '\\u011f': 'g', '\\u0121': 'g', '\\u0123': 'g',\r\n    '\\u0124': 'H',  '\\u0126': 'H', '\\u0125': 'h', '\\u0127': 'h',\r\n    '\\u0128': 'I',  '\\u012a': 'I', '\\u012c': 'I', '\\u012e': 'I', '\\u0130': 'I',\r\n    '\\u0129': 'i',  '\\u012b': 'i', '\\u012d': 'i', '\\u012f': 'i', '\\u0131': 'i',\r\n    '\\u0134': 'J',  '\\u0135': 'j',\r\n    '\\u0136': 'K',  '\\u0137': 'k', '\\u0138': 'k',\r\n    '\\u0139': 'L',  '\\u013b': 'L', '\\u013d': 'L', '\\u013f': 'L', '\\u0141': 'L',\r\n    '\\u013a': 'l',  '\\u013c': 'l', '\\u013e': 'l', '\\u0140': 'l', '\\u0142': 'l',\r\n    '\\u0143': 'N',  '\\u0145': 'N', '\\u0147': 'N', '\\u014a': 'N',\r\n    '\\u0144': 'n',  '\\u0146': 'n', '\\u0148': 'n', '\\u014b': 'n',\r\n    '\\u014c': 'O',  '\\u014e': 'O', '\\u0150': 'O',\r\n    '\\u014d': 'o',  '\\u014f': 'o', '\\u0151': 'o',\r\n    '\\u0154': 'R',  '\\u0156': 'R', '\\u0158': 'R',\r\n    '\\u0155': 'r',  '\\u0157': 'r', '\\u0159': 'r',\r\n    '\\u015a': 'S',  '\\u015c': 'S', '\\u015e': 'S', '\\u0160': 'S',\r\n    '\\u015b': 's',  '\\u015d': 's', '\\u015f': 's', '\\u0161': 's',\r\n    '\\u0162': 'T',  '\\u0164': 'T', '\\u0166': 'T',\r\n    '\\u0163': 't',  '\\u0165': 't', '\\u0167': 't',\r\n    '\\u0168': 'U',  '\\u016a': 'U', '\\u016c': 'U', '\\u016e': 'U', '\\u0170': 'U', '\\u0172': 'U',\r\n    '\\u0169': 'u',  '\\u016b': 'u', '\\u016d': 'u', '\\u016f': 'u', '\\u0171': 'u', '\\u0173': 'u',\r\n    '\\u0174': 'W',  '\\u0175': 'w',\r\n    '\\u0176': 'Y',  '\\u0177': 'y', '\\u0178': 'Y',\r\n    '\\u0179': 'Z',  '\\u017b': 'Z', '\\u017d': 'Z',\r\n    '\\u017a': 'z',  '\\u017c': 'z', '\\u017e': 'z',\r\n    '\\u0132': 'IJ', '\\u0133': 'ij',\r\n    '\\u0152': 'Oe', '\\u0153': 'oe',\r\n    '\\u0149': \"'n\", '\\u017f': 's'\r\n  };\r\n\r\n  /** Used to match Latin Unicode letters (excluding mathematical operators). */\r\n  var reLatin = /[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g;\r\n\r\n  /** Used to compose unicode character classes. */\r\n  var rsComboMarksRange = '\\\\u0300-\\\\u036f',\r\n      reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\r\n      rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\r\n      rsComboMarksExtendedRange = '\\\\u1ab0-\\\\u1aff',\r\n      rsComboMarksSupplementRange = '\\\\u1dc0-\\\\u1dff',\r\n      rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange;\r\n\r\n  /** Used to compose unicode capture groups. */\r\n  var rsCombo = '[' + rsComboRange + ']';\r\n\r\n  /**\r\n   * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and\r\n   * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).\r\n   */\r\n  var reComboMark = RegExp(rsCombo, 'g');\r\n\r\n  function deburrLetter (key) {\r\n    return deburredLetters[key];\r\n  };\r\n\r\n  function normalizeToBase (string) {\r\n    string = string.toString();\r\n    return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');\r\n  }\r\n\r\n  // List of HTML entities for escaping.\r\n  var escapeMap = {\r\n    '&': '&amp;',\r\n    '<': '&lt;',\r\n    '>': '&gt;',\r\n    '\"': '&quot;',\r\n    \"'\": '&#x27;',\r\n    '`': '&#x60;'\r\n  };\r\n\r\n  // Functions for escaping and unescaping strings to/from HTML interpolation.\r\n  var createEscaper = function (map) {\r\n    var escaper = function (match) {\r\n      return map[match];\r\n    };\r\n    // Regexes for identifying a key that needs to be escaped.\r\n    var source = '(?:' + Object.keys(map).join('|') + ')';\r\n    var testRegexp = RegExp(source);\r\n    var replaceRegexp = RegExp(source, 'g');\r\n    return function (string) {\r\n      string = string == null ? '' : '' + string;\r\n      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;\r\n    };\r\n  };\r\n\r\n  var htmlEscape = createEscaper(escapeMap);\r\n\r\n  /**\r\n   * ------------------------------------------------------------------------\r\n   * Constants\r\n   * ------------------------------------------------------------------------\r\n   */\r\n\r\n  var keyCodeMap = {\r\n    32: ' ',\r\n    48: '0',\r\n    49: '1',\r\n    50: '2',\r\n    51: '3',\r\n    52: '4',\r\n    53: '5',\r\n    54: '6',\r\n    55: '7',\r\n    56: '8',\r\n    57: '9',\r\n    59: ';',\r\n    65: 'A',\r\n    66: 'B',\r\n    67: 'C',\r\n    68: 'D',\r\n    69: 'E',\r\n    70: 'F',\r\n    71: 'G',\r\n    72: 'H',\r\n    73: 'I',\r\n    74: 'J',\r\n    75: 'K',\r\n    76: 'L',\r\n    77: 'M',\r\n    78: 'N',\r\n    79: 'O',\r\n    80: 'P',\r\n    81: 'Q',\r\n    82: 'R',\r\n    83: 'S',\r\n    84: 'T',\r\n    85: 'U',\r\n    86: 'V',\r\n    87: 'W',\r\n    88: 'X',\r\n    89: 'Y',\r\n    90: 'Z',\r\n    96: '0',\r\n    97: '1',\r\n    98: '2',\r\n    99: '3',\r\n    100: '4',\r\n    101: '5',\r\n    102: '6',\r\n    103: '7',\r\n    104: '8',\r\n    105: '9'\r\n  };\r\n\r\n  var keyCodes = {\r\n    ESCAPE: 27, // KeyboardEvent.which value for Escape (Esc) key\r\n    ENTER: 13, // KeyboardEvent.which value for Enter key\r\n    SPACE: 32, // KeyboardEvent.which value for space key\r\n    TAB: 9, // KeyboardEvent.which value for tab key\r\n    ARROW_UP: 38, // KeyboardEvent.which value for up arrow key\r\n    ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key\r\n  }\r\n\r\n  var version = {\r\n    success: false,\r\n    major: '3'\r\n  };\r\n\r\n  try {\r\n    version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.');\r\n    version.major = version.full[0];\r\n    version.success = true;\r\n  } catch (err) {\r\n    // do nothing\r\n  }\r\n\r\n  var selectId = 0;\r\n\r\n  var EVENT_KEY = '.bs.select';\r\n\r\n  var classNames = {\r\n    DISABLED: 'disabled',\r\n    DIVIDER: 'divider',\r\n    SHOW: 'open',\r\n    DROPUP: 'dropup',\r\n    MENU: 'dropdown-menu',\r\n    MENURIGHT: 'dropdown-menu-right',\r\n    MENULEFT: 'dropdown-menu-left',\r\n    // to-do: replace with more advanced template/customization options\r\n    BUTTONCLASS: 'btn-default',\r\n    POPOVERHEADER: 'popover-title',\r\n    ICONBASE: 'glyphicon',\r\n    TICKICON: 'glyphicon-ok'\r\n  }\r\n\r\n  var Selector = {\r\n    MENU: '.' + classNames.MENU\r\n  }\r\n\r\n  var elementTemplates = {\r\n    div: document.createElement('div'),\r\n    span: document.createElement('span'),\r\n    i: document.createElement('i'),\r\n    subtext: document.createElement('small'),\r\n    a: document.createElement('a'),\r\n    li: document.createElement('li'),\r\n    whitespace: document.createTextNode('\\u00A0'),\r\n    fragment: document.createDocumentFragment()\r\n  }\r\n\r\n  elementTemplates.noResults = elementTemplates.li.cloneNode(false);\r\n  elementTemplates.noResults.className = 'no-results';\r\n\r\n  elementTemplates.a.setAttribute('role', 'option');\r\n  elementTemplates.a.className = 'dropdown-item';\r\n\r\n  elementTemplates.subtext.className = 'text-muted';\r\n\r\n  elementTemplates.text = elementTemplates.span.cloneNode(false);\r\n  elementTemplates.text.className = 'text';\r\n\r\n  elementTemplates.checkMark = elementTemplates.span.cloneNode(false);\r\n\r\n  var REGEXP_ARROW = new RegExp(keyCodes.ARROW_UP + '|' + keyCodes.ARROW_DOWN);\r\n  var REGEXP_TAB_OR_ESCAPE = new RegExp('^' + keyCodes.TAB + '$|' + keyCodes.ESCAPE);\r\n\r\n  var generateOption = {\r\n    li: function (content, classes, optgroup) {\r\n      var li = elementTemplates.li.cloneNode(false);\r\n\r\n      if (content) {\r\n        if (content.nodeType === 1 || content.nodeType === 11) {\r\n          li.appendChild(content);\r\n        } else {\r\n          li.innerHTML = content;\r\n        }\r\n      }\r\n\r\n      if (typeof classes !== 'undefined' && classes !== '') li.className = classes;\r\n      if (typeof optgroup !== 'undefined' && optgroup !== null) li.classList.add('optgroup-' + optgroup);\r\n\r\n      return li;\r\n    },\r\n\r\n    a: function (text, classes, inline) {\r\n      var a = elementTemplates.a.cloneNode(true);\r\n\r\n      if (text) {\r\n        if (text.nodeType === 11) {\r\n          a.appendChild(text);\r\n        } else {\r\n          a.insertAdjacentHTML('beforeend', text);\r\n        }\r\n      }\r\n\r\n      if (typeof classes !== 'undefined' && classes !== '') a.classList.add.apply(a.classList, classes.split(/\\s+/));\r\n      if (inline) a.setAttribute('style', inline);\r\n\r\n      return a;\r\n    },\r\n\r\n    text: function (options, useFragment) {\r\n      var textElement = elementTemplates.text.cloneNode(false),\r\n          subtextElement,\r\n          iconElement;\r\n\r\n      if (options.content) {\r\n        textElement.innerHTML = options.content;\r\n      } else {\r\n        textElement.textContent = options.text;\r\n\r\n        if (options.icon) {\r\n          var whitespace = elementTemplates.whitespace.cloneNode(false);\r\n\r\n          // need to use <i> for icons in the button to prevent a breaking change\r\n          // note: switch to span in next major release\r\n          iconElement = (useFragment === true ? elementTemplates.i : elementTemplates.span).cloneNode(false);\r\n          iconElement.className = this.options.iconBase + ' ' + options.icon;\r\n\r\n          elementTemplates.fragment.appendChild(iconElement);\r\n          elementTemplates.fragment.appendChild(whitespace);\r\n        }\r\n\r\n        if (options.subtext) {\r\n          subtextElement = elementTemplates.subtext.cloneNode(false);\r\n          subtextElement.textContent = options.subtext;\r\n          textElement.appendChild(subtextElement);\r\n        }\r\n      }\r\n\r\n      if (useFragment === true) {\r\n        while (textElement.childNodes.length > 0) {\r\n          elementTemplates.fragment.appendChild(textElement.childNodes[0]);\r\n        }\r\n      } else {\r\n        elementTemplates.fragment.appendChild(textElement);\r\n      }\r\n\r\n      return elementTemplates.fragment;\r\n    },\r\n\r\n    label: function (options) {\r\n      var textElement = elementTemplates.text.cloneNode(false),\r\n          subtextElement,\r\n          iconElement;\r\n\r\n      textElement.innerHTML = options.display;\r\n\r\n      if (options.icon) {\r\n        var whitespace = elementTemplates.whitespace.cloneNode(false);\r\n\r\n        iconElement = elementTemplates.span.cloneNode(false);\r\n        iconElement.className = this.options.iconBase + ' ' + options.icon;\r\n\r\n        elementTemplates.fragment.appendChild(iconElement);\r\n        elementTemplates.fragment.appendChild(whitespace);\r\n      }\r\n\r\n      if (options.subtext) {\r\n        subtextElement = elementTemplates.subtext.cloneNode(false);\r\n        subtextElement.textContent = options.subtext;\r\n        textElement.appendChild(subtextElement);\r\n      }\r\n\r\n      elementTemplates.fragment.appendChild(textElement);\r\n\r\n      return elementTemplates.fragment;\r\n    }\r\n  }\r\n\r\n  function showNoResults (searchMatch, searchValue) {\r\n    if (!searchMatch.length) {\r\n      elementTemplates.noResults.innerHTML = this.options.noneResultsText.replace('{0}', '\"' + htmlEscape(searchValue) + '\"');\r\n      this.$menuInner[0].firstChild.appendChild(elementTemplates.noResults);\r\n    }\r\n  }\r\n\r\n  var Selectpicker = function (element, options) {\r\n    var that = this;\r\n\r\n    // bootstrap-select has been initialized - revert valHooks.select.set back to its original function\r\n    if (!valHooks.useDefault) {\r\n      $.valHooks.select.set = valHooks._set;\r\n      valHooks.useDefault = true;\r\n    }\r\n\r\n    this.$element = $(element);\r\n    this.$newElement = null;\r\n    this.$button = null;\r\n    this.$menu = null;\r\n    this.options = options;\r\n    this.selectpicker = {\r\n      main: {},\r\n      search: {},\r\n      current: {}, // current changes if a search is in progress\r\n      view: {},\r\n      isSearching: false,\r\n      keydown: {\r\n        keyHistory: '',\r\n        resetKeyHistory: {\r\n          start: function () {\r\n            return setTimeout(function () {\r\n              that.selectpicker.keydown.keyHistory = '';\r\n            }, 800);\r\n          }\r\n        }\r\n      }\r\n    };\r\n\r\n    this.sizeInfo = {};\r\n\r\n    // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a\r\n    // data-attribute)\r\n    if (this.options.title === null) {\r\n      this.options.title = this.$element.attr('title');\r\n    }\r\n\r\n    // Format window padding\r\n    var winPad = this.options.windowPadding;\r\n    if (typeof winPad === 'number') {\r\n      this.options.windowPadding = [winPad, winPad, winPad, winPad];\r\n    }\r\n\r\n    // Expose public methods\r\n    this.val = Selectpicker.prototype.val;\r\n    this.render = Selectpicker.prototype.render;\r\n    this.refresh = Selectpicker.prototype.refresh;\r\n    this.setStyle = Selectpicker.prototype.setStyle;\r\n    this.selectAll = Selectpicker.prototype.selectAll;\r\n    this.deselectAll = Selectpicker.prototype.deselectAll;\r\n    this.destroy = Selectpicker.prototype.destroy;\r\n    this.remove = Selectpicker.prototype.remove;\r\n    this.show = Selectpicker.prototype.show;\r\n    this.hide = Selectpicker.prototype.hide;\r\n\r\n    this.init();\r\n  };\r\n\r\n  Selectpicker.VERSION = '1.13.18';\r\n\r\n  // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.\r\n  Selectpicker.DEFAULTS = {\r\n    noneSelectedText: 'Nothing selected',\r\n    noneResultsText: 'No results matched {0}',\r\n    countSelectedText: function (numSelected, numTotal) {\r\n      return (numSelected == 1) ? '{0} item selected' : '{0} items selected';\r\n    },\r\n    maxOptionsText: function (numAll, numGroup) {\r\n      return [\r\n        (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',\r\n        (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'\r\n      ];\r\n    },\r\n    selectAllText: 'Select All',\r\n    deselectAllText: 'Deselect All',\r\n    doneButton: false,\r\n    doneButtonText: 'Close',\r\n    multipleSeparator: ', ',\r\n    styleBase: 'btn',\r\n    style: classNames.BUTTONCLASS,\r\n    size: 'auto',\r\n    title: null,\r\n    selectedTextFormat: 'values',\r\n    width: false,\r\n    container: false,\r\n    hideDisabled: false,\r\n    showSubtext: false,\r\n    showIcon: true,\r\n    showContent: true,\r\n    dropupAuto: true,\r\n    header: false,\r\n    liveSearch: false,\r\n    liveSearchPlaceholder: null,\r\n    liveSearchNormalize: false,\r\n    liveSearchStyle: 'contains',\r\n    actionsBox: false,\r\n    iconBase: classNames.ICONBASE,\r\n    tickIcon: classNames.TICKICON,\r\n    showTick: false,\r\n    template: {\r\n      caret: '<span class=\"caret\"></span>'\r\n    },\r\n    maxOptions: false,\r\n    mobile: false,\r\n    selectOnTab: false,\r\n    dropdownAlignRight: false,\r\n    windowPadding: 0,\r\n    virtualScroll: 600,\r\n    display: false,\r\n    sanitize: true,\r\n    sanitizeFn: null,\r\n    whiteList: DefaultWhitelist\r\n  };\r\n\r\n  Selectpicker.prototype = {\r\n\r\n    constructor: Selectpicker,\r\n\r\n    init: function () {\r\n      var that = this,\r\n          id = this.$element.attr('id'),\r\n          element = this.$element[0],\r\n          form = element.form;\r\n\r\n      selectId++;\r\n      this.selectId = 'bs-select-' + selectId;\r\n\r\n      element.classList.add('bs-select-hidden');\r\n\r\n      this.multiple = this.$element.prop('multiple');\r\n      this.autofocus = this.$element.prop('autofocus');\r\n\r\n      if (element.classList.contains('show-tick')) {\r\n        this.options.showTick = true;\r\n      }\r\n\r\n      this.$newElement = this.createDropdown();\r\n      this.buildData();\r\n      this.$element\r\n        .after(this.$newElement)\r\n        .prependTo(this.$newElement);\r\n\r\n      // ensure select is associated with form element if it got unlinked after moving it inside newElement\r\n      if (form && element.form === null) {\r\n        if (!form.id) form.id = 'form-' + this.selectId;\r\n        element.setAttribute('form', form.id);\r\n      }\r\n\r\n      this.$button = this.$newElement.children('button');\r\n      this.$menu = this.$newElement.children(Selector.MENU);\r\n      this.$menuInner = this.$menu.children('.inner');\r\n      this.$searchbox = this.$menu.find('input');\r\n\r\n      element.classList.remove('bs-select-hidden');\r\n\r\n      if (this.options.dropdownAlignRight === true) this.$menu[0].classList.add(classNames.MENURIGHT);\r\n\r\n      if (typeof id !== 'undefined') {\r\n        this.$button.attr('data-id', id);\r\n      }\r\n\r\n      this.checkDisabled();\r\n      this.clickListener();\r\n\r\n      if (this.options.liveSearch) {\r\n        this.liveSearchListener();\r\n        this.focusedParent = this.$searchbox[0];\r\n      } else {\r\n        this.focusedParent = this.$menuInner[0];\r\n      }\r\n\r\n      this.setStyle();\r\n      this.render();\r\n      this.setWidth();\r\n      if (this.options.container) {\r\n        this.selectPosition();\r\n      } else {\r\n        this.$element.on('hide' + EVENT_KEY, function () {\r\n          if (that.isVirtual()) {\r\n            // empty menu on close\r\n            var menuInner = that.$menuInner[0],\r\n                emptyMenu = menuInner.firstChild.cloneNode(false);\r\n\r\n            // replace the existing UL with an empty one - this is faster than $.empty() or innerHTML = ''\r\n            menuInner.replaceChild(emptyMenu, menuInner.firstChild);\r\n            menuInner.scrollTop = 0;\r\n          }\r\n        });\r\n      }\r\n      this.$menu.data('this', this);\r\n      this.$newElement.data('this', this);\r\n      if (this.options.mobile) this.mobile();\r\n\r\n      this.$newElement.on({\r\n        'hide.bs.dropdown': function (e) {\r\n          that.$element.trigger('hide' + EVENT_KEY, e);\r\n        },\r\n        'hidden.bs.dropdown': function (e) {\r\n          that.$element.trigger('hidden' + EVENT_KEY, e);\r\n        },\r\n        'show.bs.dropdown': function (e) {\r\n          that.$element.trigger('show' + EVENT_KEY, e);\r\n        },\r\n        'shown.bs.dropdown': function (e) {\r\n          that.$element.trigger('shown' + EVENT_KEY, e);\r\n        }\r\n      });\r\n\r\n      if (element.hasAttribute('required')) {\r\n        this.$element.on('invalid' + EVENT_KEY, function () {\r\n          that.$button[0].classList.add('bs-invalid');\r\n\r\n          that.$element\r\n            .on('shown' + EVENT_KEY + '.invalid', function () {\r\n              that.$element\r\n                .val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened\r\n                .off('shown' + EVENT_KEY + '.invalid');\r\n            })\r\n            .on('rendered' + EVENT_KEY, function () {\r\n              // if select is no longer invalid, remove the bs-invalid class\r\n              if (this.validity.valid) that.$button[0].classList.remove('bs-invalid');\r\n              that.$element.off('rendered' + EVENT_KEY);\r\n            });\r\n\r\n          that.$button.on('blur' + EVENT_KEY, function () {\r\n            that.$element.trigger('focus').trigger('blur');\r\n            that.$button.off('blur' + EVENT_KEY);\r\n          });\r\n        });\r\n      }\r\n\r\n      setTimeout(function () {\r\n        that.buildList();\r\n        that.$element.trigger('loaded' + EVENT_KEY);\r\n      });\r\n    },\r\n\r\n    createDropdown: function () {\r\n      // Options\r\n      // If we are multiple or showTick option is set, then add the show-tick class\r\n      var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',\r\n          multiselectable = this.multiple ? ' aria-multiselectable=\"true\"' : '',\r\n          inputGroup = '',\r\n          autofocus = this.autofocus ? ' autofocus' : '';\r\n\r\n      if (version.major < 4 && this.$element.parent().hasClass('input-group')) {\r\n        inputGroup = ' input-group-btn';\r\n      }\r\n\r\n      // Elements\r\n      var drop,\r\n          header = '',\r\n          searchbox = '',\r\n          actionsbox = '',\r\n          donebutton = '';\r\n\r\n      if (this.options.header) {\r\n        header =\r\n          '<div class=\"' + classNames.POPOVERHEADER + '\">' +\r\n            '<button type=\"button\" class=\"close\" aria-hidden=\"true\">&times;</button>' +\r\n              this.options.header +\r\n          '</div>';\r\n      }\r\n\r\n      if (this.options.liveSearch) {\r\n        searchbox =\r\n          '<div class=\"bs-searchbox\">' +\r\n            '<input type=\"search\" class=\"form-control\" autocomplete=\"off\"' +\r\n              (\r\n                this.options.liveSearchPlaceholder === null ? ''\r\n                :\r\n                ' placeholder=\"' + htmlEscape(this.options.liveSearchPlaceholder) + '\"'\r\n              ) +\r\n              ' role=\"combobox\" aria-label=\"Search\" aria-controls=\"' + this.selectId + '\" aria-autocomplete=\"list\">' +\r\n          '</div>';\r\n      }\r\n\r\n      if (this.multiple && this.options.actionsBox) {\r\n        actionsbox =\r\n          '<div class=\"bs-actionsbox\">' +\r\n            '<div class=\"btn-group btn-group-sm btn-block\">' +\r\n              '<button type=\"button\" class=\"actions-btn bs-select-all btn ' + classNames.BUTTONCLASS + '\">' +\r\n                this.options.selectAllText +\r\n              '</button>' +\r\n              '<button type=\"button\" class=\"actions-btn bs-deselect-all btn ' + classNames.BUTTONCLASS + '\">' +\r\n                this.options.deselectAllText +\r\n              '</button>' +\r\n            '</div>' +\r\n          '</div>';\r\n      }\r\n\r\n      if (this.multiple && this.options.doneButton) {\r\n        donebutton =\r\n          '<div class=\"bs-donebutton\">' +\r\n            '<div class=\"btn-group btn-block\">' +\r\n              '<button type=\"button\" class=\"btn btn-sm ' + classNames.BUTTONCLASS + '\">' +\r\n                this.options.doneButtonText +\r\n              '</button>' +\r\n            '</div>' +\r\n          '</div>';\r\n      }\r\n\r\n      drop =\r\n        '<div class=\"dropdown bootstrap-select' + showTick + inputGroup + '\">' +\r\n          '<button type=\"button\" tabindex=\"-1\" class=\"' + this.options.styleBase + ' dropdown-toggle\" ' + (this.options.display === 'static' ? 'data-display=\"static\"' : '') + 'data-toggle=\"dropdown\"' + autofocus + ' role=\"combobox\" aria-owns=\"' + this.selectId + '\" aria-haspopup=\"listbox\" aria-expanded=\"false\">' +\r\n            '<div class=\"filter-option\">' +\r\n              '<div class=\"filter-option-inner\">' +\r\n                '<div class=\"filter-option-inner-inner\"></div>' +\r\n              '</div> ' +\r\n            '</div>' +\r\n            (\r\n              version.major === '4' ? ''\r\n              :\r\n              '<span class=\"bs-caret\">' +\r\n                this.options.template.caret +\r\n              '</span>'\r\n            ) +\r\n          '</button>' +\r\n          '<div class=\"' + classNames.MENU + ' ' + (version.major === '4' ? '' : classNames.SHOW) + '\">' +\r\n            header +\r\n            searchbox +\r\n            actionsbox +\r\n            '<div class=\"inner ' + classNames.SHOW + '\" role=\"listbox\" id=\"' + this.selectId + '\" tabindex=\"-1\" ' + multiselectable + '>' +\r\n                '<ul class=\"' + classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '') + '\" role=\"presentation\">' +\r\n                '</ul>' +\r\n            '</div>' +\r\n            donebutton +\r\n          '</div>' +\r\n        '</div>';\r\n\r\n      return $(drop);\r\n    },\r\n\r\n    setPositionData: function () {\r\n      this.selectpicker.view.canHighlight = [];\r\n      this.selectpicker.view.size = 0;\r\n      this.selectpicker.view.firstHighlightIndex = false;\r\n\r\n      for (var i = 0; i < this.selectpicker.current.data.length; i++) {\r\n        var li = this.selectpicker.current.data[i],\r\n            canHighlight = true;\r\n\r\n        if (li.type === 'divider') {\r\n          canHighlight = false;\r\n          li.height = this.sizeInfo.dividerHeight;\r\n        } else if (li.type === 'optgroup-label') {\r\n          canHighlight = false;\r\n          li.height = this.sizeInfo.dropdownHeaderHeight;\r\n        } else {\r\n          li.height = this.sizeInfo.liHeight;\r\n        }\r\n\r\n        if (li.disabled) canHighlight = false;\r\n\r\n        this.selectpicker.view.canHighlight.push(canHighlight);\r\n\r\n        if (canHighlight) {\r\n          this.selectpicker.view.size++;\r\n          li.posinset = this.selectpicker.view.size;\r\n          if (this.selectpicker.view.firstHighlightIndex === false) this.selectpicker.view.firstHighlightIndex = i;\r\n        }\r\n\r\n        li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height;\r\n      }\r\n    },\r\n\r\n    isVirtual: function () {\r\n      return (this.options.virtualScroll !== false) && (this.selectpicker.main.elements.length >= this.options.virtualScroll) || this.options.virtualScroll === true;\r\n    },\r\n\r\n    createView: function (isSearching, setSize, refresh) {\r\n      var that = this,\r\n          scrollTop = 0,\r\n          active = [],\r\n          selected,\r\n          prevActive;\r\n\r\n      this.selectpicker.isSearching = isSearching;\r\n      this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main;\r\n\r\n      this.setPositionData();\r\n\r\n      if (setSize) {\r\n        if (refresh) {\r\n          scrollTop = this.$menuInner[0].scrollTop;\r\n        } else if (!that.multiple) {\r\n          var element = that.$element[0],\r\n              selectedIndex = (element.options[element.selectedIndex] || {}).liIndex;\r\n\r\n          if (typeof selectedIndex === 'number' && that.options.size !== false) {\r\n            var selectedData = that.selectpicker.main.data[selectedIndex],\r\n                position = selectedData && selectedData.position;\r\n\r\n            if (position) {\r\n              scrollTop = position - ((that.sizeInfo.menuInnerHeight + that.sizeInfo.liHeight) / 2);\r\n            }\r\n          }\r\n        }\r\n      }\r\n\r\n      scroll(scrollTop, true);\r\n\r\n      this.$menuInner.off('scroll.createView').on('scroll.createView', function (e, updateValue) {\r\n        if (!that.noScroll) scroll(this.scrollTop, updateValue);\r\n        that.noScroll = false;\r\n      });\r\n\r\n      function scroll (scrollTop, init) {\r\n        var size = that.selectpicker.current.elements.length,\r\n            chunks = [],\r\n            chunkSize,\r\n            chunkCount,\r\n            firstChunk,\r\n            lastChunk,\r\n            currentChunk,\r\n            prevPositions,\r\n            positionIsDifferent,\r\n            previousElements,\r\n            menuIsDifferent = true,\r\n            isVirtual = that.isVirtual();\r\n\r\n        that.selectpicker.view.scrollTop = scrollTop;\r\n\r\n        chunkSize = Math.ceil(that.sizeInfo.menuInnerHeight / that.sizeInfo.liHeight * 1.5); // number of options in a chunk\r\n        chunkCount = Math.round(size / chunkSize) || 1; // number of chunks\r\n\r\n        for (var i = 0; i < chunkCount; i++) {\r\n          var endOfChunk = (i + 1) * chunkSize;\r\n\r\n          if (i === chunkCount - 1) {\r\n            endOfChunk = size;\r\n          }\r\n\r\n          chunks[i] = [\r\n            (i) * chunkSize + (!i ? 0 : 1),\r\n            endOfChunk\r\n          ];\r\n\r\n          if (!size) break;\r\n\r\n          if (currentChunk === undefined && scrollTop - 1 <= that.selectpicker.current.data[endOfChunk - 1].position - that.sizeInfo.menuInnerHeight) {\r\n            currentChunk = i;\r\n          }\r\n        }\r\n\r\n        if (currentChunk === undefined) currentChunk = 0;\r\n\r\n        prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1];\r\n\r\n        // always display previous, current, and next chunks\r\n        firstChunk = Math.max(0, currentChunk - 1);\r\n        lastChunk = Math.min(chunkCount - 1, currentChunk + 1);\r\n\r\n        that.selectpicker.view.position0 = isVirtual === false ? 0 : (Math.max(0, chunks[firstChunk][0]) || 0);\r\n        that.selectpicker.view.position1 = isVirtual === false ? size : (Math.min(size, chunks[lastChunk][1]) || 0);\r\n\r\n        positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1;\r\n\r\n        if (that.activeIndex !== undefined) {\r\n          prevActive = that.selectpicker.main.elements[that.prevActiveIndex];\r\n          active = that.selectpicker.main.elements[that.activeIndex];\r\n          selected = that.selectpicker.main.elements[that.selectedIndex];\r\n\r\n          if (init) {\r\n            if (that.activeIndex !== that.selectedIndex) {\r\n              that.defocusItem(active);\r\n            }\r\n            that.activeIndex = undefined;\r\n          }\r\n\r\n          if (that.activeIndex && that.activeIndex !== that.selectedIndex) {\r\n            that.defocusItem(selected);\r\n          }\r\n        }\r\n\r\n        if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex) {\r\n          that.defocusItem(prevActive);\r\n        }\r\n\r\n        if (init || positionIsDifferent) {\r\n          previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : [];\r\n\r\n          if (isVirtual === false) {\r\n            that.selectpicker.view.visibleElements = that.selectpicker.current.elements;\r\n          } else {\r\n            that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1);\r\n          }\r\n\r\n          that.setOptionStatus();\r\n\r\n          // if searching, check to make sure the list has actually been updated before updating DOM\r\n          // this prevents unnecessary repaints\r\n          if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements);\r\n\r\n          // if virtual scroll is disabled and not searching,\r\n          // menu should never need to be updated more than once\r\n          if ((init || isVirtual === true) && menuIsDifferent) {\r\n            var menuInner = that.$menuInner[0],\r\n                menuFragment = document.createDocumentFragment(),\r\n                emptyMenu = menuInner.firstChild.cloneNode(false),\r\n                marginTop,\r\n                marginBottom,\r\n                elements = that.selectpicker.view.visibleElements,\r\n                toSanitize = [];\r\n\r\n            // replace the existing UL with an empty one - this is faster than $.empty()\r\n            menuInner.replaceChild(emptyMenu, menuInner.firstChild);\r\n\r\n            for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) {\r\n              var element = elements[i],\r\n                  elText,\r\n                  elementData;\r\n\r\n              if (that.options.sanitize) {\r\n                elText = element.lastChild;\r\n\r\n                if (elText) {\r\n                  elementData = that.selectpicker.current.data[i + that.selectpicker.view.position0];\r\n\r\n                  if (elementData && elementData.content && !elementData.sanitized) {\r\n                    toSanitize.push(elText);\r\n                    elementData.sanitized = true;\r\n                  }\r\n                }\r\n              }\r\n\r\n              menuFragment.appendChild(element);\r\n            }\r\n\r\n            if (that.options.sanitize && toSanitize.length) {\r\n              sanitizeHtml(toSanitize, that.options.whiteList, that.options.sanitizeFn);\r\n            }\r\n\r\n            if (isVirtual === true) {\r\n              marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position);\r\n              marginBottom = (that.selectpicker.view.position1 > size - 1 ? 0 : that.selectpicker.current.data[size - 1].position - that.selectpicker.current.data[that.selectpicker.view.position1 - 1].position);\r\n\r\n              menuInner.firstChild.style.marginTop = marginTop + 'px';\r\n              menuInner.firstChild.style.marginBottom = marginBottom + 'px';\r\n            } else {\r\n              menuInner.firstChild.style.marginTop = 0;\r\n              menuInner.firstChild.style.marginBottom = 0;\r\n            }\r\n\r\n            menuInner.firstChild.appendChild(menuFragment);\r\n\r\n            // if an option is encountered that is wider than the current menu width, update the menu width accordingly\r\n            // switch to ResizeObserver with increased browser support\r\n            if (isVirtual === true && that.sizeInfo.hasScrollBar) {\r\n              var menuInnerInnerWidth = menuInner.firstChild.offsetWidth;\r\n\r\n              if (init && menuInnerInnerWidth < that.sizeInfo.menuInnerInnerWidth && that.sizeInfo.totalMenuWidth > that.sizeInfo.selectWidth) {\r\n                menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';\r\n              } else if (menuInnerInnerWidth > that.sizeInfo.menuInnerInnerWidth) {\r\n                // set to 0 to get actual width of menu\r\n                that.$menu[0].style.minWidth = 0;\r\n\r\n                var actualMenuWidth = menuInner.firstChild.offsetWidth;\r\n\r\n                if (actualMenuWidth > that.sizeInfo.menuInnerInnerWidth) {\r\n                  that.sizeInfo.menuInnerInnerWidth = actualMenuWidth;\r\n                  menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';\r\n                }\r\n\r\n                // reset to default CSS styling\r\n                that.$menu[0].style.minWidth = '';\r\n              }\r\n            }\r\n          }\r\n        }\r\n\r\n        that.prevActiveIndex = that.activeIndex;\r\n\r\n        if (!that.options.liveSearch) {\r\n          that.$menuInner.trigger('focus');\r\n        } else if (isSearching && init) {\r\n          var index = 0,\r\n              newActive;\r\n\r\n          if (!that.selectpicker.view.canHighlight[index]) {\r\n            index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true);\r\n          }\r\n\r\n          newActive = that.selectpicker.view.visibleElements[index];\r\n\r\n          that.defocusItem(that.selectpicker.view.currentActive);\r\n\r\n          that.activeIndex = (that.selectpicker.current.data[index] || {}).index;\r\n\r\n          that.focusItem(newActive);\r\n        }\r\n      }\r\n\r\n      $(window)\r\n        .off('resize' + EVENT_KEY + '.' + this.selectId + '.createView')\r\n        .on('resize' + EVENT_KEY + '.' + this.selectId + '.createView', function () {\r\n          var isActive = that.$newElement.hasClass(classNames.SHOW);\r\n\r\n          if (isActive) scroll(that.$menuInner[0].scrollTop);\r\n        });\r\n    },\r\n\r\n    focusItem: function (li, liData, noStyle) {\r\n      if (li) {\r\n        liData = liData || this.selectpicker.main.data[this.activeIndex];\r\n        var a = li.firstChild;\r\n\r\n        if (a) {\r\n          a.setAttribute('aria-setsize', this.selectpicker.view.size);\r\n          a.setAttribute('aria-posinset', liData.posinset);\r\n\r\n          if (noStyle !== true) {\r\n            this.focusedParent.setAttribute('aria-activedescendant', a.id);\r\n            li.classList.add('active');\r\n            a.classList.add('active');\r\n          }\r\n        }\r\n      }\r\n    },\r\n\r\n    defocusItem: function (li) {\r\n      if (li) {\r\n        li.classList.remove('active');\r\n        if (li.firstChild) li.firstChild.classList.remove('active');\r\n      }\r\n    },\r\n\r\n    setPlaceholder: function () {\r\n      var that = this,\r\n          updateIndex = false;\r\n\r\n      if (this.options.title && !this.multiple) {\r\n        if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option');\r\n\r\n        // this option doesn't create a new <li> element, but does add a new option at the start,\r\n        // so startIndex should increase to prevent having to check every option for the bs-title-option class\r\n        updateIndex = true;\r\n\r\n        var element = this.$element[0],\r\n            selectTitleOption = false,\r\n            titleNotAppended = !this.selectpicker.view.titleOption.parentNode,\r\n            selectedIndex = element.selectedIndex,\r\n            selectedOption = element.options[selectedIndex],\r\n            navigation = window.performance && window.performance.getEntriesByType('navigation'),\r\n            // Safari doesn't support getEntriesByType('navigation') - fall back to performance.navigation\r\n            isNotBackForward = (navigation && navigation.length) ? navigation[0].type !== 'back_forward' : window.performance.navigation.type !== 2;\r\n\r\n        if (titleNotAppended) {\r\n          // Use native JS to prepend option (faster)\r\n          this.selectpicker.view.titleOption.className = 'bs-title-option';\r\n          this.selectpicker.view.titleOption.value = '';\r\n\r\n          // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.\r\n          // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,\r\n          // if so, the select will have the data-selected attribute\r\n          selectTitleOption = !selectedOption || (selectedIndex === 0 && selectedOption.defaultSelected === false && this.$element.data('selected') === undefined);\r\n        }\r\n\r\n        if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) {\r\n          element.insertBefore(this.selectpicker.view.titleOption, element.firstChild);\r\n        }\r\n\r\n        // Set selected *after* appending to select,\r\n        // otherwise the option doesn't get selected in IE\r\n        // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11\r\n        if (selectTitleOption && isNotBackForward) {\r\n          element.selectedIndex = 0;\r\n        } else if (document.readyState !== 'complete') {\r\n          // if navigation type is back_forward, there's a chance the select will have its value set by BFCache\r\n          // wait for that value to be set, then run render again\r\n          window.addEventListener('pageshow', function () {\r\n            if (that.selectpicker.view.displayedValue !== element.value) that.render();\r\n          });\r\n        }\r\n      }\r\n\r\n      return updateIndex;\r\n    },\r\n\r\n    buildData: function () {\r\n      var optionSelector = ':not([hidden]):not([data-hidden=\"true\"])',\r\n          mainData = [],\r\n          optID = 0,\r\n          startIndex = this.setPlaceholder() ? 1 : 0; // append the titleOption if necessary and skip the first option in the loop\r\n\r\n      if (this.options.hideDisabled) optionSelector += ':not(:disabled)';\r\n\r\n      var selectOptions = this.$element[0].querySelectorAll('select > *' + optionSelector);\r\n\r\n      function addDivider (config) {\r\n        var previousData = mainData[mainData.length - 1];\r\n\r\n        // ensure optgroup doesn't create back-to-back dividers\r\n        if (\r\n          previousData &&\r\n          previousData.type === 'divider' &&\r\n          (previousData.optID || config.optID)\r\n        ) {\r\n          return;\r\n        }\r\n\r\n        config = config || {};\r\n        config.type = 'divider';\r\n\r\n        mainData.push(config);\r\n      }\r\n\r\n      function addOption (option, config) {\r\n        config = config || {};\r\n\r\n        config.divider = option.getAttribute('data-divider') === 'true';\r\n\r\n        if (config.divider) {\r\n          addDivider({\r\n            optID: config.optID\r\n          });\r\n        } else {\r\n          var liIndex = mainData.length,\r\n              cssText = option.style.cssText,\r\n              inlineStyle = cssText ? htmlEscape(cssText) : '',\r\n              optionClass = (option.className || '') + (config.optgroupClass || '');\r\n\r\n          if (config.optID) optionClass = 'opt ' + optionClass;\r\n\r\n          config.optionClass = optionClass.trim();\r\n          config.inlineStyle = inlineStyle;\r\n          config.text = option.textContent;\r\n\r\n          config.content = option.getAttribute('data-content');\r\n          config.tokens = option.getAttribute('data-tokens');\r\n          config.subtext = option.getAttribute('data-subtext');\r\n          config.icon = option.getAttribute('data-icon');\r\n\r\n          option.liIndex = liIndex;\r\n\r\n          config.display = config.content || config.text;\r\n          config.type = 'option';\r\n          config.index = liIndex;\r\n          config.option = option;\r\n          config.selected = !!option.selected;\r\n          config.disabled = config.disabled || !!option.disabled;\r\n\r\n          mainData.push(config);\r\n        }\r\n      }\r\n\r\n      function addOptgroup (index, selectOptions) {\r\n        var optgroup = selectOptions[index],\r\n            // skip placeholder option\r\n            previous = index - 1 < startIndex ? false : selectOptions[index - 1],\r\n            next = selectOptions[index + 1],\r\n            options = optgroup.querySelectorAll('option' + optionSelector);\r\n\r\n        if (!options.length) return;\r\n\r\n        var config = {\r\n              display: htmlEscape(optgroup.label),\r\n              subtext: optgroup.getAttribute('data-subtext'),\r\n              icon: optgroup.getAttribute('data-icon'),\r\n              type: 'optgroup-label',\r\n              optgroupClass: ' ' + (optgroup.className || '')\r\n            },\r\n            headerIndex,\r\n            lastIndex;\r\n\r\n        optID++;\r\n\r\n        if (previous) {\r\n          addDivider({ optID: optID });\r\n        }\r\n\r\n        config.optID = optID;\r\n\r\n        mainData.push(config);\r\n\r\n        for (var j = 0, len = options.length; j < len; j++) {\r\n          var option = options[j];\r\n\r\n          if (j === 0) {\r\n            headerIndex = mainData.length - 1;\r\n            lastIndex = headerIndex + len;\r\n          }\r\n\r\n          addOption(option, {\r\n            headerIndex: headerIndex,\r\n            lastIndex: lastIndex,\r\n            optID: config.optID,\r\n            optgroupClass: config.optgroupClass,\r\n            disabled: optgroup.disabled\r\n          });\r\n        }\r\n\r\n        if (next) {\r\n          addDivider({ optID: optID });\r\n        }\r\n      }\r\n\r\n      for (var len = selectOptions.length, i = startIndex; i < len; i++) {\r\n        var item = selectOptions[i];\r\n\r\n        if (item.tagName !== 'OPTGROUP') {\r\n          addOption(item, {});\r\n        } else {\r\n          addOptgroup(i, selectOptions);\r\n        }\r\n      }\r\n\r\n      this.selectpicker.main.data = this.selectpicker.current.data = mainData;\r\n    },\r\n\r\n    buildList: function () {\r\n      var that = this,\r\n          selectData = this.selectpicker.main.data,\r\n          mainElements = [],\r\n          widestOptionLength = 0;\r\n\r\n      if ((that.options.showTick || that.multiple) && !elementTemplates.checkMark.parentNode) {\r\n        elementTemplates.checkMark.className = this.options.iconBase + ' ' + that.options.tickIcon + ' check-mark';\r\n        elementTemplates.a.appendChild(elementTemplates.checkMark);\r\n      }\r\n\r\n      function buildElement (item) {\r\n        var liElement,\r\n            combinedLength = 0;\r\n\r\n        switch (item.type) {\r\n          case 'divider':\r\n            liElement = generateOption.li(\r\n              false,\r\n              classNames.DIVIDER,\r\n              (item.optID ? item.optID + 'div' : undefined)\r\n            );\r\n\r\n            break;\r\n\r\n          case 'option':\r\n            liElement = generateOption.li(\r\n              generateOption.a(\r\n                generateOption.text.call(that, item),\r\n                item.optionClass,\r\n                item.inlineStyle\r\n              ),\r\n              '',\r\n              item.optID\r\n            );\r\n\r\n            if (liElement.firstChild) {\r\n              liElement.firstChild.id = that.selectId + '-' + item.index;\r\n            }\r\n\r\n            break;\r\n\r\n          case 'optgroup-label':\r\n            liElement = generateOption.li(\r\n              generateOption.label.call(that, item),\r\n              'dropdown-header' + item.optgroupClass,\r\n              item.optID\r\n            );\r\n\r\n            break;\r\n        }\r\n\r\n        item.element = liElement;\r\n        mainElements.push(liElement);\r\n\r\n        // count the number of characters in the option - not perfect, but should work in most cases\r\n        if (item.display) combinedLength += item.display.length;\r\n        if (item.subtext) combinedLength += item.subtext.length;\r\n        // if there is an icon, ensure this option's width is checked\r\n        if (item.icon) combinedLength += 1;\r\n\r\n        if (combinedLength > widestOptionLength) {\r\n          widestOptionLength = combinedLength;\r\n\r\n          // guess which option is the widest\r\n          // use this when calculating menu width\r\n          // not perfect, but it's fast, and the width will be updating accordingly when scrolling\r\n          that.selectpicker.view.widestOption = mainElements[mainElements.length - 1];\r\n        }\r\n      }\r\n\r\n      for (var len = selectData.length, i = 0; i < len; i++) {\r\n        var item = selectData[i];\r\n\r\n        buildElement(item);\r\n      }\r\n\r\n      this.selectpicker.main.elements = this.selectpicker.current.elements = mainElements;\r\n    },\r\n\r\n    findLis: function () {\r\n      return this.$menuInner.find('.inner > li');\r\n    },\r\n\r\n    render: function () {\r\n      var that = this,\r\n          element = this.$element[0],\r\n          // ensure titleOption is appended and selected (if necessary) before getting selectedOptions\r\n          placeholderSelected = this.setPlaceholder() && element.selectedIndex === 0,\r\n          selectedOptions = getSelectedOptions(element, this.options.hideDisabled),\r\n          selectedCount = selectedOptions.length,\r\n          button = this.$button[0],\r\n          buttonInner = button.querySelector('.filter-option-inner-inner'),\r\n          multipleSeparator = document.createTextNode(this.options.multipleSeparator),\r\n          titleFragment = elementTemplates.fragment.cloneNode(false),\r\n          showCount,\r\n          countMax,\r\n          hasContent = false;\r\n\r\n      button.classList.toggle('bs-placeholder', that.multiple ? !selectedCount : !getSelectValues(element, selectedOptions));\r\n\r\n      if (!that.multiple && selectedOptions.length === 1) {\r\n        that.selectpicker.view.displayedValue = getSelectValues(element, selectedOptions);\r\n      }\r\n\r\n      if (this.options.selectedTextFormat === 'static') {\r\n        titleFragment = generateOption.text.call(this, { text: this.options.title }, true);\r\n      } else {\r\n        showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 1;\r\n\r\n        // determine if the number of selected options will be shown (showCount === true)\r\n        if (showCount) {\r\n          countMax = this.options.selectedTextFormat.split('>');\r\n          showCount = (countMax.length > 1 && selectedCount > countMax[1]) || (countMax.length === 1 && selectedCount >= 2);\r\n        }\r\n\r\n        // only loop through all selected options if the count won't be shown\r\n        if (showCount === false) {\r\n          if (!placeholderSelected) {\r\n            for (var selectedIndex = 0; selectedIndex < selectedCount; selectedIndex++) {\r\n              if (selectedIndex < 50) {\r\n                var option = selectedOptions[selectedIndex],\r\n                    thisData = this.selectpicker.main.data[option.liIndex],\r\n                    titleOptions = {};\r\n\r\n                if (this.multiple && selectedIndex > 0) {\r\n                  titleFragment.appendChild(multipleSeparator.cloneNode(false));\r\n                }\r\n\r\n                if (option.title) {\r\n                  titleOptions.text = option.title;\r\n                } else if (thisData) {\r\n                  if (thisData.content && that.options.showContent) {\r\n                    titleOptions.content = thisData.content.toString();\r\n                    hasContent = true;\r\n                  } else {\r\n                    if (that.options.showIcon) {\r\n                      titleOptions.icon = thisData.icon;\r\n                    }\r\n                    if (that.options.showSubtext && !that.multiple && thisData.subtext) titleOptions.subtext = ' ' + thisData.subtext;\r\n                    titleOptions.text = option.textContent.trim();\r\n                  }\r\n                }\r\n\r\n                titleFragment.appendChild(generateOption.text.call(this, titleOptions, true));\r\n              } else {\r\n                break;\r\n              }\r\n            }\r\n\r\n            // add ellipsis\r\n            if (selectedCount > 49) {\r\n              titleFragment.appendChild(document.createTextNode('...'));\r\n            }\r\n          }\r\n        } else {\r\n          var optionSelector = ':not([hidden]):not([data-hidden=\"true\"]):not([data-divider=\"true\"])';\r\n          if (this.options.hideDisabled) optionSelector += ':not(:disabled)';\r\n\r\n          // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc.\r\n          var totalCount = this.$element[0].querySelectorAll('select > option' + optionSelector + ', optgroup' + optionSelector + ' option' + optionSelector).length,\r\n              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedCount, totalCount) : this.options.countSelectedText;\r\n\r\n          titleFragment = generateOption.text.call(this, {\r\n            text: tr8nText.replace('{0}', selectedCount.toString()).replace('{1}', totalCount.toString())\r\n          }, true);\r\n        }\r\n      }\r\n\r\n      if (this.options.title == undefined) {\r\n        // use .attr to ensure undefined is returned if title attribute is not set\r\n        this.options.title = this.$element.attr('title');\r\n      }\r\n\r\n      // If the select doesn't have a title, then use the default, or if nothing is set at all, use noneSelectedText\r\n      if (!titleFragment.childNodes.length) {\r\n        titleFragment = generateOption.text.call(this, {\r\n          text: typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText\r\n        }, true);\r\n      }\r\n\r\n      // strip all HTML tags and trim the result, then unescape any escaped tags\r\n      button.title = titleFragment.textContent.replace(/<[^>]*>?/g, '').trim();\r\n\r\n      if (this.options.sanitize && hasContent) {\r\n        sanitizeHtml([titleFragment], that.options.whiteList, that.options.sanitizeFn);\r\n      }\r\n\r\n      buttonInner.innerHTML = '';\r\n      buttonInner.appendChild(titleFragment);\r\n\r\n      if (version.major < 4 && this.$newElement[0].classList.contains('bs3-has-addon')) {\r\n        var filterExpand = button.querySelector('.filter-expand'),\r\n            clone = buttonInner.cloneNode(true);\r\n\r\n        clone.className = 'filter-expand';\r\n\r\n        if (filterExpand) {\r\n          button.replaceChild(clone, filterExpand);\r\n        } else {\r\n          button.appendChild(clone);\r\n        }\r\n      }\r\n\r\n      this.$element.trigger('rendered' + EVENT_KEY);\r\n    },\r\n\r\n    /**\r\n     * @param [style]\r\n     * @param [status]\r\n     */\r\n    setStyle: function (newStyle, status) {\r\n      var button = this.$button[0],\r\n          newElement = this.$newElement[0],\r\n          style = this.options.style.trim(),\r\n          buttonClass;\r\n\r\n      if (this.$element.attr('class')) {\r\n        this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\\[.*\\]/gi, ''));\r\n      }\r\n\r\n      if (version.major < 4) {\r\n        newElement.classList.add('bs3');\r\n\r\n        if (newElement.parentNode.classList && newElement.parentNode.classList.contains('input-group') &&\r\n            (newElement.previousElementSibling || newElement.nextElementSibling) &&\r\n            (newElement.previousElementSibling || newElement.nextElementSibling).classList.contains('input-group-addon')\r\n        ) {\r\n          newElement.classList.add('bs3-has-addon');\r\n        }\r\n      }\r\n\r\n      if (newStyle) {\r\n        buttonClass = newStyle.trim();\r\n      } else {\r\n        buttonClass = style;\r\n      }\r\n\r\n      if (status == 'add') {\r\n        if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));\r\n      } else if (status == 'remove') {\r\n        if (buttonClass) button.classList.remove.apply(button.classList, buttonClass.split(' '));\r\n      } else {\r\n        if (style) button.classList.remove.apply(button.classList, style.split(' '));\r\n        if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));\r\n      }\r\n    },\r\n\r\n    liHeight: function (refresh) {\r\n      if (!refresh && (this.options.size === false || Object.keys(this.sizeInfo).length)) return;\r\n\r\n      var newElement = elementTemplates.div.cloneNode(false),\r\n          menu = elementTemplates.div.cloneNode(false),\r\n          menuInner = elementTemplates.div.cloneNode(false),\r\n          menuInnerInner = document.createElement('ul'),\r\n          divider = elementTemplates.li.cloneNode(false),\r\n          dropdownHeader = elementTemplates.li.cloneNode(false),\r\n          li,\r\n          a = elementTemplates.a.cloneNode(false),\r\n          text = elementTemplates.span.cloneNode(false),\r\n          header = this.options.header && this.$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null,\r\n          search = this.options.liveSearch ? elementTemplates.div.cloneNode(false) : null,\r\n          actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,\r\n          doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null,\r\n          firstOption = this.$element.find('option')[0];\r\n\r\n      this.sizeInfo.selectWidth = this.$newElement[0].offsetWidth;\r\n\r\n      text.className = 'text';\r\n      a.className = 'dropdown-item ' + (firstOption ? firstOption.className : '');\r\n      newElement.className = this.$menu[0].parentNode.className + ' ' + classNames.SHOW;\r\n      newElement.style.width = 0; // ensure button width doesn't affect natural width of menu when calculating\r\n      if (this.options.width === 'auto') menu.style.minWidth = 0;\r\n      menu.className = classNames.MENU + ' ' + classNames.SHOW;\r\n      menuInner.className = 'inner ' + classNames.SHOW;\r\n      menuInnerInner.className = classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '');\r\n      divider.className = classNames.DIVIDER;\r\n      dropdownHeader.className = 'dropdown-header';\r\n\r\n      text.appendChild(document.createTextNode('\\u200b'));\r\n\r\n      if (this.selectpicker.current.data.length) {\r\n        for (var i = 0; i < this.selectpicker.current.data.length; i++) {\r\n          var data = this.selectpicker.current.data[i];\r\n          if (data.type === 'option') {\r\n            li = data.element;\r\n            break;\r\n          }\r\n        }\r\n      } else {\r\n        li = elementTemplates.li.cloneNode(false);\r\n        a.appendChild(text);\r\n        li.appendChild(a);\r\n      }\r\n\r\n      dropdownHeader.appendChild(text.cloneNode(true));\r\n\r\n      if (this.selectpicker.view.widestOption) {\r\n        menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true));\r\n      }\r\n\r\n      menuInnerInner.appendChild(li);\r\n      menuInnerInner.appendChild(divider);\r\n      menuInnerInner.appendChild(dropdownHeader);\r\n      if (header) menu.appendChild(header);\r\n      if (search) {\r\n        var input = document.createElement('input');\r\n        search.className = 'bs-searchbox';\r\n        input.className = 'form-control';\r\n        search.appendChild(input);\r\n        menu.appendChild(search);\r\n      }\r\n      if (actions) menu.appendChild(actions);\r\n      menuInner.appendChild(menuInnerInner);\r\n      menu.appendChild(menuInner);\r\n      if (doneButton) menu.appendChild(doneButton);\r\n      newElement.appendChild(menu);\r\n\r\n      document.body.appendChild(newElement);\r\n\r\n      var liHeight = li.offsetHeight,\r\n          dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0,\r\n          headerHeight = header ? header.offsetHeight : 0,\r\n          searchHeight = search ? search.offsetHeight : 0,\r\n          actionsHeight = actions ? actions.offsetHeight : 0,\r\n          doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,\r\n          dividerHeight = $(divider).outerHeight(true),\r\n          // fall back to jQuery if getComputedStyle is not supported\r\n          menuStyle = window.getComputedStyle ? window.getComputedStyle(menu) : false,\r\n          menuWidth = menu.offsetWidth,\r\n          $menu = menuStyle ? null : $(menu),\r\n          menuPadding = {\r\n            vert: toInteger(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +\r\n                  toInteger(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +\r\n                  toInteger(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +\r\n                  toInteger(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),\r\n            horiz: toInteger(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) +\r\n                  toInteger(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) +\r\n                  toInteger(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) +\r\n                  toInteger(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth'))\r\n          },\r\n          menuExtras = {\r\n            vert: menuPadding.vert +\r\n                  toInteger(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) +\r\n                  toInteger(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2,\r\n            horiz: menuPadding.horiz +\r\n                  toInteger(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) +\r\n                  toInteger(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2\r\n          },\r\n          scrollBarWidth;\r\n\r\n      menuInner.style.overflowY = 'scroll';\r\n\r\n      scrollBarWidth = menu.offsetWidth - menuWidth;\r\n\r\n      document.body.removeChild(newElement);\r\n\r\n      this.sizeInfo.liHeight = liHeight;\r\n      this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight;\r\n      this.sizeInfo.headerHeight = headerHeight;\r\n      this.sizeInfo.searchHeight = searchHeight;\r\n      this.sizeInfo.actionsHeight = actionsHeight;\r\n      this.sizeInfo.doneButtonHeight = doneButtonHeight;\r\n      this.sizeInfo.dividerHeight = dividerHeight;\r\n      this.sizeInfo.menuPadding = menuPadding;\r\n      this.sizeInfo.menuExtras = menuExtras;\r\n      this.sizeInfo.menuWidth = menuWidth;\r\n      this.sizeInfo.menuInnerInnerWidth = menuWidth - menuPadding.horiz;\r\n      this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth;\r\n      this.sizeInfo.scrollBarWidth = scrollBarWidth;\r\n      this.sizeInfo.selectHeight = this.$newElement[0].offsetHeight;\r\n\r\n      this.setPositionData();\r\n    },\r\n\r\n    getSelectPosition: function () {\r\n      var that = this,\r\n          $window = $(window),\r\n          pos = that.$newElement.offset(),\r\n          $container = $(that.options.container),\r\n          containerPos;\r\n\r\n      if (that.options.container && $container.length && !$container.is('body')) {\r\n        containerPos = $container.offset();\r\n        containerPos.top += parseInt($container.css('borderTopWidth'));\r\n        containerPos.left += parseInt($container.css('borderLeftWidth'));\r\n      } else {\r\n        containerPos = { top: 0, left: 0 };\r\n      }\r\n\r\n      var winPad = that.options.windowPadding;\r\n\r\n      this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();\r\n      this.sizeInfo.selectOffsetBot = $window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo.selectHeight - containerPos.top - winPad[2];\r\n      this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();\r\n      this.sizeInfo.selectOffsetRight = $window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo.selectWidth - containerPos.left - winPad[1];\r\n      this.sizeInfo.selectOffsetTop -= winPad[0];\r\n      this.sizeInfo.selectOffsetLeft -= winPad[3];\r\n    },\r\n\r\n    setMenuSize: function (isAuto) {\r\n      this.getSelectPosition();\r\n\r\n      var selectWidth = this.sizeInfo.selectWidth,\r\n          liHeight = this.sizeInfo.liHeight,\r\n          headerHeight = this.sizeInfo.headerHeight,\r\n          searchHeight = this.sizeInfo.searchHeight,\r\n          actionsHeight = this.sizeInfo.actionsHeight,\r\n          doneButtonHeight = this.sizeInfo.doneButtonHeight,\r\n          divHeight = this.sizeInfo.dividerHeight,\r\n          menuPadding = this.sizeInfo.menuPadding,\r\n          menuInnerHeight,\r\n          menuHeight,\r\n          divLength = 0,\r\n          minHeight,\r\n          _minHeight,\r\n          maxHeight,\r\n          menuInnerMinHeight,\r\n          estimate,\r\n          isDropup;\r\n\r\n      if (this.options.dropupAuto) {\r\n        // Get the estimated height of the menu without scrollbars.\r\n        // This is useful for smaller menus, where there might be plenty of room\r\n        // below the button without setting dropup, but we can't know\r\n        // the exact height of the menu until createView is called later\r\n        estimate = liHeight * this.selectpicker.current.elements.length + menuPadding.vert;\r\n\r\n        isDropup = this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot;\r\n\r\n        // ensure dropup doesn't change while searching (so menu doesn't bounce back and forth)\r\n        if (this.selectpicker.isSearching === true) {\r\n          isDropup = this.selectpicker.dropup;\r\n        }\r\n\r\n        this.$newElement.toggleClass(classNames.DROPUP, isDropup);\r\n        this.selectpicker.dropup = isDropup;\r\n      }\r\n\r\n      if (this.options.size === 'auto') {\r\n        _minHeight = this.selectpicker.current.elements.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0;\r\n        menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert;\r\n        minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;\r\n        menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0);\r\n\r\n        if (this.$newElement.hasClass(classNames.DROPUP)) {\r\n          menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert;\r\n        }\r\n\r\n        maxHeight = menuHeight;\r\n        menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert;\r\n      } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {\r\n        for (var i = 0; i < this.options.size; i++) {\r\n          if (this.selectpicker.current.data[i].type === 'divider') divLength++;\r\n        }\r\n\r\n        menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;\r\n        menuInnerHeight = menuHeight - menuPadding.vert;\r\n        maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;\r\n        minHeight = menuInnerMinHeight = '';\r\n      }\r\n\r\n      this.$menu.css({\r\n        'max-height': maxHeight + 'px',\r\n        'overflow': 'hidden',\r\n        'min-height': minHeight + 'px'\r\n      });\r\n\r\n      this.$menuInner.css({\r\n        'max-height': menuInnerHeight + 'px',\r\n        'overflow-y': 'auto',\r\n        'min-height': menuInnerMinHeight + 'px'\r\n      });\r\n\r\n      // ensure menuInnerHeight is always a positive number to prevent issues calculating chunkSize in createView\r\n      this.sizeInfo.menuInnerHeight = Math.max(menuInnerHeight, 1);\r\n\r\n      if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) {\r\n        this.sizeInfo.hasScrollBar = true;\r\n        this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth;\r\n      }\r\n\r\n      if (this.options.dropdownAlignRight === 'auto') {\r\n        this.$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.sizeInfo.totalMenuWidth - selectWidth));\r\n      }\r\n\r\n      if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update();\r\n    },\r\n\r\n    setSize: function (refresh) {\r\n      this.liHeight(refresh);\r\n\r\n      if (this.options.header) this.$menu.css('padding-top', 0);\r\n\r\n      if (this.options.size !== false) {\r\n        var that = this,\r\n            $window = $(window);\r\n\r\n        this.setMenuSize();\r\n\r\n        if (this.options.liveSearch) {\r\n          this.$searchbox\r\n            .off('input.setMenuSize propertychange.setMenuSize')\r\n            .on('input.setMenuSize propertychange.setMenuSize', function () {\r\n              return that.setMenuSize();\r\n            });\r\n        }\r\n\r\n        if (this.options.size === 'auto') {\r\n          $window\r\n            .off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize')\r\n            .on('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize', function () {\r\n              return that.setMenuSize();\r\n            });\r\n        } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {\r\n          $window.off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize');\r\n        }\r\n      }\r\n\r\n      this.createView(false, true, refresh);\r\n    },\r\n\r\n    setWidth: function () {\r\n      var that = this;\r\n\r\n      if (this.options.width === 'auto') {\r\n        requestAnimationFrame(function () {\r\n          that.$menu.css('min-width', '0');\r\n\r\n          that.$element.on('loaded' + EVENT_KEY, function () {\r\n            that.liHeight();\r\n            that.setMenuSize();\r\n\r\n            // Get correct width if element is hidden\r\n            var $selectClone = that.$newElement.clone().appendTo('body'),\r\n                btnWidth = $selectClone.css('width', 'auto').children('button').outerWidth();\r\n\r\n            $selectClone.remove();\r\n\r\n            // Set width to whatever's larger, button title or longest option\r\n            that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth);\r\n            that.$newElement.css('width', that.sizeInfo.selectWidth + 'px');\r\n          });\r\n        });\r\n      } else if (this.options.width === 'fit') {\r\n        // Remove inline min-width so width can be changed from 'auto'\r\n        this.$menu.css('min-width', '');\r\n        this.$newElement.css('width', '').addClass('fit-width');\r\n      } else if (this.options.width) {\r\n        // Remove inline min-width so width can be changed from 'auto'\r\n        this.$menu.css('min-width', '');\r\n        this.$newElement.css('width', this.options.width);\r\n      } else {\r\n        // Remove inline min-width/width so width can be changed\r\n        this.$menu.css('min-width', '');\r\n        this.$newElement.css('width', '');\r\n      }\r\n      // Remove fit-width class if width is changed programmatically\r\n      if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {\r\n        this.$newElement[0].classList.remove('fit-width');\r\n      }\r\n    },\r\n\r\n    selectPosition: function () {\r\n      this.$bsContainer = $('<div class=\"bs-container\" />');\r\n\r\n      var that = this,\r\n          $container = $(this.options.container),\r\n          pos,\r\n          containerPos,\r\n          actualHeight,\r\n          getPlacement = function ($element) {\r\n            var containerPosition = {},\r\n                // fall back to dropdown's default display setting if display is not manually set\r\n                display = that.options.display || (\r\n                  // Bootstrap 3 doesn't have $.fn.dropdown.Constructor.Default\r\n                  $.fn.dropdown.Constructor.Default ? $.fn.dropdown.Constructor.Default.display\r\n                  : false\r\n                );\r\n\r\n            that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, $element.hasClass(classNames.DROPUP));\r\n            pos = $element.offset();\r\n\r\n            if (!$container.is('body')) {\r\n              containerPos = $container.offset();\r\n              containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();\r\n              containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();\r\n            } else {\r\n              containerPos = { top: 0, left: 0 };\r\n            }\r\n\r\n            actualHeight = $element.hasClass(classNames.DROPUP) ? 0 : $element[0].offsetHeight;\r\n\r\n            // Bootstrap 4+ uses Popper for menu positioning\r\n            if (version.major < 4 || display === 'static') {\r\n              containerPosition.top = pos.top - containerPos.top + actualHeight;\r\n              containerPosition.left = pos.left - containerPos.left;\r\n            }\r\n\r\n            containerPosition.width = $element[0].offsetWidth;\r\n\r\n            that.$bsContainer.css(containerPosition);\r\n          };\r\n\r\n      this.$button.on('click.bs.dropdown.data-api', function () {\r\n        if (that.isDisabled()) {\r\n          return;\r\n        }\r\n\r\n        getPlacement(that.$newElement);\r\n\r\n        that.$bsContainer\r\n          .appendTo(that.options.container)\r\n          .toggleClass(classNames.SHOW, !that.$button.hasClass(classNames.SHOW))\r\n          .append(that.$menu);\r\n      });\r\n\r\n      $(window)\r\n        .off('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId)\r\n        .on('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId, function () {\r\n          var isActive = that.$newElement.hasClass(classNames.SHOW);\r\n\r\n          if (isActive) getPlacement(that.$newElement);\r\n        });\r\n\r\n      this.$element.on('hide' + EVENT_KEY, function () {\r\n        that.$menu.data('height', that.$menu.height());\r\n        that.$bsContainer.detach();\r\n      });\r\n    },\r\n\r\n    setOptionStatus: function (selectedOnly) {\r\n      var that = this;\r\n\r\n      that.noScroll = false;\r\n\r\n      if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) {\r\n        for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) {\r\n          var liData = that.selectpicker.current.data[i + that.selectpicker.view.position0],\r\n              option = liData.option;\r\n\r\n          if (option) {\r\n            if (selectedOnly !== true) {\r\n              that.setDisabled(\r\n                liData.index,\r\n                liData.disabled\r\n              );\r\n            }\r\n\r\n            that.setSelected(\r\n              liData.index,\r\n              option.selected\r\n            );\r\n          }\r\n        }\r\n      }\r\n    },\r\n\r\n    /**\r\n     * @param {number} index - the index of the option that is being changed\r\n     * @param {boolean} selected - true if the option is being selected, false if being deselected\r\n     */\r\n    setSelected: function (index, selected) {\r\n      var li = this.selectpicker.main.elements[index],\r\n          liData = this.selectpicker.main.data[index],\r\n          activeIndexIsSet = this.activeIndex !== undefined,\r\n          thisIsActive = this.activeIndex === index,\r\n          prevActive,\r\n          a,\r\n          // if current option is already active\r\n          // OR\r\n          // if the current option is being selected, it's NOT multiple, and\r\n          // activeIndex is undefined:\r\n          //  - when the menu is first being opened, OR\r\n          //  - after a search has been performed, OR\r\n          //  - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeIndex)\r\n          keepActive = thisIsActive || (selected && !this.multiple && !activeIndexIsSet);\r\n\r\n      liData.selected = selected;\r\n\r\n      a = li.firstChild;\r\n\r\n      if (selected) {\r\n        this.selectedIndex = index;\r\n      }\r\n\r\n      li.classList.toggle('selected', selected);\r\n\r\n      if (keepActive) {\r\n        this.focusItem(li, liData);\r\n        this.selectpicker.view.currentActive = li;\r\n        this.activeIndex = index;\r\n      } else {\r\n        this.defocusItem(li);\r\n      }\r\n\r\n      if (a) {\r\n        a.classList.toggle('selected', selected);\r\n\r\n        if (selected) {\r\n          a.setAttribute('aria-selected', true);\r\n        } else {\r\n          if (this.multiple) {\r\n            a.setAttribute('aria-selected', false);\r\n          } else {\r\n            a.removeAttribute('aria-selected');\r\n          }\r\n        }\r\n      }\r\n\r\n      if (!keepActive && !activeIndexIsSet && selected && this.prevActiveIndex !== undefined) {\r\n        prevActive = this.selectpicker.main.elements[this.prevActiveIndex];\r\n\r\n        this.defocusItem(prevActive);\r\n      }\r\n    },\r\n\r\n    /**\r\n     * @param {number} index - the index of the option that is being disabled\r\n     * @param {boolean} disabled - true if the option is being disabled, false if being enabled\r\n     */\r\n    setDisabled: function (index, disabled) {\r\n      var li = this.selectpicker.main.elements[index],\r\n          a;\r\n\r\n      this.selectpicker.main.data[index].disabled = disabled;\r\n\r\n      a = li.firstChild;\r\n\r\n      li.classList.toggle(classNames.DISABLED, disabled);\r\n\r\n      if (a) {\r\n        if (version.major === '4') a.classList.toggle(classNames.DISABLED, disabled);\r\n\r\n        if (disabled) {\r\n          a.setAttribute('aria-disabled', disabled);\r\n          a.setAttribute('tabindex', -1);\r\n        } else {\r\n          a.removeAttribute('aria-disabled');\r\n          a.setAttribute('tabindex', 0);\r\n        }\r\n      }\r\n    },\r\n\r\n    isDisabled: function () {\r\n      return this.$element[0].disabled;\r\n    },\r\n\r\n    checkDisabled: function () {\r\n      if (this.isDisabled()) {\r\n        this.$newElement[0].classList.add(classNames.DISABLED);\r\n        this.$button.addClass(classNames.DISABLED).attr('aria-disabled', true);\r\n      } else {\r\n        if (this.$button[0].classList.contains(classNames.DISABLED)) {\r\n          this.$newElement[0].classList.remove(classNames.DISABLED);\r\n          this.$button.removeClass(classNames.DISABLED).attr('aria-disabled', false);\r\n        }\r\n      }\r\n    },\r\n\r\n    clickListener: function () {\r\n      var that = this,\r\n          $document = $(document);\r\n\r\n      $document.data('spaceSelect', false);\r\n\r\n      this.$button.on('keyup', function (e) {\r\n        if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {\r\n          e.preventDefault();\r\n          $document.data('spaceSelect', false);\r\n        }\r\n      });\r\n\r\n      this.$newElement.on('show.bs.dropdown', function () {\r\n        if (version.major > 3 && !that.dropdown) {\r\n          that.dropdown = that.$button.data('bs.dropdown');\r\n          that.dropdown._menu = that.$menu[0];\r\n        }\r\n      });\r\n\r\n      this.$button.on('click.bs.dropdown.data-api', function () {\r\n        if (!that.$newElement.hasClass(classNames.SHOW)) {\r\n          that.setSize();\r\n        }\r\n      });\r\n\r\n      function setFocus () {\r\n        if (that.options.liveSearch) {\r\n          that.$searchbox.trigger('focus');\r\n        } else {\r\n          that.$menuInner.trigger('focus');\r\n        }\r\n      }\r\n\r\n      function checkPopperExists () {\r\n        if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state.isCreated) {\r\n          setFocus();\r\n        } else {\r\n          requestAnimationFrame(checkPopperExists);\r\n        }\r\n      }\r\n\r\n      this.$element.on('shown' + EVENT_KEY, function () {\r\n        if (that.$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) {\r\n          that.$menuInner[0].scrollTop = that.selectpicker.view.scrollTop;\r\n        }\r\n\r\n        if (version.major > 3) {\r\n          requestAnimationFrame(checkPopperExists);\r\n        } else {\r\n          setFocus();\r\n        }\r\n      });\r\n\r\n      // ensure posinset and setsize are correct before selecting an option via a click\r\n      this.$menuInner.on('mouseenter', 'li a', function (e) {\r\n        var hoverLi = this.parentElement,\r\n            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,\r\n            index = Array.prototype.indexOf.call(hoverLi.parentElement.children, hoverLi),\r\n            hoverData = that.selectpicker.current.data[index + position0];\r\n\r\n        that.focusItem(hoverLi, hoverData, true);\r\n      });\r\n\r\n      this.$menuInner.on('click', 'li a', function (e, retainActive) {\r\n        var $this = $(this),\r\n            element = that.$element[0],\r\n            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,\r\n            clickedData = that.selectpicker.current.data[$this.parent().index() + position0],\r\n            clickedIndex = clickedData.index,\r\n            prevValue = getSelectValues(element),\r\n            prevIndex = element.selectedIndex,\r\n            prevOption = element.options[prevIndex],\r\n            triggerChange = true;\r\n\r\n        // Don't close on multi choice menu\r\n        if (that.multiple && that.options.maxOptions !== 1) {\r\n          e.stopPropagation();\r\n        }\r\n\r\n        e.preventDefault();\r\n\r\n        // Don't run if the select is disabled\r\n        if (!that.isDisabled() && !$this.parent().hasClass(classNames.DISABLED)) {\r\n          var option = clickedData.option,\r\n              $option = $(option),\r\n              state = option.selected,\r\n              $optgroup = $option.parent('optgroup'),\r\n              $optgroupOptions = $optgroup.find('option'),\r\n              maxOptions = that.options.maxOptions,\r\n              maxOptionsGrp = $optgroup.data('maxOptions') || false;\r\n\r\n          if (clickedIndex === that.activeIndex) retainActive = true;\r\n\r\n          if (!retainActive) {\r\n            that.prevActiveIndex = that.activeIndex;\r\n            that.activeIndex = undefined;\r\n          }\r\n\r\n          if (!that.multiple) { // Deselect all others if not multi select box\r\n            if (prevOption) prevOption.selected = false;\r\n            option.selected = true;\r\n            that.setSelected(clickedIndex, true);\r\n          } else { // Toggle the one we have chosen if we are multi select.\r\n            option.selected = !state;\r\n\r\n            that.setSelected(clickedIndex, !state);\r\n            that.focusedParent.focus();\r\n\r\n            if (maxOptions !== false || maxOptionsGrp !== false) {\r\n              var maxReached = maxOptions < getSelectedOptions(element).length,\r\n                  maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;\r\n\r\n              if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {\r\n                if (maxOptions && maxOptions == 1) {\r\n                  element.selectedIndex = -1;\r\n                  option.selected = true;\r\n                  that.setOptionStatus(true);\r\n                } else if (maxOptionsGrp && maxOptionsGrp == 1) {\r\n                  for (var i = 0; i < $optgroupOptions.length; i++) {\r\n                    var _option = $optgroupOptions[i];\r\n                    _option.selected = false;\r\n                    that.setSelected(_option.liIndex, false);\r\n                  }\r\n\r\n                  option.selected = true;\r\n                  that.setSelected(clickedIndex, true);\r\n                } else {\r\n                  var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,\r\n                      maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,\r\n                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),\r\n                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),\r\n                      $notify = $('<div class=\"notify\"></div>');\r\n                  // If {var} is set in array, replace it\r\n                  /** @deprecated */\r\n                  if (maxOptionsArr[2]) {\r\n                    maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);\r\n                    maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);\r\n                  }\r\n\r\n                  option.selected = false;\r\n\r\n                  that.$menu.append($notify);\r\n\r\n                  if (maxOptions && maxReached) {\r\n                    $notify.append($('<div>' + maxTxt + '</div>'));\r\n                    triggerChange = false;\r\n                    that.$element.trigger('maxReached' + EVENT_KEY);\r\n                  }\r\n\r\n                  if (maxOptionsGrp && maxReachedGrp) {\r\n                    $notify.append($('<div>' + maxTxtGrp + '</div>'));\r\n                    triggerChange = false;\r\n                    that.$element.trigger('maxReachedGrp' + EVENT_KEY);\r\n                  }\r\n\r\n                  setTimeout(function () {\r\n                    that.setSelected(clickedIndex, false);\r\n                  }, 10);\r\n\r\n                  $notify[0].classList.add('fadeOut');\r\n\r\n                  setTimeout(function () {\r\n                    $notify.remove();\r\n                  }, 1050);\r\n                }\r\n              }\r\n            }\r\n          }\r\n\r\n          if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {\r\n            that.$button.trigger('focus');\r\n          } else if (that.options.liveSearch) {\r\n            that.$searchbox.trigger('focus');\r\n          }\r\n\r\n          // Trigger select 'change'\r\n          if (triggerChange) {\r\n            if (that.multiple || prevIndex !== element.selectedIndex) {\r\n              // $option.prop('selected') is current option state (selected/unselected). prevValue is the value of the select prior to being changed.\r\n              changedArguments = [option.index, $option.prop('selected'), prevValue];\r\n              that.$element\r\n                .triggerNative('change');\r\n            }\r\n          }\r\n        }\r\n      });\r\n\r\n      this.$menu.on('click', 'li.' + classNames.DISABLED + ' a, .' + classNames.POPOVERHEADER + ', .' + classNames.POPOVERHEADER + ' :not(.close)', function (e) {\r\n        if (e.currentTarget == this) {\r\n          e.preventDefault();\r\n          e.stopPropagation();\r\n          if (that.options.liveSearch && !$(e.target).hasClass('close')) {\r\n            that.$searchbox.trigger('focus');\r\n          } else {\r\n            that.$button.trigger('focus');\r\n          }\r\n        }\r\n      });\r\n\r\n      this.$menuInner.on('click', '.divider, .dropdown-header', function (e) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        if (that.options.liveSearch) {\r\n          that.$searchbox.trigger('focus');\r\n        } else {\r\n          that.$button.trigger('focus');\r\n        }\r\n      });\r\n\r\n      this.$menu.on('click', '.' + classNames.POPOVERHEADER + ' .close', function () {\r\n        that.$button.trigger('click');\r\n      });\r\n\r\n      this.$searchbox.on('click', function (e) {\r\n        e.stopPropagation();\r\n      });\r\n\r\n      this.$menu.on('click', '.actions-btn', function (e) {\r\n        if (that.options.liveSearch) {\r\n          that.$searchbox.trigger('focus');\r\n        } else {\r\n          that.$button.trigger('focus');\r\n        }\r\n\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n\r\n        if ($(this).hasClass('bs-select-all')) {\r\n          that.selectAll();\r\n        } else {\r\n          that.deselectAll();\r\n        }\r\n      });\r\n\r\n      this.$button\r\n        .on('focus' + EVENT_KEY, function (e) {\r\n          var tabindex = that.$element[0].getAttribute('tabindex');\r\n\r\n          // only change when button is actually focused\r\n          if (tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {\r\n            // apply select element's tabindex to ensure correct order is followed when tabbing to the next element\r\n            this.setAttribute('tabindex', tabindex);\r\n            // set element's tabindex to -1 to allow for reverse tabbing\r\n            that.$element[0].setAttribute('tabindex', -1);\r\n            that.selectpicker.view.tabindex = tabindex;\r\n          }\r\n        })\r\n        .on('blur' + EVENT_KEY, function (e) {\r\n          // revert everything to original tabindex\r\n          if (that.selectpicker.view.tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {\r\n            that.$element[0].setAttribute('tabindex', that.selectpicker.view.tabindex);\r\n            this.setAttribute('tabindex', -1);\r\n            that.selectpicker.view.tabindex = undefined;\r\n          }\r\n        });\r\n\r\n      this.$element\r\n        .on('change' + EVENT_KEY, function () {\r\n          that.render();\r\n          that.$element.trigger('changed' + EVENT_KEY, changedArguments);\r\n          changedArguments = null;\r\n        })\r\n        .on('focus' + EVENT_KEY, function () {\r\n          if (!that.options.mobile) that.$button[0].focus();\r\n        });\r\n    },\r\n\r\n    liveSearchListener: function () {\r\n      var that = this;\r\n\r\n      this.$button.on('click.bs.dropdown.data-api', function () {\r\n        if (!!that.$searchbox.val()) {\r\n          that.$searchbox.val('');\r\n          that.selectpicker.search.previousValue = undefined;\r\n        }\r\n      });\r\n\r\n      this.$searchbox.on('click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api', function (e) {\r\n        e.stopPropagation();\r\n      });\r\n\r\n      this.$searchbox.on('input propertychange', function () {\r\n        var searchValue = that.$searchbox[0].value;\r\n\r\n        that.selectpicker.search.elements = [];\r\n        that.selectpicker.search.data = [];\r\n\r\n        if (searchValue) {\r\n          var i,\r\n              searchMatch = [],\r\n              q = searchValue.toUpperCase(),\r\n              cache = {},\r\n              cacheArr = [],\r\n              searchStyle = that._searchStyle(),\r\n              normalizeSearch = that.options.liveSearchNormalize;\r\n\r\n          if (normalizeSearch) q = normalizeToBase(q);\r\n\r\n          for (var i = 0; i < that.selectpicker.main.data.length; i++) {\r\n            var li = that.selectpicker.main.data[i];\r\n\r\n            if (!cache[i]) {\r\n              cache[i] = stringSearch(li, q, searchStyle, normalizeSearch);\r\n            }\r\n\r\n            if (cache[i] && li.headerIndex !== undefined && cacheArr.indexOf(li.headerIndex) === -1) {\r\n              if (li.headerIndex > 0) {\r\n                cache[li.headerIndex - 1] = true;\r\n                cacheArr.push(li.headerIndex - 1);\r\n              }\r\n\r\n              cache[li.headerIndex] = true;\r\n              cacheArr.push(li.headerIndex);\r\n\r\n              cache[li.lastIndex + 1] = true;\r\n            }\r\n\r\n            if (cache[i] && li.type !== 'optgroup-label') cacheArr.push(i);\r\n          }\r\n\r\n          for (var i = 0, cacheLen = cacheArr.length; i < cacheLen; i++) {\r\n            var index = cacheArr[i],\r\n                prevIndex = cacheArr[i - 1],\r\n                li = that.selectpicker.main.data[index],\r\n                liPrev = that.selectpicker.main.data[prevIndex];\r\n\r\n            if (li.type !== 'divider' || (li.type === 'divider' && liPrev && liPrev.type !== 'divider' && cacheLen - 1 !== i)) {\r\n              that.selectpicker.search.data.push(li);\r\n              searchMatch.push(that.selectpicker.main.elements[index]);\r\n            }\r\n          }\r\n\r\n          that.activeIndex = undefined;\r\n          that.noScroll = true;\r\n          that.$menuInner.scrollTop(0);\r\n          that.selectpicker.search.elements = searchMatch;\r\n          that.createView(true);\r\n          showNoResults.call(that, searchMatch, searchValue);\r\n        } else if (that.selectpicker.search.previousValue) { // for IE11 (#2402)\r\n          that.$menuInner.scrollTop(0);\r\n          that.createView(false);\r\n        }\r\n\r\n        that.selectpicker.search.previousValue =  searchValue;\r\n      });\r\n    },\r\n\r\n    _searchStyle: function () {\r\n      return this.options.liveSearchStyle || 'contains';\r\n    },\r\n\r\n    val: function (value) {\r\n      var element = this.$element[0];\r\n\r\n      if (typeof value !== 'undefined') {\r\n        var prevValue = getSelectValues(element);\r\n\r\n        changedArguments = [null, null, prevValue];\r\n\r\n        this.$element\r\n          .val(value)\r\n          .trigger('changed' + EVENT_KEY, changedArguments);\r\n\r\n        if (this.$newElement.hasClass(classNames.SHOW)) {\r\n          if (this.multiple) {\r\n            this.setOptionStatus(true);\r\n          } else {\r\n            var liSelectedIndex = (element.options[element.selectedIndex] || {}).liIndex;\r\n\r\n            if (typeof liSelectedIndex === 'number') {\r\n              this.setSelected(this.selectedIndex, false);\r\n              this.setSelected(liSelectedIndex, true);\r\n            }\r\n          }\r\n        }\r\n\r\n        this.render();\r\n\r\n        changedArguments = null;\r\n\r\n        return this.$element;\r\n      } else {\r\n        return this.$element.val();\r\n      }\r\n    },\r\n\r\n    changeAll: function (status) {\r\n      if (!this.multiple) return;\r\n      if (typeof status === 'undefined') status = true;\r\n\r\n      var element = this.$element[0],\r\n          previousSelected = 0,\r\n          currentSelected = 0,\r\n          prevValue = getSelectValues(element);\r\n\r\n      element.classList.add('bs-select-hidden');\r\n\r\n      for (var i = 0, data = this.selectpicker.current.data, len = data.length; i < len; i++) {\r\n        var liData = data[i],\r\n            option = liData.option;\r\n\r\n        if (option && !liData.disabled && liData.type !== 'divider') {\r\n          if (liData.selected) previousSelected++;\r\n          option.selected = status;\r\n          if (status === true) currentSelected++;\r\n        }\r\n      }\r\n\r\n      element.classList.remove('bs-select-hidden');\r\n\r\n      if (previousSelected === currentSelected) return;\r\n\r\n      this.setOptionStatus();\r\n\r\n      changedArguments = [null, null, prevValue];\r\n\r\n      this.$element\r\n        .triggerNative('change');\r\n    },\r\n\r\n    selectAll: function () {\r\n      return this.changeAll(true);\r\n    },\r\n\r\n    deselectAll: function () {\r\n      return this.changeAll(false);\r\n    },\r\n\r\n    toggle: function (e) {\r\n      e = e || window.event;\r\n\r\n      if (e) e.stopPropagation();\r\n\r\n      this.$button.trigger('click.bs.dropdown.data-api');\r\n    },\r\n\r\n    keydown: function (e) {\r\n      var $this = $(this),\r\n          isToggle = $this.hasClass('dropdown-toggle'),\r\n          $parent = isToggle ? $this.closest('.dropdown') : $this.closest(Selector.MENU),\r\n          that = $parent.data('this'),\r\n          $items = that.findLis(),\r\n          index,\r\n          isActive,\r\n          liActive,\r\n          activeLi,\r\n          offset,\r\n          updateScroll = false,\r\n          downOnTab = e.which === keyCodes.TAB && !isToggle && !that.options.selectOnTab,\r\n          isArrowKey = REGEXP_ARROW.test(e.which) || downOnTab,\r\n          scrollTop = that.$menuInner[0].scrollTop,\r\n          isVirtual = that.isVirtual(),\r\n          position0 = isVirtual === true ? that.selectpicker.view.position0 : 0;\r\n\r\n      // do nothing if a function key is pressed\r\n      if (e.which >= 112 && e.which <= 123) return;\r\n\r\n      isActive = that.$newElement.hasClass(classNames.SHOW);\r\n\r\n      if (\r\n        !isActive &&\r\n        (\r\n          isArrowKey ||\r\n          (e.which >= 48 && e.which <= 57) ||\r\n          (e.which >= 96 && e.which <= 105) ||\r\n          (e.which >= 65 && e.which <= 90)\r\n        )\r\n      ) {\r\n        that.$button.trigger('click.bs.dropdown.data-api');\r\n\r\n        if (that.options.liveSearch) {\r\n          that.$searchbox.trigger('focus');\r\n          return;\r\n        }\r\n      }\r\n\r\n      if (e.which === keyCodes.ESCAPE && isActive) {\r\n        e.preventDefault();\r\n        that.$button.trigger('click.bs.dropdown.data-api').trigger('focus');\r\n      }\r\n\r\n      if (isArrowKey) { // if up or down\r\n        if (!$items.length) return;\r\n\r\n        liActive = that.selectpicker.main.elements[that.activeIndex];\r\n        index = liActive ? Array.prototype.indexOf.call(liActive.parentElement.children, liActive) : -1;\r\n\r\n        if (index !== -1) {\r\n          that.defocusItem(liActive);\r\n        }\r\n\r\n        if (e.which === keyCodes.ARROW_UP) { // up\r\n          if (index !== -1) index--;\r\n          if (index + position0 < 0) index += $items.length;\r\n\r\n          if (!that.selectpicker.view.canHighlight[index + position0]) {\r\n            index = that.selectpicker.view.canHighlight.slice(0, index + position0).lastIndexOf(true) - position0;\r\n            if (index === -1) index = $items.length - 1;\r\n          }\r\n        } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down\r\n          index++;\r\n          if (index + position0 >= that.selectpicker.view.canHighlight.length) index = that.selectpicker.view.firstHighlightIndex;\r\n\r\n          if (!that.selectpicker.view.canHighlight[index + position0]) {\r\n            index = index + 1 + that.selectpicker.view.canHighlight.slice(index + position0 + 1).indexOf(true);\r\n          }\r\n        }\r\n\r\n        e.preventDefault();\r\n\r\n        var liActiveIndex = position0 + index;\r\n\r\n        if (e.which === keyCodes.ARROW_UP) { // up\r\n          // scroll to bottom and highlight last option\r\n          if (position0 === 0 && index === $items.length - 1) {\r\n            that.$menuInner[0].scrollTop = that.$menuInner[0].scrollHeight;\r\n\r\n            liActiveIndex = that.selectpicker.current.elements.length - 1;\r\n          } else {\r\n            activeLi = that.selectpicker.current.data[liActiveIndex];\r\n            offset = activeLi.position - activeLi.height;\r\n\r\n            updateScroll = offset < scrollTop;\r\n          }\r\n        } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down\r\n          // scroll to top and highlight first option\r\n          if (index === that.selectpicker.view.firstHighlightIndex) {\r\n            that.$menuInner[0].scrollTop = 0;\r\n\r\n            liActiveIndex = that.selectpicker.view.firstHighlightIndex;\r\n          } else {\r\n            activeLi = that.selectpicker.current.data[liActiveIndex];\r\n            offset = activeLi.position - that.sizeInfo.menuInnerHeight;\r\n\r\n            updateScroll = offset > scrollTop;\r\n          }\r\n        }\r\n\r\n        liActive = that.selectpicker.current.elements[liActiveIndex];\r\n\r\n        that.activeIndex = that.selectpicker.current.data[liActiveIndex].index;\r\n\r\n        that.focusItem(liActive);\r\n\r\n        that.selectpicker.view.currentActive = liActive;\r\n\r\n        if (updateScroll) that.$menuInner[0].scrollTop = offset;\r\n\r\n        if (that.options.liveSearch) {\r\n          that.$searchbox.trigger('focus');\r\n        } else {\r\n          $this.trigger('focus');\r\n        }\r\n      } else if (\r\n        (!$this.is('input') && !REGEXP_TAB_OR_ESCAPE.test(e.which)) ||\r\n        (e.which === keyCodes.SPACE && that.selectpicker.keydown.keyHistory)\r\n      ) {\r\n        var searchMatch,\r\n            matches = [],\r\n            keyHistory;\r\n\r\n        e.preventDefault();\r\n\r\n        that.selectpicker.keydown.keyHistory += keyCodeMap[e.which];\r\n\r\n        if (that.selectpicker.keydown.resetKeyHistory.cancel) clearTimeout(that.selectpicker.keydown.resetKeyHistory.cancel);\r\n        that.selectpicker.keydown.resetKeyHistory.cancel = that.selectpicker.keydown.resetKeyHistory.start();\r\n\r\n        keyHistory = that.selectpicker.keydown.keyHistory;\r\n\r\n        // if all letters are the same, set keyHistory to just the first character when searching\r\n        if (/^(.)\\1+$/.test(keyHistory)) {\r\n          keyHistory = keyHistory.charAt(0);\r\n        }\r\n\r\n        // find matches\r\n        for (var i = 0; i < that.selectpicker.current.data.length; i++) {\r\n          var li = that.selectpicker.current.data[i],\r\n              hasMatch;\r\n\r\n          hasMatch = stringSearch(li, keyHistory, 'startsWith', true);\r\n\r\n          if (hasMatch && that.selectpicker.view.canHighlight[i]) {\r\n            matches.push(li.index);\r\n          }\r\n        }\r\n\r\n        if (matches.length) {\r\n          var matchIndex = 0;\r\n\r\n          $items.removeClass('active').find('a').removeClass('active');\r\n\r\n          // either only one key has been pressed or they are all the same key\r\n          if (keyHistory.length === 1) {\r\n            matchIndex = matches.indexOf(that.activeIndex);\r\n\r\n            if (matchIndex === -1 || matchIndex === matches.length - 1) {\r\n              matchIndex = 0;\r\n            } else {\r\n              matchIndex++;\r\n            }\r\n          }\r\n\r\n          searchMatch = matches[matchIndex];\r\n\r\n          activeLi = that.selectpicker.main.data[searchMatch];\r\n\r\n          if (scrollTop - activeLi.position > 0) {\r\n            offset = activeLi.position - activeLi.height;\r\n            updateScroll = true;\r\n          } else {\r\n            offset = activeLi.position - that.sizeInfo.menuInnerHeight;\r\n            // if the option is already visible at the current scroll position, just keep it the same\r\n            updateScroll = activeLi.position > scrollTop + that.sizeInfo.menuInnerHeight;\r\n          }\r\n\r\n          liActive = that.selectpicker.main.elements[searchMatch];\r\n\r\n          that.activeIndex = matches[matchIndex];\r\n\r\n          that.focusItem(liActive);\r\n\r\n          if (liActive) liActive.firstChild.focus();\r\n\r\n          if (updateScroll) that.$menuInner[0].scrollTop = offset;\r\n\r\n          $this.trigger('focus');\r\n        }\r\n      }\r\n\r\n      // Select focused option if \"Enter\", \"Spacebar\" or \"Tab\" (when selectOnTab is true) are pressed inside the menu.\r\n      if (\r\n        isActive &&\r\n        (\r\n          (e.which === keyCodes.SPACE && !that.selectpicker.keydown.keyHistory) ||\r\n          e.which === keyCodes.ENTER ||\r\n          (e.which === keyCodes.TAB && that.options.selectOnTab)\r\n        )\r\n      ) {\r\n        if (e.which !== keyCodes.SPACE) e.preventDefault();\r\n\r\n        if (!that.options.liveSearch || e.which !== keyCodes.SPACE) {\r\n          that.$menuInner.find('.active a').trigger('click', true); // retain active class\r\n          $this.trigger('focus');\r\n\r\n          if (!that.options.liveSearch) {\r\n            // Prevent screen from scrolling if the user hits the spacebar\r\n            e.preventDefault();\r\n            // Fixes spacebar selection of dropdown items in FF & IE\r\n            $(document).data('spaceSelect', true);\r\n          }\r\n        }\r\n      }\r\n    },\r\n\r\n    mobile: function () {\r\n      // ensure mobile is set to true if mobile function is called after init\r\n      this.options.mobile = true;\r\n      this.$element[0].classList.add('mobile-device');\r\n    },\r\n\r\n    refresh: function () {\r\n      // update options if data attributes have been changed\r\n      var config = $.extend({}, this.options, this.$element.data());\r\n      this.options = config;\r\n\r\n      this.checkDisabled();\r\n      this.buildData();\r\n      this.setStyle();\r\n      this.render();\r\n      this.buildList();\r\n      this.setWidth();\r\n\r\n      this.setSize(true);\r\n\r\n      this.$element.trigger('refreshed' + EVENT_KEY);\r\n    },\r\n\r\n    hide: function () {\r\n      this.$newElement.hide();\r\n    },\r\n\r\n    show: function () {\r\n      this.$newElement.show();\r\n    },\r\n\r\n    remove: function () {\r\n      this.$newElement.remove();\r\n      this.$element.remove();\r\n    },\r\n\r\n    destroy: function () {\r\n      this.$newElement.before(this.$element).remove();\r\n\r\n      if (this.$bsContainer) {\r\n        this.$bsContainer.remove();\r\n      } else {\r\n        this.$menu.remove();\r\n      }\r\n\r\n      if (this.selectpicker.view.titleOption && this.selectpicker.view.titleOption.parentNode) {\r\n        this.selectpicker.view.titleOption.parentNode.removeChild(this.selectpicker.view.titleOption);\r\n      }\r\n\r\n      this.$element\r\n        .off(EVENT_KEY)\r\n        .removeData('selectpicker')\r\n        .removeClass('bs-select-hidden selectpicker');\r\n\r\n      $(window).off(EVENT_KEY + '.' + this.selectId);\r\n    }\r\n  };\r\n\r\n  // SELECTPICKER PLUGIN DEFINITION\r\n  // ==============================\r\n  function Plugin (option) {\r\n    // get the args of the outer function..\r\n    var args = arguments;\r\n    // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them\r\n    // to get lost/corrupted in android 2.3 and IE9 #715 #775\r\n    var _option = option;\r\n\r\n    [].shift.apply(args);\r\n\r\n    // if the version was not set successfully\r\n    if (!version.success) {\r\n      // try to retreive it again\r\n      try {\r\n        version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.');\r\n      } catch (err) {\r\n        // fall back to use BootstrapVersion if set\r\n        if (Selectpicker.BootstrapVersion) {\r\n          version.full = Selectpicker.BootstrapVersion.split(' ')[0].split('.');\r\n        } else {\r\n          version.full = [version.major, '0', '0'];\r\n\r\n          console.warn(\r\n            'There was an issue retrieving Bootstrap\\'s version. ' +\r\n            'Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. ' +\r\n            'If loading Bootstrap asynchronously, the version may need to be manually specified via $.fn.selectpicker.Constructor.BootstrapVersion.',\r\n            err\r\n          );\r\n        }\r\n      }\r\n\r\n      version.major = version.full[0];\r\n      version.success = true;\r\n    }\r\n\r\n    if (version.major === '4') {\r\n      // some defaults need to be changed if using Bootstrap 4\r\n      // check to see if they have already been manually changed before forcing them to update\r\n      var toUpdate = [];\r\n\r\n      if (Selectpicker.DEFAULTS.style === classNames.BUTTONCLASS) toUpdate.push({ name: 'style', className: 'BUTTONCLASS' });\r\n      if (Selectpicker.DEFAULTS.iconBase === classNames.ICONBASE) toUpdate.push({ name: 'iconBase', className: 'ICONBASE' });\r\n      if (Selectpicker.DEFAULTS.tickIcon === classNames.TICKICON) toUpdate.push({ name: 'tickIcon', className: 'TICKICON' });\r\n\r\n      classNames.DIVIDER = 'dropdown-divider';\r\n      classNames.SHOW = 'show';\r\n      classNames.BUTTONCLASS = 'btn-light';\r\n      classNames.POPOVERHEADER = 'popover-header';\r\n      classNames.ICONBASE = '';\r\n      classNames.TICKICON = 'bs-ok-default';\r\n\r\n      for (var i = 0; i < toUpdate.length; i++) {\r\n        var option = toUpdate[i];\r\n        Selectpicker.DEFAULTS[option.name] = classNames[option.className];\r\n      }\r\n    }\r\n\r\n    var value;\r\n    var chain = this.each(function () {\r\n      var $this = $(this);\r\n      if ($this.is('select')) {\r\n        var data = $this.data('selectpicker'),\r\n            options = typeof _option == 'object' && _option;\r\n\r\n        if (!data) {\r\n          var dataAttributes = $this.data();\r\n\r\n          for (var dataAttr in dataAttributes) {\r\n            if (Object.prototype.hasOwnProperty.call(dataAttributes, dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {\r\n              delete dataAttributes[dataAttr];\r\n            }\r\n          }\r\n\r\n          var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, dataAttributes, options);\r\n          config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), dataAttributes.template, options.template);\r\n          $this.data('selectpicker', (data = new Selectpicker(this, config)));\r\n        } else if (options) {\r\n          for (var i in options) {\r\n            if (Object.prototype.hasOwnProperty.call(options, i)) {\r\n              data.options[i] = options[i];\r\n            }\r\n          }\r\n        }\r\n\r\n        if (typeof _option == 'string') {\r\n          if (data[_option] instanceof Function) {\r\n            value = data[_option].apply(data, args);\r\n          } else {\r\n            value = data.options[_option];\r\n          }\r\n        }\r\n      }\r\n    });\r\n\r\n    if (typeof value !== 'undefined') {\r\n      // noinspection JSUnusedAssignment\r\n      return value;\r\n    } else {\r\n      return chain;\r\n    }\r\n  }\r\n\r\n  var old = $.fn.selectpicker;\r\n  $.fn.selectpicker = Plugin;\r\n  $.fn.selectpicker.Constructor = Selectpicker;\r\n\r\n  // SELECTPICKER NO CONFLICT\r\n  // ========================\r\n  $.fn.selectpicker.noConflict = function () {\r\n    $.fn.selectpicker = old;\r\n    return this;\r\n  };\r\n\r\n  // get Bootstrap's keydown event handler for either Bootstrap 4 or Bootstrap 3\r\n  function keydownHandler () {\r\n    if ($.fn.dropdown) {\r\n      // wait to define until function is called in case Bootstrap isn't loaded yet\r\n      var bootstrapKeydown = $.fn.dropdown.Constructor._dataApiKeydownHandler || $.fn.dropdown.Constructor.prototype.keydown;\r\n      return bootstrapKeydown.apply(this, arguments);\r\n    }\r\n  }\r\n\r\n  $(document)\r\n    .off('keydown.bs.dropdown.data-api')\r\n    .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > [data-toggle=\"dropdown\"]', keydownHandler)\r\n    .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > .dropdown-menu', keydownHandler)\r\n    .on('keydown' + EVENT_KEY, '.bootstrap-select [data-toggle=\"dropdown\"], .bootstrap-select [role=\"listbox\"], .bootstrap-select .bs-searchbox input', Selectpicker.prototype.keydown)\r\n    .on('focusin.modal', '.bootstrap-select [data-toggle=\"dropdown\"], .bootstrap-select [role=\"listbox\"], .bootstrap-select .bs-searchbox input', function (e) {\r\n      e.stopPropagation();\r\n    });\r\n\r\n  // SELECTPICKER DATA-API\r\n  // =====================\r\n  $(window).on('load' + EVENT_KEY + '.data-api', function () {\r\n    $('.selectpicker').each(function () {\r\n      var $selectpicker = $(this);\r\n      Plugin.call($selectpicker, $selectpicker.data());\r\n    })\r\n  });\r\n})(jQuery);\r\n\r\n\r\n}));\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/auto-refresh/bootstrap-table-auto-refresh.js",
    "content": "/**\r\n * @author: Alec Fenichel\r\n * @webSite: https://fenichelar.com\r\n * @update: zhixin wen <wenzhixin2010@gmail.com>\r\n */\r\n\r\nvar Utils = $.fn.bootstrapTable.utils\r\n\r\nObject.assign($.fn.bootstrapTable.defaults, {\r\n  autoRefresh: false,\r\n  showAutoRefresh: true,\r\n  autoRefreshInterval: 60,\r\n  autoRefreshSilent: true,\r\n  autoRefreshStatus: true,\r\n  autoRefreshFunction: null\r\n})\r\n\r\nUtils.assignIcons($.fn.bootstrapTable.icons, 'autoRefresh', {\r\n  glyphicon: 'glyphicon-time icon-time',\r\n  fa: 'fa-clock',\r\n  bi: 'bi-clock',\r\n  icon: 'icon-clock',\r\n  'material-icons': 'access_time'\r\n})\r\n\r\nObject.assign($.fn.bootstrapTable.locales, {\r\n  formatAutoRefresh () {\r\n    return 'Auto Refresh'\r\n  }\r\n})\r\n\r\nObject.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)\r\n\r\n$.BootstrapTable = class extends $.BootstrapTable {\r\n  init (...args) {\r\n    super.init(...args)\r\n\r\n    if (this.options.autoRefresh && this.options.autoRefreshStatus) {\r\n      this.setupRefreshInterval()\r\n    }\r\n  }\r\n\r\n  initToolbar (...args) {\r\n    if (this.options.autoRefresh) {\r\n      this.buttons = Object.assign(this.buttons, {\r\n        autoRefresh: {\r\n          text: this.options.formatAutoRefresh(),\r\n          icon: this.options.icons.autoRefresh,\r\n          render: false,\r\n          event: this.toggleAutoRefresh,\r\n          attributes: {\r\n            'aria-label': this.options.formatAutoRefresh(),\r\n            title: this.options.formatAutoRefresh()\r\n          }\r\n        }\r\n      })\r\n    }\r\n\r\n    super.initToolbar(...args)\r\n  }\r\n\r\n  toggleAutoRefresh () {\r\n    if (this.options.autoRefresh) {\r\n      if (this.options.autoRefreshStatus) {\r\n        clearInterval(this.options.autoRefreshFunction)\r\n        this.$toolbar.find('>.columns .auto-refresh')\r\n          .removeClass(this.constants.classes.buttonActive)\r\n      } else {\r\n        this.setupRefreshInterval()\r\n        this.$toolbar.find('>.columns .auto-refresh')\r\n          .addClass(this.constants.classes.buttonActive)\r\n      }\r\n      this.options.autoRefreshStatus = !this.options.autoRefreshStatus\r\n    }\r\n  }\r\n\r\n  destroy () {\r\n    if (this.options.autoRefresh && this.options.autoRefreshStatus) {\r\n      clearInterval(this.options.autoRefreshFunction)\r\n    }\r\n\r\n    super.destroy()\r\n  }\r\n\r\n  setupRefreshInterval () {\r\n    this.options.autoRefreshFunction = setInterval(() => {\r\n      if (!this.options.autoRefresh || !this.options.autoRefreshStatus) {\r\n        return\r\n      }\r\n      this.refresh({ silent: this.options.autoRefreshSilent })\r\n    }, this.options.autoRefreshInterval * 1000)\r\n  }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/columns/bootstrap-table-fixed-columns.js",
    "content": "/**\n * @author zhixin wen <wenzhixin2010@gmail.com>\n * @github: bootstrap-table/dist/extensions/fixed-columns/bootstrap-table-fixed-columns.min.js\n */\n!function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?e(require(\"jquery\")):\"function\"==typeof define&&define.amd?define([\"jquery\"],e):e((t=\"undefined\"!=typeof globalThis?globalThis:t||self).jQuery)}(this,(function(t){\"use strict\";function e(t,e,n){return e=i(e),function(t,e){if(e&&(\"object\"==typeof e||\"function\"==typeof e))return e;if(void 0!==e)throw new TypeError(\"Derived constructors may only return object or undefined\");return function(t){if(void 0===t)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return t}(t)}(t,o()?Reflect.construct(e,n||[],i(t).constructor):e.apply(t,n))}function n(t,e,n){return function(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(t,c(r.key),r)}}(t.prototype,e),Object.defineProperty(t,\"prototype\",{writable:!1}),t}function r(){return r=\"undefined\"!=typeof Reflect&&Reflect.get?Reflect.get.bind():function(t,e,n){var r=function(t,e){for(;!{}.hasOwnProperty.call(t,e)&&null!==(t=i(t)););return t}(t,e);if(r){var o=Object.getOwnPropertyDescriptor(r,e);return o.get?o.get.call(arguments.length<3?t:n):o.value}},r.apply(null,arguments)}function i(t){return i=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},i(t)}function o(){try{var t=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(t){}return(o=function(){return!!t})()}function u(t,e){return u=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},u(t,e)}function f(t,e,n,o){var u=r(i(t.prototype),e,n);return\"function\"==typeof u?function(t){return u.apply(n,t)}:u}function c(t){var e=function(t,e){if(\"object\"!=typeof t||!t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var r=n.call(t,e);if(\"object\"!=typeof r)return r;throw new TypeError(\"@@toPrimitive must return a primitive value.\")}return String(t)}(t,\"string\");return\"symbol\"==typeof e?e:e+\"\"}var a,s,l=\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:{},d={};function h(){if(s)return a;s=1;var t=function(t){return t&&t.Math===Math&&t};return a=t(\"object\"==typeof globalThis&&globalThis)||t(\"object\"==typeof window&&window)||t(\"object\"==typeof self&&self)||t(\"object\"==typeof l&&l)||t(\"object\"==typeof a&&a)||function(){return this}()||Function(\"return this\")()}var p,v,y,b,g,m,x,w,$={};function O(){return v?p:(v=1,p=function(t){try{return!!t()}catch(t){return!0}})}function C(){if(b)return y;b=1;var t=O();return y=!t((function(){return 7!==Object.defineProperty({},1,{get:function(){return 7}})[1]}))}function j(){if(m)return g;m=1;var t=O();return g=!t((function(){var t=function(){}.bind();return\"function\"!=typeof t||t.hasOwnProperty(\"prototype\")}))}function S(){if(w)return x;w=1;var t=j(),e=Function.prototype.call;return x=t?e.bind(e):function(){return e.apply(e,arguments)},x}var R,B,F,T,k,P,E,A,N,H,I,L,W,D,M,_,z,X,Y,q,G,V,U,K,Q,Z,J,tt,et,nt,rt,it,ot,ut,ft,ct,at,st,lt,dt,ht,pt={};function vt(){if(R)return pt;R=1;var t={}.propertyIsEnumerable,e=Object.getOwnPropertyDescriptor,n=e&&!t.call({1:2},1);return pt.f=n?function(t){var n=e(this,t);return!!n&&n.enumerable}:t,pt}function yt(){return F?B:(F=1,B=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}})}function bt(){if(k)return T;k=1;var t=j(),e=Function.prototype,n=e.call,r=t&&e.bind.bind(n,n);return T=t?r:function(t){return function(){return n.apply(t,arguments)}},T}function gt(){if(E)return P;E=1;var t=bt(),e=t({}.toString),n=t(\"\".slice);return P=function(t){return n(e(t),8,-1)}}function mt(){if(N)return A;N=1;var t=bt(),e=O(),n=gt(),r=Object,i=t(\"\".split);return A=e((function(){return!r(\"z\").propertyIsEnumerable(0)}))?function(t){return\"String\"===n(t)?i(t,\"\"):r(t)}:r}function xt(){return I?H:(I=1,H=function(t){return null==t})}function wt(){if(W)return L;W=1;var t=xt(),e=TypeError;return L=function(n){if(t(n))throw new e(\"Can't call method on \"+n);return n}}function $t(){if(M)return D;M=1;var t=mt(),e=wt();return D=function(n){return t(e(n))}}function Ot(){if(z)return _;z=1;var t=\"object\"==typeof document&&document.all;return _=void 0===t&&void 0!==t?function(e){return\"function\"==typeof e||e===t}:function(t){return\"function\"==typeof t}}function Ct(){if(Y)return X;Y=1;var t=Ot();return X=function(e){return\"object\"==typeof e?null!==e:t(e)}}function jt(){if(G)return q;G=1;var t=h(),e=Ot();return q=function(n,r){return arguments.length<2?(i=t[n],e(i)?i:void 0):t[n]&&t[n][r];var i},q}function St(){if(J)return Z;J=1;var t,e,n=h(),r=function(){if(Q)return K;Q=1;var t=h().navigator,e=t&&t.userAgent;return K=e?String(e):\"\"}(),i=n.process,o=n.Deno,u=i&&i.versions||o&&o.version,f=u&&u.v8;return f&&(e=(t=f.split(\".\"))[0]>0&&t[0]<4?1:+(t[0]+t[1])),!e&&r&&(!(t=r.match(/Edge\\/(\\d+)/))||t[1]>=74)&&(t=r.match(/Chrome\\/(\\d+)/))&&(e=+t[1]),Z=e}function Rt(){if(et)return tt;et=1;var t=St(),e=O(),n=h().String;return tt=!!Object.getOwnPropertySymbols&&!e((function(){var e=Symbol(\"symbol detection\");return!n(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&t&&t<41}))}function Bt(){if(rt)return nt;rt=1;var t=Rt();return nt=t&&!Symbol.sham&&\"symbol\"==typeof Symbol.iterator}function Ft(){if(ot)return it;ot=1;var t=jt(),e=Ot(),n=function(){if(U)return V;U=1;var t=bt();return V=t({}.isPrototypeOf)}(),r=Bt(),i=Object;return it=r?function(t){return\"symbol\"==typeof t}:function(r){var o=t(\"Symbol\");return e(o)&&n(o.prototype,i(r))}}function Tt(){if(ft)return ut;ft=1;var t=String;return ut=function(e){try{return t(e)}catch(t){return\"Object\"}}}function kt(){if(at)return ct;at=1;var t=Ot(),e=Tt(),n=TypeError;return ct=function(r){if(t(r))return r;throw new n(e(r)+\" is not a function\")}}function Pt(){if(lt)return st;lt=1;var t=kt(),e=xt();return st=function(n,r){var i=n[r];return e(i)?void 0:t(i)}}function Et(){if(ht)return dt;ht=1;var t=S(),e=Ot(),n=Ct(),r=TypeError;return dt=function(i,o){var u,f;if(\"string\"===o&&e(u=i.toString)&&!n(f=t(u,i)))return f;if(e(u=i.valueOf)&&!n(f=t(u,i)))return f;if(\"string\"!==o&&e(u=i.toString)&&!n(f=t(u,i)))return f;throw new r(\"Can't convert object to primitive value\")}}var At,Nt,Ht,It,Lt,Wt,Dt,Mt,_t,zt,Xt,Yt,qt,Gt,Vt,Ut,Kt,Qt,Zt,Jt,te,ee,ne,re,ie={exports:{}};function oe(){if(It)return Ht;It=1;var t=h(),e=Object.defineProperty;return Ht=function(n,r){try{e(t,n,{value:r,configurable:!0,writable:!0})}catch(e){t[n]=r}return r}}function ue(){if(Lt)return ie.exports;Lt=1;var t=Nt?At:(Nt=1,At=!1),e=h(),n=oe(),r=\"__core-js_shared__\",i=ie.exports=e[r]||n(r,{});return(i.versions||(i.versions=[])).push({version:\"3.39.0\",mode:t?\"pure\":\"global\",copyright:\"© 2014-2024 Denis Pushkarev (zloirock.ru)\",license:\"https://github.com/zloirock/core-js/blob/v3.39.0/LICENSE\",source:\"https://github.com/zloirock/core-js\"}),ie.exports}function fe(){if(Dt)return Wt;Dt=1;var t=ue();return Wt=function(e,n){return t[e]||(t[e]=n||{})}}function ce(){if(_t)return Mt;_t=1;var t=wt(),e=Object;return Mt=function(n){return e(t(n))}}function ae(){if(Xt)return zt;Xt=1;var t=bt(),e=ce(),n=t({}.hasOwnProperty);return zt=Object.hasOwn||function(t,r){return n(e(t),r)}}function se(){if(qt)return Yt;qt=1;var t=bt(),e=0,n=Math.random(),r=t(1..toString);return Yt=function(t){return\"Symbol(\"+(void 0===t?\"\":t)+\")_\"+r(++e+n,36)}}function le(){if(Vt)return Gt;Vt=1;var t=h(),e=fe(),n=ae(),r=se(),i=Rt(),o=Bt(),u=t.Symbol,f=e(\"wks\"),c=o?u.for||u:u&&u.withoutSetter||r;return Gt=function(t){return n(f,t)||(f[t]=i&&n(u,t)?u[t]:c(\"Symbol.\"+t)),f[t]}}function de(){if(Kt)return Ut;Kt=1;var t=S(),e=Ct(),n=Ft(),r=Pt(),i=Et(),o=le(),u=TypeError,f=o(\"toPrimitive\");return Ut=function(o,c){if(!e(o)||n(o))return o;var a,s=r(o,f);if(s){if(void 0===c&&(c=\"default\"),a=t(s,o,c),!e(a)||n(a))return a;throw new u(\"Can't convert object to primitive value\")}return void 0===c&&(c=\"number\"),i(o,c)}}function he(){if(Zt)return Qt;Zt=1;var t=de(),e=Ft();return Qt=function(n){var r=t(n,\"string\");return e(r)?r:r+\"\"}}function pe(){if(te)return Jt;te=1;var t=h(),e=Ct(),n=t.document,r=e(n)&&e(n.createElement);return Jt=function(t){return r?n.createElement(t):{}}}function ve(){if(ne)return ee;ne=1;var t=C(),e=O(),n=pe();return ee=!t&&!e((function(){return 7!==Object.defineProperty(n(\"div\"),\"a\",{get:function(){return 7}}).a}))}function ye(){if(re)return $;re=1;var t=C(),e=S(),n=vt(),r=yt(),i=$t(),o=he(),u=ae(),f=ve(),c=Object.getOwnPropertyDescriptor;return $.f=t?c:function(t,a){if(t=i(t),a=o(a),f)try{return c(t,a)}catch(t){}if(u(t,a))return r(!e(n.f,t,a),t[a])},$}var be,ge,me,xe,we,$e,Oe,Ce={};function je(){if(ge)return be;ge=1;var t=C(),e=O();return be=t&&e((function(){return 42!==Object.defineProperty((function(){}),\"prototype\",{value:42,writable:!1}).prototype}))}function Se(){if(xe)return me;xe=1;var t=Ct(),e=String,n=TypeError;return me=function(r){if(t(r))return r;throw new n(e(r)+\" is not an object\")}}function Re(){if(we)return Ce;we=1;var t=C(),e=ve(),n=je(),r=Se(),i=he(),o=TypeError,u=Object.defineProperty,f=Object.getOwnPropertyDescriptor,c=\"enumerable\",a=\"configurable\",s=\"writable\";return Ce.f=t?n?function(t,e,n){if(r(t),e=i(e),r(n),\"function\"==typeof t&&\"prototype\"===e&&\"value\"in n&&s in n&&!n[s]){var o=f(t,e);o&&o[s]&&(t[e]=n.value,n={configurable:a in n?n[a]:o[a],enumerable:c in n?n[c]:o[c],writable:!1})}return u(t,e,n)}:u:function(t,n,f){if(r(t),n=i(n),r(f),e)try{return u(t,n,f)}catch(t){}if(\"get\"in f||\"set\"in f)throw new o(\"Accessors not supported\");return\"value\"in f&&(t[n]=f.value),t},Ce}function Be(){if(Oe)return $e;Oe=1;var t=C(),e=Re(),n=yt();return $e=t?function(t,r,i){return e.f(t,r,n(1,i))}:function(t,e,n){return t[e]=n,t}}var Fe,Te,ke,Pe,Ee,Ae,Ne,He,Ie,Le,We,De,Me,_e,ze,Xe={exports:{}};function Ye(){if(Pe)return ke;Pe=1;var t=bt(),e=Ot(),n=ue(),r=t(Function.toString);return e(n.inspectSource)||(n.inspectSource=function(t){return r(t)}),ke=n.inspectSource}function qe(){if(He)return Ne;He=1;var t=fe(),e=se(),n=t(\"keys\");return Ne=function(t){return n[t]||(n[t]=e(t))}}function Ge(){return Le?Ie:(Le=1,Ie={})}function Ve(){if(De)return We;De=1;var t,e,n,r=function(){if(Ae)return Ee;Ae=1;var t=h(),e=Ot(),n=t.WeakMap;return Ee=e(n)&&/native code/.test(String(n))}(),i=h(),o=Ct(),u=Be(),f=ae(),c=ue(),a=qe(),s=Ge(),l=\"Object already initialized\",d=i.TypeError,p=i.WeakMap;if(r||c.state){var v=c.state||(c.state=new p);v.get=v.get,v.has=v.has,v.set=v.set,t=function(t,e){if(v.has(t))throw new d(l);return e.facade=t,v.set(t,e),e},e=function(t){return v.get(t)||{}},n=function(t){return v.has(t)}}else{var y=a(\"state\");s[y]=!0,t=function(t,e){if(f(t,y))throw new d(l);return e.facade=t,u(t,y,e),e},e=function(t){return f(t,y)?t[y]:{}},n=function(t){return f(t,y)}}return We={set:t,get:e,has:n,enforce:function(r){return n(r)?e(r):t(r,{})},getterFor:function(t){return function(n){var r;if(!o(n)||(r=e(n)).type!==t)throw new d(\"Incompatible receiver, \"+t+\" required\");return r}}}}function Ue(){if(Me)return Xe.exports;Me=1;var t=bt(),e=O(),n=Ot(),r=ae(),i=C(),o=function(){if(Te)return Fe;Te=1;var t=C(),e=ae(),n=Function.prototype,r=t&&Object.getOwnPropertyDescriptor,i=e(n,\"name\"),o=i&&\"something\"===function(){}.name,u=i&&(!t||t&&r(n,\"name\").configurable);return Fe={EXISTS:i,PROPER:o,CONFIGURABLE:u}}().CONFIGURABLE,u=Ye(),f=Ve(),c=f.enforce,a=f.get,s=String,l=Object.defineProperty,d=t(\"\".slice),h=t(\"\".replace),p=t([].join),v=i&&!e((function(){return 8!==l((function(){}),\"length\",{value:8}).length})),y=String(String).split(\"String\"),b=Xe.exports=function(t,e,n){\"Symbol(\"===d(s(e),0,7)&&(e=\"[\"+h(s(e),/^Symbol\\(([^)]*)\\).*$/,\"$1\")+\"]\"),n&&n.getter&&(e=\"get \"+e),n&&n.setter&&(e=\"set \"+e),(!r(t,\"name\")||o&&t.name!==e)&&(i?l(t,\"name\",{value:e,configurable:!0}):t.name=e),v&&n&&r(n,\"arity\")&&t.length!==n.arity&&l(t,\"length\",{value:n.arity});try{n&&r(n,\"constructor\")&&n.constructor?i&&l(t,\"prototype\",{writable:!1}):t.prototype&&(t.prototype=void 0)}catch(t){}var u=c(t);return r(u,\"source\")||(u.source=p(y,\"string\"==typeof e?e:\"\")),t};return Function.prototype.toString=b((function(){return n(this)&&a(this).source||u(this)}),\"toString\"),Xe.exports}function Ke(){if(ze)return _e;ze=1;var t=Ot(),e=Re(),n=Ue(),r=oe();return _e=function(i,o,u,f){f||(f={});var c=f.enumerable,a=void 0!==f.name?f.name:o;if(t(u)&&n(u,a,f),f.global)c?i[o]=u:r(o,u);else{try{f.unsafe?i[o]&&(c=!0):delete i[o]}catch(t){}c?i[o]=u:e.f(i,o,{value:u,enumerable:!1,configurable:!f.nonConfigurable,writable:!f.nonWritable})}return i}}var Qe,Ze,Je,tn,en,nn,rn,on,un,fn,cn,an,sn,ln,dn,hn,pn,vn={};function yn(){if(tn)return Je;tn=1;var t=function(){if(Ze)return Qe;Ze=1;var t=Math.ceil,e=Math.floor;return Qe=Math.trunc||function(n){var r=+n;return(r>0?e:t)(r)}}();return Je=function(e){var n=+e;return n!=n||0===n?0:t(n)}}function bn(){if(nn)return en;nn=1;var t=yn(),e=Math.max,n=Math.min;return en=function(r,i){var o=t(r);return o<0?e(o+i,0):n(o,i)}}function gn(){if(on)return rn;on=1;var t=yn(),e=Math.min;return rn=function(n){var r=t(n);return r>0?e(r,9007199254740991):0}}function mn(){if(fn)return un;fn=1;var t=gn();return un=function(e){return t(e.length)}}function xn(){if(an)return cn;an=1;var t=$t(),e=bn(),n=mn(),r=function(r){return function(i,o,u){var f=t(i),c=n(f);if(0===c)return!r&&-1;var a,s=e(u,c);if(r&&o!=o){for(;c>s;)if((a=f[s++])!=a)return!0}else for(;c>s;s++)if((r||s in f)&&f[s]===o)return r||s||0;return!r&&-1}};return cn={includes:r(!0),indexOf:r(!1)}}function wn(){if(ln)return sn;ln=1;var t=bt(),e=ae(),n=$t(),r=xn().indexOf,i=Ge(),o=t([].push);return sn=function(t,u){var f,c=n(t),a=0,s=[];for(f in c)!e(i,f)&&e(c,f)&&o(s,f);for(;u.length>a;)e(c,f=u[a++])&&(~r(s,f)||o(s,f));return s}}function $n(){return hn?dn:(hn=1,dn=[\"constructor\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"toLocaleString\",\"toString\",\"valueOf\"])}var On,Cn,jn,Sn,Rn,Bn,Fn,Tn,kn,Pn,En,An,Nn,Hn,In,Ln,Wn,Dn,Mn,_n,zn,Xn,Yn,qn,Gn,Vn,Un,Kn={};function Qn(){return On||(On=1,Kn.f=Object.getOwnPropertySymbols),Kn}function Zn(){if(jn)return Cn;jn=1;var t=jt(),e=bt(),n=function(){if(pn)return vn;pn=1;var t=wn(),e=$n().concat(\"length\",\"prototype\");return vn.f=Object.getOwnPropertyNames||function(n){return t(n,e)},vn}(),r=Qn(),i=Se(),o=e([].concat);return Cn=t(\"Reflect\",\"ownKeys\")||function(t){var e=n.f(i(t)),u=r.f;return u?o(e,u(t)):e}}function Jn(){if(Rn)return Sn;Rn=1;var t=ae(),e=Zn(),n=ye(),r=Re();return Sn=function(i,o,u){for(var f=e(o),c=r.f,a=n.f,s=0;s<f.length;s++){var l=f[s];t(i,l)||u&&t(u,l)||c(i,l,a(o,l))}}}function tr(){if(kn)return Tn;kn=1;var t=h(),e=ye().f,n=Be(),r=Ke(),i=oe(),o=Jn(),u=function(){if(Fn)return Bn;Fn=1;var t=O(),e=Ot(),n=/#|\\.prototype\\./,r=function(n,r){var c=o[i(n)];return c===f||c!==u&&(e(r)?t(r):!!r)},i=r.normalize=function(t){return String(t).replace(n,\".\").toLowerCase()},o=r.data={},u=r.NATIVE=\"N\",f=r.POLYFILL=\"P\";return Bn=r}();return Tn=function(f,c){var a,s,l,d,h,p=f.target,v=f.global,y=f.stat;if(a=v?t:y?t[p]||i(p,{}):t[p]&&t[p].prototype)for(s in c){if(d=c[s],l=f.dontCallGetSet?(h=e(a,s))&&h.value:a[s],!u(v?s:p+(y?\".\":\"#\")+s,f.forced)&&void 0!==l){if(typeof d==typeof l)continue;o(d,l)}(f.sham||l&&l.sham)&&n(d,\"sham\",!0),r(a,s,d,f)}}}function er(){if(En)return Pn;En=1;var t=gt(),e=bt();return Pn=function(n){if(\"Function\"===t(n))return e(n)}}function nr(){if(In)return Hn;In=1;var t=gt();return Hn=Array.isArray||function(e){return\"Array\"===t(e)}}function rr(){if(Wn)return Ln;Wn=1;var t={};return t[le()(\"toStringTag\")]=\"z\",Ln=\"[object z]\"===String(t)}function ir(){if(Mn)return Dn;Mn=1;var t=rr(),e=Ot(),n=gt(),r=le()(\"toStringTag\"),i=Object,o=\"Arguments\"===n(function(){return arguments}());return Dn=t?n:function(t){var u,f,c;return void 0===t?\"Undefined\":null===t?\"Null\":\"string\"==typeof(f=function(t,e){try{return t[e]}catch(t){}}(u=i(t),r))?f:o?n(u):\"Object\"===(c=n(u))&&e(u.callee)?\"Arguments\":c}}function or(){if(zn)return _n;zn=1;var t=bt(),e=O(),n=Ot(),r=ir(),i=jt(),o=Ye(),u=function(){},f=i(\"Reflect\",\"construct\"),c=/^\\s*(?:class|function)\\b/,a=t(c.exec),s=!c.test(u),l=function(t){if(!n(t))return!1;try{return f(u,[],t),!0}catch(t){return!1}},d=function(t){if(!n(t))return!1;switch(r(t)){case\"AsyncFunction\":case\"GeneratorFunction\":case\"AsyncGeneratorFunction\":return!1}try{return s||!!a(c,o(t))}catch(t){return!0}};return d.sham=!0,_n=!f||e((function(){var t;return l(l.call)||!l(Object)||!l((function(){t=!0}))||t}))?d:l}function ur(){if(Yn)return Xn;Yn=1;var t=nr(),e=or(),n=Ct(),r=le()(\"species\"),i=Array;return Xn=function(o){var u;return t(o)&&(u=o.constructor,(e(u)&&(u===i||t(u.prototype))||n(u)&&null===(u=u[r]))&&(u=void 0)),void 0===u?i:u}}function fr(){if(Gn)return qn;Gn=1;var t=ur();return qn=function(e,n){return new(t(e))(0===n?0:n)}}function cr(){if(Un)return Vn;Un=1;var t=function(){if(Nn)return An;Nn=1;var t=er(),e=kt(),n=j(),r=t(t.bind);return An=function(t,i){return e(t),void 0===i?t:n?r(t,i):function(){return t.apply(i,arguments)}},An}(),e=bt(),n=mt(),r=ce(),i=mn(),o=fr(),u=e([].push),f=function(e){var f=1===e,c=2===e,a=3===e,s=4===e,l=6===e,d=7===e,h=5===e||l;return function(p,v,y,b){for(var g,m,x=r(p),w=n(x),$=i(w),O=t(v,y),C=0,j=b||o,S=f?j(p,$):c||d?j(p,0):void 0;$>C;C++)if((h||C in w)&&(m=O(g=w[C],C,x),e))if(f)S[C]=m;else if(m)switch(e){case 3:return!0;case 5:return g;case 6:return C;case 2:u(S,g)}else switch(e){case 4:return!1;case 7:u(S,g)}return l?-1:a||s?s:S}};return Vn={forEach:f(0),map:f(1),filter:f(2),some:f(3),every:f(4),find:f(5),findIndex:f(6),filterReject:f(7)}}var ar,sr,lr,dr,hr,pr,vr,yr,br,gr,mr={};function xr(){if(sr)return ar;sr=1;var t=wn(),e=$n();return ar=Object.keys||function(n){return t(n,e)}}function wr(){if(hr)return dr;hr=1;var t=jt();return dr=t(\"document\",\"documentElement\")}function $r(){if(vr)return pr;vr=1;var t,e=Se(),n=function(){if(lr)return mr;lr=1;var t=C(),e=je(),n=Re(),r=Se(),i=$t(),o=xr();return mr.f=t&&!e?Object.defineProperties:function(t,e){r(t);for(var u,f=i(e),c=o(e),a=c.length,s=0;a>s;)n.f(t,u=c[s++],f[u]);return t},mr}(),r=$n(),i=Ge(),o=wr(),u=pe(),f=qe(),c=\"prototype\",a=\"script\",s=f(\"IE_PROTO\"),l=function(){},d=function(t){return\"<\"+a+\">\"+t+\"</\"+a+\">\"},h=function(t){t.write(d(\"\")),t.close();var e=t.parentWindow.Object;return t=null,e},p=function(){try{t=new ActiveXObject(\"htmlfile\")}catch(t){}var e,n,i;p=\"undefined\"!=typeof document?document.domain&&t?h(t):(n=u(\"iframe\"),i=\"java\"+a+\":\",n.style.display=\"none\",o.appendChild(n),n.src=String(i),(e=n.contentWindow.document).open(),e.write(d(\"document.F=Object\")),e.close(),e.F):h(t);for(var f=r.length;f--;)delete p[c][r[f]];return p()};return i[s]=!0,pr=Object.create||function(t,r){var i;return null!==t?(l[c]=e(t),i=new l,l[c]=null,i[s]=t):i=p(),void 0===r?i:n.f(i,r)}}function Or(){if(br)return yr;br=1;var t=le(),e=$r(),n=Re().f,r=t(\"unscopables\"),i=Array.prototype;return void 0===i[r]&&n(i,r,{configurable:!0,value:e(null)}),yr=function(t){i[r][t]=!0}}!function(){if(gr)return d;gr=1;var t=tr(),e=cr().find,n=Or(),r=\"find\",i=!0;r in[]&&Array(1)[r]((function(){i=!1})),t({target:\"Array\",proto:!0,forced:i},{find:function(t){return e(this,t,arguments.length>1?arguments[1]:void 0)}}),n(r)}();var Cr,jr,Sr,Rr={};function Br(){if(jr)return Cr;jr=1;var t=O();return Cr=function(e,n){var r=[][e];return!!r&&t((function(){r.call(null,n||function(){return 1},1)}))}}!function(){if(Sr)return Rr;Sr=1;var t=tr(),e=er(),n=xn().indexOf,r=Br(),i=e([].indexOf),o=!!i&&1/i([1],1,-0)<0;t({target:\"Array\",proto:!0,forced:o||!r(\"indexOf\")},{indexOf:function(t){var e=arguments.length>1?arguments[1]:void 0;return o?i(this,t,e)||0:n(this,t,e)}})}();var Fr,Tr={};!function(){if(Fr)return Tr;Fr=1;var t=tr(),e=bt(),n=nr(),r=e([].reverse),i=[1,2];t({target:\"Array\",proto:!0,forced:String(i)===String(i.reverse())},{reverse:function(){return n(this)&&(this.length=this.length),r(this)}})}();var kr,Pr,Er,Ar={};!function(){if(Er)return Ar;Er=1;var t=tr(),e=function(){if(Pr)return kr;Pr=1;var t=C(),e=bt(),n=S(),r=O(),i=xr(),o=Qn(),u=vt(),f=ce(),c=mt(),a=Object.assign,s=Object.defineProperty,l=e([].concat);return kr=!a||r((function(){if(t&&1!==a({b:1},a(s({},\"a\",{enumerable:!0,get:function(){s(this,\"b\",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},n={},r=Symbol(\"assign detection\"),o=\"abcdefghijklmnopqrst\";return e[r]=7,o.split(\"\").forEach((function(t){n[t]=t})),7!==a({},e)[r]||i(a({},n)).join(\"\")!==o}))?function(e,r){for(var a=f(e),s=arguments.length,d=1,h=o.f,p=u.f;s>d;)for(var v,y=c(arguments[d++]),b=h?l(i(y),h(y)):i(y),g=b.length,m=0;g>m;)v=b[m++],t&&!n(p,y,v)||(a[v]=y[v]);return a}:a,kr}();t({target:\"Object\",stat:!0,arity:2,forced:Object.assign!==e},{assign:e})}();var Nr,Hr,Ir,Lr={};!function(){if(Ir)return Lr;Ir=1;var t=rr(),e=Ke(),n=function(){if(Hr)return Nr;Hr=1;var t=rr(),e=ir();return Nr=t?{}.toString:function(){return\"[object \"+e(this)+\"]\"}}();t||e(Object.prototype,\"toString\",n,{unsafe:!0})}();var Wr,Dr,Mr,_r,zr,Xr,Yr,qr,Gr,Vr={};function Ur(){if(Dr)return Wr;Dr=1;var t=ir(),e=String;return Wr=function(n){if(\"Symbol\"===t(n))throw new TypeError(\"Cannot convert a Symbol value to a string\");return e(n)}}function Kr(){return _r?Mr:(_r=1,Mr=\"\\t\\n\\v\\f\\r                　\\u2028\\u2029\\ufeff\")}function Qr(){if(qr)return Yr;qr=1;var t=h(),e=O(),n=bt(),r=Ur(),i=function(){if(Xr)return zr;Xr=1;var t=bt(),e=wt(),n=Ur(),r=Kr(),i=t(\"\".replace),o=RegExp(\"^[\"+r+\"]+\"),u=RegExp(\"(^|[^\"+r+\"])[\"+r+\"]+$\"),f=function(t){return function(r){var f=n(e(r));return 1&t&&(f=i(f,o,\"\")),2&t&&(f=i(f,u,\"$1\")),f}};return zr={start:f(1),end:f(2),trim:f(3)}}().trim,o=Kr(),u=t.parseInt,f=t.Symbol,c=f&&f.iterator,a=/^[+-]?0x/i,s=n(a.exec),l=8!==u(o+\"08\")||22!==u(o+\"0x16\")||c&&!e((function(){u(Object(c))}));return Yr=l?function(t,e){var n=i(r(t));return u(n,e>>>0||(s(a,n)?16:10))}:u}!function(){if(Gr)return Vr;Gr=1;var t=tr(),e=Qr();t({global:!0,forced:parseInt!==e},{parseInt:e})}();var Zr=t.fn.bootstrapTable.utils;Object.assign(t.fn.bootstrapTable.defaults,{fixedColumns:!1,fixedNumber:0,fixedRightNumber:0}),t.BootstrapTable=function(r){function i(){return function(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}(this,i),e(this,i,arguments)}return function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Super expression must either be null or a function\");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,\"prototype\",{writable:!1}),e&&u(t,e)}(i,r),n(i,[{key:\"fixedColumnsSupported\",value:function(){return this.options.fixedColumns&&!this.options.detailView&&!this.options.cardView}},{key:\"initContainer\",value:function(){f(i,\"initContainer\",this)([]),this.fixedColumnsSupported()&&(this.options.fixedNumber&&(this.$tableContainer.append('<div class=\"fixed-columns\"></div>'),this.$fixedColumns=this.$tableContainer.find(\".fixed-columns\")),this.options.fixedRightNumber&&(this.$tableContainer.append('<div class=\"fixed-columns-right\"></div>'),this.$fixedColumnsRight=this.$tableContainer.find(\".fixed-columns-right\")))}},{key:\"initBody\",value:function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];f(i,\"initBody\",this)(e),this.$fixedColumns&&this.$fixedColumns.length&&this.$fixedColumns.toggle(this.fixedColumnsSupported()),this.$fixedColumnsRight&&this.$fixedColumnsRight.length&&this.$fixedColumnsRight.toggle(this.fixedColumnsSupported()),this.fixedColumnsSupported()&&(this.options.showHeader&&this.options.height||(this.initFixedColumnsBody(),this.initFixedColumnsEvents()))}},{key:\"trigger\",value:function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];f(i,\"trigger\",this)(e),this.fixedColumnsSupported()&&(\"post-header\"===e[0]?this.initFixedColumnsHeader():\"scroll-body\"===e[0]&&(this.needFixedColumns&&this.options.fixedNumber&&this.$fixedBody.scrollTop(this.$tableBody.scrollTop()),this.needFixedColumns&&this.options.fixedRightNumber&&this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop())))}},{key:\"updateSelected\",value:function(){var e=this;f(i,\"updateSelected\",this)([]),this.fixedColumnsSupported()&&this.$tableBody.find(\"tr\").each((function(n,r){var i=t(r),o=i.data(\"index\"),u=i.attr(\"class\"),f='[name=\"'.concat(e.options.selectItemName,'\"]'),c=i.find(f);if(void 0!==o){var a=function(t,n){var r=n.find('tr[data-index=\"'.concat(o,'\"]'));r.attr(\"class\",u),c.length&&r.find(f).prop(\"checked\",c.prop(\"checked\")),e.$selectAll.length&&t.add(n).find('[name=\"btSelectAll\"]').prop(\"checked\",e.$selectAll.prop(\"checked\"))};e.$fixedBody&&e.options.fixedNumber&&a(e.$fixedHeader,e.$fixedBody),e.$fixedBodyRight&&e.options.fixedRightNumber&&a(e.$fixedHeaderRight,e.$fixedBodyRight)}}))}},{key:\"hideLoading\",value:function(){f(i,\"hideLoading\",this)([]),this.needFixedColumns&&this.options.fixedNumber&&this.$fixedColumns.find(\".fixed-table-loading\").hide(),this.needFixedColumns&&this.options.fixedRightNumber&&this.$fixedColumnsRight&&this.$fixedColumnsRight.find(\".fixed-table-loading\").hide()}},{key:\"initFixedColumnsHeader\",value:function(){var t=this;this.options.height?this.needFixedColumns=this.$tableHeader.outerWidth(!0)<this.$tableHeader.find(\"table\").outerWidth(!0):this.needFixedColumns=this.$tableBody.outerWidth(!0)<this.$tableBody.find(\"table\").outerWidth(!0);var e=function(e,n){return e.find(\".fixed-table-header\").remove(),e.append(t.$tableHeader.clone(!0)),e.css({width:t.getFixedColumnsWidth(n)}),e.find(\".fixed-table-header\")};this.needFixedColumns&&this.options.fixedNumber?(this.$fixedHeader=e(this.$fixedColumns),this.$fixedHeader.css(\"margin-right\",\"\")):this.$fixedColumns&&this.$fixedColumns.html(\"\").css(\"width\",\"\"),this.needFixedColumns&&this.options.fixedRightNumber&&this.$fixedColumnsRight?(this.$fixedHeaderRight=e(this.$fixedColumnsRight,!0),this.$fixedHeaderRight.scrollLeft(this.$fixedHeaderRight.find(\"table\").width())):this.$fixedColumnsRight&&this.$fixedColumnsRight.html(\"\").css(\"width\",\"\"),this.initFixedColumnsBody(),this.initFixedColumnsEvents()}},{key:\"initFixedColumnsBody\",value:function(){var t=this,e=function(e,n){e.find(\".fixed-table-body\").remove(),e.append(t.$tableBody.clone(!0)),e.find(\".fixed-table-body table\").removeAttr(\"id\");var r=e.find(\".fixed-table-body\"),i=t.$tableBody.get(0),o=i.scrollWidth>i.clientWidth?Zr.getScrollBarWidth():0,u=t.$tableContainer.outerHeight(!0)-o-1;return e.css({height:u}),r.css({height:u-n.height()}),r};this.needFixedColumns&&this.options.fixedNumber&&(this.$fixedBody=e(this.$fixedColumns,this.$fixedHeader)),this.needFixedColumns&&this.options.fixedRightNumber&&this.$fixedColumnsRight&&(this.$fixedBodyRight=e(this.$fixedColumnsRight,this.$fixedHeaderRight),this.$fixedBodyRight.scrollLeft(this.$fixedBodyRight.find(\"table\").width()),this.$fixedBodyRight.css(\"overflow-y\",this.options.height?\"auto\":\"hidden\"))}},{key:\"getFixedColumnsWidth\",value:function(t){var e=this.getVisibleFields(),n=0,r=this.options.fixedNumber,i=0;t&&(e=e.reverse(),r=this.options.fixedRightNumber,i=parseInt(this.$tableHeader.css(\"margin-right\"),10));for(var o=0;o<r;o++)n+=this.$header.find('th[data-field=\"'.concat(e[o],'\"]')).outerWidth(!0);return n+i+1}},{key:\"initFixedColumnsEvents\",value:function(){var e=this,n=function(n,r){var i='tr[data-index=\"'.concat(t(n.currentTarget).data(\"index\"),'\"]'),o=e.$tableBody.find(i);e.$fixedBody&&(o=o.add(e.$fixedBody.find(i))),e.$fixedBodyRight&&(o=o.add(e.$fixedBodyRight.find(i))),o.css(\"background-color\",r?t(n.currentTarget).css(\"background-color\"):\"\")};this.$tableBody.find(\"tr\").hover((function(t){n(t,!0)}),(function(t){n(t,!1)}));var r=\"undefined\"!=typeof navigator&&navigator.userAgent.toLowerCase().indexOf(\"firefox\")>-1?\"DOMMouseScroll\":\"mousewheel\";this.needFixedColumns&&this.options.fixedNumber&&this.$fixedBody&&(this.$fixedBody.find(\"tr\").hover((function(t){n(t,!0)}),(function(t){n(t,!1)})),this.$fixedBody[0].addEventListener(r,(function(t){!function(t,n){var r,i,o,u,f,c=(i=0,o=0,u=0,f=0,\"detail\"in(r=t)&&(o=r.detail),\"wheelDelta\"in r&&(o=-r.wheelDelta/120),\"wheelDeltaY\"in r&&(o=-r.wheelDeltaY/120),\"wheelDeltaX\"in r&&(i=-r.wheelDeltaX/120),\"axis\"in r&&r.axis===r.HORIZONTAL_AXIS&&(i=o,o=0),u=10*i,f=10*o,\"deltaY\"in r&&(f=r.deltaY),\"deltaX\"in r&&(u=r.deltaX),(u||f)&&r.deltaMode&&(1===r.deltaMode?(u*=40,f*=40):(u*=800,f*=800)),u&&!i&&(i=u<1?-1:1),f&&!o&&(o=f<1?-1:1),{spinX:i,spinY:o,pixelX:u,pixelY:f}),a=Math.ceil(c.pixelY),s=e.$tableBody.scrollTop()+a;(a<0&&s>0||a>0&&s<n.scrollHeight-n.clientHeight)&&t.preventDefault(),e.$tableBody.scrollTop(s),e.$fixedBody&&e.$fixedBody.scrollTop(s),e.$fixedBodyRight&&e.$fixedBodyRight.scrollTop(s)}(t,e.$fixedBody[0])}))),this.needFixedColumns&&this.options.fixedRightNumber&&(this.$fixedBodyRight.find(\"tr\").hover((function(t){n(t,!0)}),(function(t){n(t,!1)})),this.$fixedBodyRight.off(\"scroll\").on(\"scroll\",(function(){var t=e.$fixedBodyRight.scrollTop();e.$tableBody.scrollTop(t),e.$fixedBody&&e.$fixedBody.scrollTop(t)}))),this.options.filterControl&&t(this.$fixedColumns).off(\"keyup change\").on(\"keyup change\",(function(n){var r=t(n.target),i=r.val(),o=r.parents(\"th\").data(\"field\"),u=e.$header.find('th[data-field=\"'.concat(o,'\"]'));if(r.is(\"input\"))u.find(\"input\").val(i);else if(r.is(\"select\")){var f=u.find(\"select\");f.find(\"option[selected]\").removeAttr(\"selected\"),f.find('option[value=\"'.concat(i,'\"]')).attr(\"selected\",!0)}e.triggerSearch()}))}},{key:\"renderStickyHeader\",value:function(){if(this.options.stickyHeader&&(this.$stickyContainer=this.$container.find(\".sticky-header-container\"),f(i,\"renderStickyHeader\",this)([]),this.needFixedColumns&&this.options.fixedNumber&&this.$fixedColumns.css(\"z-index\",101).find(\".sticky-header-container\").css(\"right\",\"\").width(this.$fixedColumns.outerWidth()),this.needFixedColumns&&this.options.fixedRightNumber)){var t=this.$fixedColumnsRight.find(\".sticky-header-container\");this.$fixedColumnsRight.css(\"z-index\",101),t.css(\"left\",\"\").scrollLeft(t.find(\".table\").outerWidth()).width(this.$fixedColumnsRight.outerWidth())}}},{key:\"matchPositionX\",value:function(){this.options.stickyHeader&&this.$stickyContainer.eq(0).scrollLeft(this.$tableBody.scrollLeft())}}])}(t.BootstrapTable)}));\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/cookie/bootstrap-table-cookie.js",
    "content": "/**\n * @author: Dennis Hernández\n * @update zhixin wen <wenzhixin2010@gmail.com>\n */\nvar Utils = $.fn.bootstrapTable.utils\nvar UtilsCookie = {\n  cookieIds: {\n    sortOrder: 'bs.table.sortOrder',\n    sortName: 'bs.table.sortName',\n    sortPriority: 'bs.table.sortPriority',\n    pageNumber: 'bs.table.pageNumber',\n    pageList: 'bs.table.pageList',\n    hiddenColumns: 'bs.table.hiddenColumns',\n    columns: 'bs.table.columns',\n    cardView: 'bs.table.cardView',\n    customView: 'bs.table.customView',\n    searchText: 'bs.table.searchText',\n    reorderColumns: 'bs.table.reorderColumns',\n    filterControl: 'bs.table.filterControl',\n    filterBy: 'bs.table.filterBy'\n  },\n  getCurrentHeader (that) {\n    return that.options.height ? that.$tableHeader : that.$header\n  },\n  getCurrentSearchControls (that) {\n    return that.options.height ? 'table select, table input' : 'select, input'\n  },\n  isCookieSupportedByBrowser () {\n    return navigator.cookieEnabled\n  },\n  isCookieEnabled (that, cookieName) {\n    if (cookieName === 'bs.table.columns') {\n      return that.options.cookiesEnabled.includes('bs.table.hiddenColumns')\n    }\n    return that.options.cookiesEnabled.includes(cookieName)\n  },\n  setCookie (that, cookieName, cookieValue) {\n    if (\n      !that.options.cookie ||\n      !UtilsCookie.isCookieEnabled(that, cookieName)\n    ) {\n      return\n    }\n\n    return that._storage.setItem(`${that.options.cookieIdTable}.${cookieName}`, cookieValue)\n  },\n  getCookie (that, cookieName) {\n    if (\n      !cookieName ||\n      !UtilsCookie.isCookieEnabled(that, cookieName)\n    ) {\n      return null\n    }\n\n    return that._storage.getItem(`${that.options.cookieIdTable}.${cookieName}`)\n  },\n  deleteCookie (that, cookieName) {\n    return that._storage.removeItem(`${that.options.cookieIdTable}.${cookieName}`)\n  },\n  calculateExpiration (cookieExpire) {\n    const time = cookieExpire.replace(/[0-9]*/, '') // s,mi,h,d,m,y\n\n    cookieExpire = cookieExpire.replace(/[A-Za-z]{1,2}/, '') // number\n\n    switch (time.toLowerCase()) {\n      case 's':\n        cookieExpire = +cookieExpire\n        break\n      case 'mi':\n        cookieExpire *= 60\n        break\n      case 'h':\n        cookieExpire = cookieExpire * 60 * 60\n        break\n      case 'd':\n        cookieExpire = cookieExpire * 24 * 60 * 60\n        break\n      case 'm':\n        cookieExpire = cookieExpire * 30 * 24 * 60 * 60\n        break\n      case 'y':\n        cookieExpire = cookieExpire * 365 * 24 * 60 * 60\n        break\n      default:\n        cookieExpire = undefined\n        break\n    }\n    if (!cookieExpire) {\n      return ''\n    }\n    const d = new Date()\n\n    d.setTime(d.getTime() + cookieExpire * 1000)\n    return d.toGMTString()\n  },\n  initCookieFilters (that) {\n    setTimeout(() => {\n      const parsedCookieFilters = JSON.parse(\n        UtilsCookie.getCookie(that, UtilsCookie.cookieIds.filterControl))\n\n      if (!that._filterControlValuesLoaded && parsedCookieFilters) {\n        const cachedFilters = {}\n        const header = UtilsCookie.getCurrentHeader(that)\n        const searchControls = UtilsCookie.getCurrentSearchControls(that)\n\n        const applyCookieFilters = (element, filteredCookies) => {\n          filteredCookies.forEach(cookie => {\n            const value = element.value.toString()\n            const text = cookie.text\n\n            if (\n              text === '' ||\n              element.type === 'radio' &&\n              value !== text\n            ) {\n              return\n            }\n\n            if (\n              element.tagName === 'INPUT' &&\n              element.type === 'radio' &&\n              value === text\n            ) {\n              element.checked = true\n              cachedFilters[cookie.field] = text\n            } else if (element.tagName === 'INPUT') {\n              element.value = text\n              cachedFilters[cookie.field] = text\n            } else if (\n              element.tagName === 'SELECT' &&\n              that.options.filterControlContainer\n            ) {\n              element.value = text\n              cachedFilters[cookie.field] = text\n            } else if (text !== '' && element.tagName === 'SELECT') {\n              cachedFilters[cookie.field] = text\n              for (const currentElement of element) {\n                if (currentElement.value === text) {\n                  currentElement.selected = true\n                  return\n                }\n              }\n              const option = document.createElement('option')\n\n              option.value = text\n              option.text = text\n              element.add(option, element[1])\n              element.selectedIndex = 1\n            }\n          })\n        }\n\n        let filterContainer = header\n\n        if (that.options.filterControlContainer) {\n          filterContainer = $(`${that.options.filterControlContainer}`)\n        }\n\n        filterContainer.find(searchControls).each(function () {\n          const field = $(this).closest('[data-field]').data('field')\n          const filteredCookies = parsedCookieFilters.filter(cookie => cookie.field === field)\n\n          applyCookieFilters(this, filteredCookies)\n        })\n\n        that.initColumnSearch(cachedFilters)\n        that._filterControlValuesLoaded = true\n        that.initServer()\n      }\n    }, 250)\n  }\n}\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  cookie: false,\n  cookieExpire: '2h',\n  cookiePath: null,\n  cookieDomain: null,\n  cookieSecure: null,\n  cookieSameSite: 'Lax',\n  cookieIdTable: '',\n  cookiesEnabled: [\n    'bs.table.sortOrder', 'bs.table.sortName', 'bs.table.sortPriority',\n    'bs.table.pageNumber', 'bs.table.pageList',\n    'bs.table.hiddenColumns', 'bs.table.searchText',\n    'bs.table.filterControl', 'bs.table.filterBy',\n    'bs.table.reorderColumns', 'bs.table.cardView', 'bs.table.customView'\n  ],\n  cookieStorage: 'cookieStorage', // localStorage, sessionStorage, customStorage\n  cookieCustomStorageGet: null,\n  cookieCustomStorageSet: null,\n  cookieCustomStorageDelete: null,\n  // internal variable\n  _filterControls: [],\n  _filterControlValuesLoaded: false,\n  _storage: {\n    setItem: undefined,\n    getItem: undefined,\n    removeItem: undefined\n  }\n})\n\n$.fn.bootstrapTable.methods.push('getCookies')\n$.fn.bootstrapTable.methods.push('deleteCookie')\n\nObject.assign($.fn.bootstrapTable.utils, {\n  setCookie: UtilsCookie.setCookie,\n  getCookie: UtilsCookie.getCookie\n})\n\n$.BootstrapTable = class extends $.BootstrapTable {\n  init () {\n    if (this.options.cookie) {\n      if (\n        this.options.cookieStorage === 'cookieStorage' &&\n        !UtilsCookie.isCookieSupportedByBrowser()\n      ) {\n        throw new Error('Cookies are not enabled in this browser.')\n      }\n\n      this.configureStorage()\n\n      // FilterBy logic\n      const filterByCookieValue = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.filterBy)\n\n      if (typeof filterByCookieValue === 'boolean' && !filterByCookieValue) {\n        throw new Error('The cookie value of filterBy must be a json!')\n      }\n\n      let filterByCookie = {}\n\n      try {\n        filterByCookie = JSON.parse(filterByCookieValue)\n      } catch (e) {\n        console.error(e)\n        throw new Error('Could not parse the json of the filterBy cookie!')\n      }\n      this.filterColumns = filterByCookie ? filterByCookie : {}\n\n      // FilterControl logic\n      this._filterControls = []\n      this._filterControlValuesLoaded = false\n\n      this.options.cookiesEnabled = typeof this.options.cookiesEnabled === 'string' ?\n        this.options.cookiesEnabled.replace('[', '').replace(']', '')\n          .replace(/'/g, '').replace(/ /g, '').split(',') :\n        this.options.cookiesEnabled\n\n      if (this.options.filterControl) {\n        this.$el.on('column-search.bs.table', (e, field, text) => {\n          let isNewField = true\n\n          for (let i = 0; i < this._filterControls.length; i++) {\n            if (this._filterControls[i].field === field) {\n              this._filterControls[i].text = text\n              isNewField = false\n              break\n            }\n          }\n          if (isNewField) {\n            this._filterControls.push({\n              field,\n              text\n            })\n          }\n\n          UtilsCookie.setCookie(this, UtilsCookie.cookieIds.filterControl, JSON.stringify(this._filterControls))\n        }).on('created-controls.bs.table', UtilsCookie.initCookieFilters(this))\n      }\n    }\n    super.init()\n  }\n\n  initServer (...args) {\n    if (\n      this.options.cookie &&\n      this.options.filterControl &&\n      !this._filterControlValuesLoaded\n    ) {\n      const cookie = JSON.parse(UtilsCookie.getCookie(this, UtilsCookie.cookieIds.filterControl))\n\n      if (cookie) {\n        return\n      }\n    }\n    super.initServer(...args)\n  }\n\n  initTable (...args) {\n    super.initTable(...args)\n    this.initCookie()\n  }\n\n  onSort (...args) {\n    super.onSort(...args)\n\n    if (!this.options.cookie) {\n      return\n    }\n\n    if (this.options.sortName === undefined || this.options.sortOrder === undefined) {\n      UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortName)\n      UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortOrder)\n    } else {\n      this.options.sortPriority = null\n      UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortPriority)\n\n      UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortOrder, this.options.sortOrder)\n      UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortName, this.options.sortName)\n    }\n  }\n\n  onMultipleSort (...args) {\n    super.onMultipleSort(...args)\n\n    if (!this.options.cookie) {\n      return\n    }\n\n    if (this.options.sortPriority === undefined) {\n      UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortPriority)\n    } else {\n      this.options.sortName = undefined\n      this.options.sortOrder = undefined\n      UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortName)\n      UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortOrder)\n\n      UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortPriority, JSON.stringify(this.options.sortPriority))\n    }\n  }\n\n  onPageNumber (...args) {\n    super.onPageNumber(...args)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)\n  }\n\n  onPageListChange (...args) {\n    super.onPageListChange(...args)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageList,\n      this.options.pageSize === this.options.formatAllRows() ? 'all' : this.options.pageSize)\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)\n  }\n\n  onPagePre (...args) {\n    super.onPagePre(...args)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)\n  }\n\n  onPageNext (...args) {\n    super.onPageNext(...args)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)\n  }\n\n  _toggleColumn (...args) {\n    super._toggleColumn(...args)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.hiddenColumns,\n      JSON.stringify(this.getHiddenColumns().map(column => column.field)))\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.columns,\n      JSON.stringify(this.columns.map(column => column.field)))\n  }\n\n  _toggleAllColumns (...args) {\n    super._toggleAllColumns(...args)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.hiddenColumns,\n      JSON.stringify(this.getHiddenColumns().map(column => column.field)))\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.columns,\n      JSON.stringify(this.columns.map(column => column.field)))\n  }\n\n  toggleView () {\n    super.toggleView()\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.cardView, this.options.cardView)\n  }\n\n  toggleCustomView () {\n    super.toggleCustomView()\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.customView, this.customViewDefaultView)\n  }\n\n  selectPage (page) {\n    super.selectPage(page)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, page)\n  }\n\n  onSearch (event) {\n    super.onSearch(event, arguments.length > 1 ? arguments[1] : true)\n    if (!this.options.cookie) {\n      return\n    }\n    if (this.options.search) {\n      UtilsCookie.setCookie(this, UtilsCookie.cookieIds.searchText, this.searchText)\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)\n  }\n\n  initHeader (...args) {\n    if (this.options.reorderableColumns && this.options.cookie) {\n      this.columnsSortOrder = JSON.parse(UtilsCookie.getCookie(this, UtilsCookie.cookieIds.reorderColumns))\n    }\n    super.initHeader(...args)\n  }\n\n  persistReorderColumnsState (that) {\n    UtilsCookie.setCookie(that, UtilsCookie.cookieIds.reorderColumns, JSON.stringify(that.columnsSortOrder))\n  }\n\n  filterBy (...args) {\n    super.filterBy(...args)\n    if (!this.options.cookie) {\n      return\n    }\n    UtilsCookie.setCookie(this, UtilsCookie.cookieIds.filterBy, JSON.stringify(this.filterColumns))\n  }\n\n  initCookie () {\n    if (!this.options.cookie) {\n      return\n    }\n\n    if (this.options.cookieIdTable === '' || this.options.cookieExpire === '') {\n      console.error('Configuration error. Please review the cookieIdTable and the cookieExpire property. If the properties are correct, then this browser does not support cookies.')\n      this.options.cookie = false // Make sure that the cookie extension is disabled\n      return\n    }\n\n    const sortOrderCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.sortOrder)\n    const sortOrderNameCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.sortName)\n    let sortPriorityCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.sortPriority)\n    const pageNumberCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.pageNumber)\n    const pageListCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.pageList)\n    const searchTextCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.searchText)\n    const cardViewCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.cardView)\n    const customViewCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.customView)\n    const hiddenColumnsCookieValue = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.hiddenColumns)\n    const columnsCookieValue = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.columns)\n\n    let hiddenColumnsCookie = {}\n    let columnsCookie = {}\n\n    try {\n      hiddenColumnsCookie = JSON.parse(hiddenColumnsCookieValue)\n      columnsCookie = JSON.parse(columnsCookieValue)\n    } catch (e) {\n      console.error(e)\n      throw new Error('Could not parse the json of the columns cookie!')\n    }\n\n    try {\n      sortPriorityCookie = JSON.parse(sortPriorityCookie)\n    } catch (e) {\n      console.error(e)\n      throw new Error('Could not parse the json of the sortPriority cookie!', sortPriorityCookie)\n    }\n\n    if (!sortPriorityCookie) {\n      // sortOrder\n      this.options.sortOrder = sortOrderCookie ? sortOrderCookie : this.options.sortOrder\n      // sortName\n      this.options.sortName = sortOrderNameCookie ? sortOrderNameCookie : this.options.sortName\n    } else {\n      this.options.sortOrder = undefined\n      this.options.sortName = undefined\n    }\n\n    // sortPriority\n    this.options.sortPriority = sortPriorityCookie ? sortPriorityCookie : this.options.sortPriority\n\n    if (this.options.sortOrder || this.options.sortName) {\n      // sortPriority\n      this.options.sortPriority = null\n    }\n\n    // pageNumber\n    this.options.pageNumber = pageNumberCookie ? +pageNumberCookie : this.options.pageNumber\n    // pageSize\n    this.options.pageSize = pageListCookie ? pageListCookie === 'all' ?\n      this.options.formatAllRows() : +pageListCookie : this.options.pageSize\n    // searchText\n    if (UtilsCookie.isCookieEnabled(this, UtilsCookie.cookieIds.searchText) && this.options.searchText === '') {\n      this.options.searchText = searchTextCookie ? searchTextCookie : ''\n    }\n    // cardView\n    if (cardViewCookie !== null) {\n      this.options.cardView = cardViewCookie === 'true' ? cardViewCookie : false\n    }\n    this.customViewDefaultView = customViewCookie === 'true'\n\n    if (hiddenColumnsCookie) {\n      columnsCookie = columnsCookie || this.columns.map(column => column.field)\n\n      for (const column of this.columns) {\n        if (\n          !column.switchable ||\n          !columnsCookie.includes(column.field)\n        ) {\n          continue\n        }\n\n        column.visible = this.isSelectionColumn(column) ||\n          !hiddenColumnsCookie.includes(column.field)\n      }\n    }\n  }\n\n  getCookies () {\n    const cookies = {}\n\n    for (const [key, value] of Object.entries(UtilsCookie.cookieIds)) {\n      cookies[key] = UtilsCookie.getCookie(this, value)\n      if (['columns', 'hiddenColumns', 'sortPriority'].includes(key)) {\n        cookies[key] = JSON.parse(cookies[key])\n      }\n    }\n    return cookies\n  }\n\n  deleteCookie (cookieName) {\n    if (!cookieName || !this.options.cookie) {\n      return\n    }\n\n    UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds[cookieName])\n  }\n\n  configureStorage () {\n    this._storage = {}\n    switch (this.options.cookieStorage) {\n      case 'cookieStorage':\n        this._storage.setItem = (cookieName, cookieValue) => {\n          document.cookie = [\n            cookieName, '=', encodeURIComponent(cookieValue),\n            `; expires=${UtilsCookie.calculateExpiration(this.options.cookieExpire)}`,\n            this.options.cookiePath ? `; path=${this.options.cookiePath}` : '',\n            this.options.cookieDomain ? `; domain=${this.options.cookieDomain}` : '',\n            this.options.cookieSecure ? '; secure' : '',\n            `;SameSite=${this.options.cookieSameSite}`\n          ].join('')\n        }\n        this._storage.getItem = cookieName => {\n          const value = `; ${document.cookie}`\n          const parts = value.split(`; ${cookieName}=`)\n\n          return parts.length === 2 ? decodeURIComponent(parts.pop().split(';').shift()) : null\n        }\n        this._storage.removeItem = cookieName => {\n          document.cookie = [\n            encodeURIComponent(cookieName), '=',\n            '; expires=Thu, 01 Jan 1970 00:00:00 GMT',\n            this.options.cookiePath ? `; path=${this.options.cookiePath}` : '',\n            this.options.cookieDomain ? `; domain=${this.options.cookieDomain}` : '',\n            `;SameSite=${this.options.cookieSameSite}`\n          ].join('')\n        }\n        break\n      case 'localStorage':\n        this._storage.setItem = (cookieName, cookieValue) => {\n          localStorage.setItem(cookieName, cookieValue)\n        }\n        this._storage.getItem = cookieName => localStorage.getItem(cookieName)\n        this._storage.removeItem = cookieName => {\n          localStorage.removeItem(cookieName)\n        }\n        break\n      case 'sessionStorage':\n        this._storage.setItem = (cookieName, cookieValue) => {\n          sessionStorage.setItem(cookieName, cookieValue)\n        }\n        this._storage.getItem = cookieName => sessionStorage.getItem(cookieName)\n        this._storage.removeItem = cookieName => {\n          sessionStorage.removeItem(cookieName)\n        }\n        break\n      case 'customStorage':\n        if (\n          !this.options.cookieCustomStorageSet ||\n          !this.options.cookieCustomStorageGet ||\n          !this.options.cookieCustomStorageDelete\n        ) {\n          throw new Error('The following options must be set while using the customStorage: cookieCustomStorageSet, cookieCustomStorageGet and cookieCustomStorageDelete')\n        }\n\n        this._storage.setItem = (cookieName, cookieValue) => {\n          Utils.calculateObjectValue(this.options, this.options.cookieCustomStorageSet, [cookieName, cookieValue], '')\n        }\n        this._storage.getItem = cookieName => Utils.calculateObjectValue(this.options, this.options.cookieCustomStorageGet, [cookieName], '')\n        this._storage.removeItem = cookieName => {\n          Utils.calculateObjectValue(this.options, this.options.cookieCustomStorageDelete, [cookieName], '')\n        }\n        break\n      default:\n        throw new Error('Storage method not supported.')\n    }\n  }\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/custom-view/bootstrap-table-custom-view.js",
    "content": "/**\n * @author: Dustin Utecht\n * @github: https://github.com/UtechtDustin\n */\n\nvar Utils = $.fn.bootstrapTable.utils\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  customView: false,\n  showCustomView: false,\n  customViewDefaultView: false\n})\n\nUtils.assignIcons($.fn.bootstrapTable.icons, 'customViewOn', {\n  glyphicon: 'glyphicon-list',\n  fa: 'fa-list',\n  bi: 'bi-list',\n  icon: 'list',\n  'material-icons': 'list'\n})\n\nUtils.assignIcons($.fn.bootstrapTable.icons, 'customViewOff', {\n  glyphicon: 'glyphicon glyphicon-eye-open',\n  fa: 'fa-th',\n  bi: 'bi-grid',\n  icon: 'grid_on',\n  'material-icons': 'grid_on'\n})\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  onCustomViewPostBody () {\n    return false\n  },\n  onCustomViewPreBody () {\n    return false\n  },\n  onToggleCustomView () {\n    return false\n  }\n})\n\nObject.assign($.fn.bootstrapTable.locales, {\n  formatToggleCustomViewOn () {\n    return 'Show custom view'\n  },\n  formatToggleCustomViewOff () {\n    return 'Hide custom view'\n  }\n})\nObject.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)\n\n$.fn.bootstrapTable.methods.push('toggleCustomView')\n\nObject.assign($.fn.bootstrapTable.events, {\n  'custom-view-post-body.bs.table': 'onCustomViewPostBody',\n  'custom-view-pre-body.bs.table': 'onCustomViewPreBody',\n  'toggle-custom-view.bs.table': 'onToggleCustomView'\n})\n\n$.BootstrapTable = class extends $.BootstrapTable {\n\n  init () {\n    this.customViewDefaultView = this.options.customViewDefaultView\n\n    super.init()\n  }\n\n  initToolbar (...args) {\n    if (this.options.customView && this.options.showCustomView) {\n      this.buttons = Object.assign(this.buttons, {\n        customView: {\n          text: this.options.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn(),\n          icon: this.options.customViewDefaultView ? this.options.icons.customViewOn : this.options.icons.customViewOff,\n          event: this.toggleCustomView,\n          attributes: {\n            'aria-label': this.options.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn(),\n            title: this.options.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn()\n          }\n        }\n      })\n    }\n\n    super.initToolbar(...args)\n  }\n\n  initBody () {\n    super.initBody()\n\n    if (!this.options.customView) {\n      return\n    }\n\n    const $table = this.$el\n    const $customViewContainer = this.$container.find('.fixed-table-custom-view')\n\n    $table.hide()\n    $customViewContainer.hide()\n    if (!this.options.customView || !this.customViewDefaultView) {\n      $table.show()\n      return\n    }\n\n    const data = this.getData().slice(this.pageFrom - 1, this.pageTo)\n    const value = Utils.calculateObjectValue(this, this.options.customView, [data], '')\n\n    this.trigger('custom-view-pre-body', data, value)\n    if ($customViewContainer.length === 1) {\n      $customViewContainer.show().html(value)\n    } else {\n      this.$tableBody.after(`<div class=\"fixed-table-custom-view\">${value}</div>`)\n    }\n\n    this.trigger('custom-view-post-body', data, value)\n  }\n\n  toggleCustomView () {\n    this.customViewDefaultView = !this.customViewDefaultView\n\n    const icon = this.options.showButtonIcons ? this.customViewDefaultView ? this.options.icons.customViewOn : this.options.icons.customViewOff : ''\n    const text = this.options.showButtonText ? this.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn() : ''\n\n    this.$toolbar.find('button[name=\"customView\"]')\n      .html(`${Utils.sprintf(this.constants.html.icon, this.options.iconsPrefix, icon)} ${text}`)\n      .attr('aria-label', text)\n      .attr('title', text)\n\n    this.initBody()\n    this.trigger('toggle-custom-view', this.customViewDefaultView)\n  }\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/editable/bootstrap-editable.css",
    "content": "/*! X-editable - v1.5.3 \r\n* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery\r\n* http://github.com/vitalets/x-editable\r\n* Copyright (c) 2019 Vitaliy Potapov; Licensed MIT */\r\n.editableform {\r\n    margin-bottom: 0; /* overwrites bootstrap margin */\r\n}\r\n\r\n.editableform .control-group {\r\n    margin-bottom: 0; /* overwrites bootstrap margin */\r\n    white-space: nowrap; /* prevent wrapping buttons on new line */\r\n    line-height: 20px; /* overwriting bootstrap line-height. See #133 */\r\n}\r\n\r\n/*\r\n    BS3 fix: stop css from breaking when the form is inside a popup and inside a form with the class .form-horizontal\r\n    See: https://github.com/vitalets/x-editable/issues/682\r\n*/\r\n.form-horizontal .editable-popup .editableform .form-group {\r\n    margin-left:0;\r\n    margin-right:0;\r\n}\r\n\r\n\r\n/* \r\n  BS3 width:1005 for inputs breaks editable form in popup \r\n  See: https://github.com/vitalets/x-editable/issues/393\r\n*/\r\n.editableform .form-control {\r\n    width: auto;\r\n}\r\n\r\n.editable-buttons {\r\n   display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */\r\n   vertical-align: top;\r\n   margin-left: 7px;\r\n   /* inline-block emulation for IE7*/\r\n   zoom: 1; \r\n   *display: inline;\r\n}\r\n\r\n.editable-buttons.editable-buttons-bottom {\r\n   display: block; \r\n   margin-top: 7px;\r\n   margin-left: 0;\r\n}\r\n\r\n.editable-input {\r\n    vertical-align: top; \r\n    display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */\r\n    width: auto; /* bootstrap-responsive has width: 100% that breakes layout */\r\n    white-space: normal; /* reset white-space decalred in parent*/\r\n   /* display-inline emulation for IE7*/\r\n   zoom: 1; \r\n   *display: inline;   \r\n}\r\n\r\n.editable-buttons .editable-cancel {\r\n   margin-left: 7px; \r\n}\r\n\r\n/*for jquery-ui buttons need set height to look more pretty*/\r\n.editable-buttons button.ui-button-icon-only {\r\n   height: 24px; \r\n   width: 30px;\r\n}\r\n\r\n.editableform-loading {\r\n    background: url('loading.gif') center center no-repeat;  \r\n    height: 25px;\r\n    width: auto; \r\n    min-width: 25px; \r\n}\r\n\r\n.editable-inline .editableform-loading {\r\n    background-position: left 5px;      \r\n}\r\n\r\n .editable-error-block {\r\n    max-width: 300px;\r\n    margin: 5px 0 0 0;\r\n    width: auto;\r\n    white-space: normal;\r\n}\r\n\r\n/*add padding for jquery ui*/\r\n.editable-error-block.ui-state-error {\r\n    padding: 3px;  \r\n}  \r\n\r\n.editable-error {\r\n   color: red;  \r\n}\r\n\r\n/* ---- For specific types ---- */\r\n\r\n.editableform .editable-date {\r\n    padding: 0; \r\n    margin: 0;\r\n    float: left;\r\n}\r\n\r\n/* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */\r\n.editable-inline .add-on .icon-th {\r\n   margin-top: 3px;\r\n   margin-left: 1px; \r\n}\r\n\r\n\r\n/* checklist vertical alignment */\r\n.editable-checklist label input[type=\"checkbox\"], \r\n.editable-checklist label span {\r\n    vertical-align: middle;\r\n    margin: 0;\r\n}\r\n\r\n.editable-checklist label {\r\n    white-space: nowrap; \r\n}\r\n\r\n/* set exact width of textarea to fit buttons toolbar */\r\n.editable-wysihtml5 {\r\n    width: 566px; \r\n    height: 250px; \r\n}\r\n\r\n/* clear button shown as link in date inputs */\r\n.editable-clear {\r\n   clear: both;\r\n   font-size: 0.9em;\r\n   text-decoration: none;\r\n   text-align: right;\r\n}\r\n\r\n/* IOS-style clear button for text inputs */\r\n.editable-clear-x {\r\n   background: url('clear.png') center center no-repeat;\r\n   display: block;\r\n   width: 13px;    \r\n   height: 13px;\r\n   position: absolute;\r\n   opacity: 0.6;\r\n   z-index: 100;\r\n   \r\n   top: 50%;\r\n   right: 6px;\r\n   margin-top: -6px;\r\n   \r\n}\r\n\r\n.editable-clear-x:hover {\r\n   opacity: 1;\r\n}\r\n\r\n.editable-pre-wrapped {\r\n   white-space: pre-wrap;\r\n}\r\n\r\n.editable-container.editable-popup {\r\n    max-width: none !important; /* without this rule poshytip/tooltip does not stretch */\r\n}  \r\n\r\n.editable-container.popover {\r\n    width: auto; /* without this rule popover does not stretch */\r\n}\r\n\r\n.editable-container.editable-inline {\r\n    display: inline-block; \r\n    vertical-align: middle;\r\n    width: auto;\r\n    /* inline-block emulation for IE7*/\r\n    zoom: 1; \r\n    *display: inline;    \r\n}\r\n\r\n.editable-container.ui-widget {\r\n   font-size: inherit;  /* jqueryui widget font 1.1em too big, overwrite it */\r\n   z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */\r\n}\r\n.editable-click, \r\na.editable-click, \r\na.editable-click:hover {\r\n    text-decoration: none;\r\n    border-bottom: dashed 1px #0088cc;\r\n}\r\n\r\n.editable-click.editable-disabled, \r\na.editable-click.editable-disabled, \r\na.editable-click.editable-disabled:hover {\r\n   color: #585858;  \r\n   cursor: default;\r\n   border-bottom: none;\r\n}\r\n\r\n.editable-empty, .editable-empty:hover, .editable-empty:focus{\r\n  font-style: italic; \r\n  color: #DD1144;  \r\n  /* border-bottom: none; */\r\n  text-decoration: none;\r\n}\r\n\r\n.editable-unsaved {\r\n  font-weight: bold; \r\n}\r\n\r\n.editable-unsaved:after {\r\n/*    content: '*'*/\r\n}\r\n\r\n.editable-bg-transition {\r\n  -webkit-transition: background-color 1400ms ease-out;\r\n  -moz-transition: background-color 1400ms ease-out;\r\n  -o-transition: background-color 1400ms ease-out;\r\n  -ms-transition: background-color 1400ms ease-out;\r\n  transition: background-color 1400ms ease-out;  \r\n}\r\n\r\n/*see https://github.com/vitalets/x-editable/issues/139 */\r\n.form-horizontal .editable\r\n{ \r\n    padding-top: 5px;\r\n    display:inline-block;\r\n}\r\n\r\n\r\n/*!\r\n * Datepicker for Bootstrap\r\n *\r\n * Copyright 2012 Stefan Petre\r\n * Improvements by Andrew Rowls\r\n * Licensed under the Apache License v2.0\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n */\r\n.datepicker {\r\n  padding: 4px;\r\n  -webkit-border-radius: 4px;\r\n  -moz-border-radius: 4px;\r\n  border-radius: 4px;\r\n  direction: ltr;\r\n  /*.dow {\r\n\t\tborder-top: 1px solid #ddd !important;\r\n\t}*/\r\n\r\n}\r\n.datepicker-inline {\r\n  width: 220px;\r\n}\r\n.datepicker.datepicker-rtl {\r\n  direction: rtl;\r\n}\r\n.datepicker.datepicker-rtl table tr td span {\r\n  float: right;\r\n}\r\n.datepicker-dropdown {\r\n  top: 0;\r\n  left: 0;\r\n}\r\n.datepicker-dropdown:before {\r\n  content: '';\r\n  display: inline-block;\r\n  border-left: 7px solid transparent;\r\n  border-right: 7px solid transparent;\r\n  border-bottom: 7px solid #ccc;\r\n  border-bottom-color: rgba(0, 0, 0, 0.2);\r\n  position: absolute;\r\n  top: -7px;\r\n  left: 6px;\r\n}\r\n.datepicker-dropdown:after {\r\n  content: '';\r\n  display: inline-block;\r\n  border-left: 6px solid transparent;\r\n  border-right: 6px solid transparent;\r\n  border-bottom: 6px solid #ffffff;\r\n  position: absolute;\r\n  top: -6px;\r\n  left: 7px;\r\n}\r\n.datepicker > div {\r\n  display: none;\r\n}\r\n.datepicker.days div.datepicker-days {\r\n  display: block;\r\n}\r\n.datepicker.months div.datepicker-months {\r\n  display: block;\r\n}\r\n.datepicker.years div.datepicker-years {\r\n  display: block;\r\n}\r\n.datepicker table {\r\n  margin: 0;\r\n}\r\n.datepicker td,\r\n.datepicker th {\r\n  text-align: center;\r\n  width: 20px;\r\n  height: 20px;\r\n  -webkit-border-radius: 4px;\r\n  -moz-border-radius: 4px;\r\n  border-radius: 4px;\r\n  border: none;\r\n}\r\n.table-striped .datepicker table tr td,\r\n.table-striped .datepicker table tr th {\r\n  background-color: transparent;\r\n}\r\n.datepicker table tr td.day:hover {\r\n  background: #eeeeee;\r\n  cursor: pointer;\r\n}\r\n.datepicker table tr td.old,\r\n.datepicker table tr td.new {\r\n  color: #999999;\r\n}\r\n.datepicker table tr td.disabled,\r\n.datepicker table tr td.disabled:hover {\r\n  background: none;\r\n  color: #999999;\r\n  cursor: default;\r\n}\r\n.datepicker table tr td.today,\r\n.datepicker table tr td.today:hover,\r\n.datepicker table tr td.today.disabled,\r\n.datepicker table tr td.today.disabled:hover {\r\n  background-color: #fde19a;\r\n  background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);\r\n  background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);\r\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));\r\n  background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);\r\n  background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);\r\n  background-image: linear-gradient(top, #fdd49a, #fdf59a);\r\n  background-repeat: repeat-x;\r\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);\r\n  border-color: #fdf59a #fdf59a #fbed50;\r\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\r\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\r\n  color: #000;\r\n}\r\n.datepicker table tr td.today:hover,\r\n.datepicker table tr td.today:hover:hover,\r\n.datepicker table tr td.today.disabled:hover,\r\n.datepicker table tr td.today.disabled:hover:hover,\r\n.datepicker table tr td.today:active,\r\n.datepicker table tr td.today:hover:active,\r\n.datepicker table tr td.today.disabled:active,\r\n.datepicker table tr td.today.disabled:hover:active,\r\n.datepicker table tr td.today.active,\r\n.datepicker table tr td.today:hover.active,\r\n.datepicker table tr td.today.disabled.active,\r\n.datepicker table tr td.today.disabled:hover.active,\r\n.datepicker table tr td.today.disabled,\r\n.datepicker table tr td.today:hover.disabled,\r\n.datepicker table tr td.today.disabled.disabled,\r\n.datepicker table tr td.today.disabled:hover.disabled,\r\n.datepicker table tr td.today[disabled],\r\n.datepicker table tr td.today:hover[disabled],\r\n.datepicker table tr td.today.disabled[disabled],\r\n.datepicker table tr td.today.disabled:hover[disabled] {\r\n  background-color: #fdf59a;\r\n}\r\n.datepicker table tr td.today:active,\r\n.datepicker table tr td.today:hover:active,\r\n.datepicker table tr td.today.disabled:active,\r\n.datepicker table tr td.today.disabled:hover:active,\r\n.datepicker table tr td.today.active,\r\n.datepicker table tr td.today:hover.active,\r\n.datepicker table tr td.today.disabled.active,\r\n.datepicker table tr td.today.disabled:hover.active {\r\n  background-color: #fbf069 \\9;\r\n}\r\n.datepicker table tr td.today:hover:hover {\r\n  color: #000;\r\n}\r\n.datepicker table tr td.today.active:hover {\r\n  color: #fff;\r\n}\r\n.datepicker table tr td.range,\r\n.datepicker table tr td.range:hover,\r\n.datepicker table tr td.range.disabled,\r\n.datepicker table tr td.range.disabled:hover {\r\n  background: #eeeeee;\r\n  -webkit-border-radius: 0;\r\n  -moz-border-radius: 0;\r\n  border-radius: 0;\r\n}\r\n.datepicker table tr td.range.today,\r\n.datepicker table tr td.range.today:hover,\r\n.datepicker table tr td.range.today.disabled,\r\n.datepicker table tr td.range.today.disabled:hover {\r\n  background-color: #f3d17a;\r\n  background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);\r\n  background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);\r\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));\r\n  background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);\r\n  background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);\r\n  background-image: linear-gradient(top, #f3c17a, #f3e97a);\r\n  background-repeat: repeat-x;\r\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);\r\n  border-color: #f3e97a #f3e97a #edde34;\r\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\r\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\r\n  -webkit-border-radius: 0;\r\n  -moz-border-radius: 0;\r\n  border-radius: 0;\r\n}\r\n.datepicker table tr td.range.today:hover,\r\n.datepicker table tr td.range.today:hover:hover,\r\n.datepicker table tr td.range.today.disabled:hover,\r\n.datepicker table tr td.range.today.disabled:hover:hover,\r\n.datepicker table tr td.range.today:active,\r\n.datepicker table tr td.range.today:hover:active,\r\n.datepicker table tr td.range.today.disabled:active,\r\n.datepicker table tr td.range.today.disabled:hover:active,\r\n.datepicker table tr td.range.today.active,\r\n.datepicker table tr td.range.today:hover.active,\r\n.datepicker table tr td.range.today.disabled.active,\r\n.datepicker table tr td.range.today.disabled:hover.active,\r\n.datepicker table tr td.range.today.disabled,\r\n.datepicker table tr td.range.today:hover.disabled,\r\n.datepicker table tr td.range.today.disabled.disabled,\r\n.datepicker table tr td.range.today.disabled:hover.disabled,\r\n.datepicker table tr td.range.today[disabled],\r\n.datepicker table tr td.range.today:hover[disabled],\r\n.datepicker table tr td.range.today.disabled[disabled],\r\n.datepicker table tr td.range.today.disabled:hover[disabled] {\r\n  background-color: #f3e97a;\r\n}\r\n.datepicker table tr td.range.today:active,\r\n.datepicker table tr td.range.today:hover:active,\r\n.datepicker table tr td.range.today.disabled:active,\r\n.datepicker table tr td.range.today.disabled:hover:active,\r\n.datepicker table tr td.range.today.active,\r\n.datepicker table tr td.range.today:hover.active,\r\n.datepicker table tr td.range.today.disabled.active,\r\n.datepicker table tr td.range.today.disabled:hover.active {\r\n  background-color: #efe24b \\9;\r\n}\r\n.datepicker table tr td.selected,\r\n.datepicker table tr td.selected:hover,\r\n.datepicker table tr td.selected.disabled,\r\n.datepicker table tr td.selected.disabled:hover {\r\n  background-color: #9e9e9e;\r\n  background-image: -moz-linear-gradient(top, #b3b3b3, #808080);\r\n  background-image: -ms-linear-gradient(top, #b3b3b3, #808080);\r\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));\r\n  background-image: -webkit-linear-gradient(top, #b3b3b3, #808080);\r\n  background-image: -o-linear-gradient(top, #b3b3b3, #808080);\r\n  background-image: linear-gradient(top, #b3b3b3, #808080);\r\n  background-repeat: repeat-x;\r\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);\r\n  border-color: #808080 #808080 #595959;\r\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\r\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\r\n  color: #fff;\r\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\r\n}\r\n.datepicker table tr td.selected:hover,\r\n.datepicker table tr td.selected:hover:hover,\r\n.datepicker table tr td.selected.disabled:hover,\r\n.datepicker table tr td.selected.disabled:hover:hover,\r\n.datepicker table tr td.selected:active,\r\n.datepicker table tr td.selected:hover:active,\r\n.datepicker table tr td.selected.disabled:active,\r\n.datepicker table tr td.selected.disabled:hover:active,\r\n.datepicker table tr td.selected.active,\r\n.datepicker table tr td.selected:hover.active,\r\n.datepicker table tr td.selected.disabled.active,\r\n.datepicker table tr td.selected.disabled:hover.active,\r\n.datepicker table tr td.selected.disabled,\r\n.datepicker table tr td.selected:hover.disabled,\r\n.datepicker table tr td.selected.disabled.disabled,\r\n.datepicker table tr td.selected.disabled:hover.disabled,\r\n.datepicker table tr td.selected[disabled],\r\n.datepicker table tr td.selected:hover[disabled],\r\n.datepicker table tr td.selected.disabled[disabled],\r\n.datepicker table tr td.selected.disabled:hover[disabled] {\r\n  background-color: #808080;\r\n}\r\n.datepicker table tr td.selected:active,\r\n.datepicker table tr td.selected:hover:active,\r\n.datepicker table tr td.selected.disabled:active,\r\n.datepicker table tr td.selected.disabled:hover:active,\r\n.datepicker table tr td.selected.active,\r\n.datepicker table tr td.selected:hover.active,\r\n.datepicker table tr td.selected.disabled.active,\r\n.datepicker table tr td.selected.disabled:hover.active {\r\n  background-color: #666666 \\9;\r\n}\r\n.datepicker table tr td.active,\r\n.datepicker table tr td.active:hover,\r\n.datepicker table tr td.active.disabled,\r\n.datepicker table tr td.active.disabled:hover {\r\n  background-color: #006dcc;\r\n  background-image: -moz-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: -ms-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));\r\n  background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: -o-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: linear-gradient(top, #0088cc, #0044cc);\r\n  background-repeat: repeat-x;\r\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);\r\n  border-color: #0044cc #0044cc #002a80;\r\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\r\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\r\n  color: #fff;\r\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\r\n}\r\n.datepicker table tr td.active:hover,\r\n.datepicker table tr td.active:hover:hover,\r\n.datepicker table tr td.active.disabled:hover,\r\n.datepicker table tr td.active.disabled:hover:hover,\r\n.datepicker table tr td.active:active,\r\n.datepicker table tr td.active:hover:active,\r\n.datepicker table tr td.active.disabled:active,\r\n.datepicker table tr td.active.disabled:hover:active,\r\n.datepicker table tr td.active.active,\r\n.datepicker table tr td.active:hover.active,\r\n.datepicker table tr td.active.disabled.active,\r\n.datepicker table tr td.active.disabled:hover.active,\r\n.datepicker table tr td.active.disabled,\r\n.datepicker table tr td.active:hover.disabled,\r\n.datepicker table tr td.active.disabled.disabled,\r\n.datepicker table tr td.active.disabled:hover.disabled,\r\n.datepicker table tr td.active[disabled],\r\n.datepicker table tr td.active:hover[disabled],\r\n.datepicker table tr td.active.disabled[disabled],\r\n.datepicker table tr td.active.disabled:hover[disabled] {\r\n  background-color: #0044cc;\r\n}\r\n.datepicker table tr td.active:active,\r\n.datepicker table tr td.active:hover:active,\r\n.datepicker table tr td.active.disabled:active,\r\n.datepicker table tr td.active.disabled:hover:active,\r\n.datepicker table tr td.active.active,\r\n.datepicker table tr td.active:hover.active,\r\n.datepicker table tr td.active.disabled.active,\r\n.datepicker table tr td.active.disabled:hover.active {\r\n  background-color: #003399 \\9;\r\n}\r\n.datepicker table tr td span {\r\n  display: block;\r\n  width: 23%;\r\n  height: 54px;\r\n  line-height: 54px;\r\n  float: left;\r\n  margin: 1%;\r\n  cursor: pointer;\r\n  -webkit-border-radius: 4px;\r\n  -moz-border-radius: 4px;\r\n  border-radius: 4px;\r\n}\r\n.datepicker table tr td span:hover {\r\n  background: #eeeeee;\r\n}\r\n.datepicker table tr td span.disabled,\r\n.datepicker table tr td span.disabled:hover {\r\n  background: none;\r\n  color: #999999;\r\n  cursor: default;\r\n}\r\n.datepicker table tr td span.active,\r\n.datepicker table tr td span.active:hover,\r\n.datepicker table tr td span.active.disabled,\r\n.datepicker table tr td span.active.disabled:hover {\r\n  background-color: #006dcc;\r\n  background-image: -moz-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: -ms-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));\r\n  background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: -o-linear-gradient(top, #0088cc, #0044cc);\r\n  background-image: linear-gradient(top, #0088cc, #0044cc);\r\n  background-repeat: repeat-x;\r\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);\r\n  border-color: #0044cc #0044cc #002a80;\r\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\r\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\r\n  color: #fff;\r\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\r\n}\r\n.datepicker table tr td span.active:hover,\r\n.datepicker table tr td span.active:hover:hover,\r\n.datepicker table tr td span.active.disabled:hover,\r\n.datepicker table tr td span.active.disabled:hover:hover,\r\n.datepicker table tr td span.active:active,\r\n.datepicker table tr td span.active:hover:active,\r\n.datepicker table tr td span.active.disabled:active,\r\n.datepicker table tr td span.active.disabled:hover:active,\r\n.datepicker table tr td span.active.active,\r\n.datepicker table tr td span.active:hover.active,\r\n.datepicker table tr td span.active.disabled.active,\r\n.datepicker table tr td span.active.disabled:hover.active,\r\n.datepicker table tr td span.active.disabled,\r\n.datepicker table tr td span.active:hover.disabled,\r\n.datepicker table tr td span.active.disabled.disabled,\r\n.datepicker table tr td span.active.disabled:hover.disabled,\r\n.datepicker table tr td span.active[disabled],\r\n.datepicker table tr td span.active:hover[disabled],\r\n.datepicker table tr td span.active.disabled[disabled],\r\n.datepicker table tr td span.active.disabled:hover[disabled] {\r\n  background-color: #0044cc;\r\n}\r\n.datepicker table tr td span.active:active,\r\n.datepicker table tr td span.active:hover:active,\r\n.datepicker table tr td span.active.disabled:active,\r\n.datepicker table tr td span.active.disabled:hover:active,\r\n.datepicker table tr td span.active.active,\r\n.datepicker table tr td span.active:hover.active,\r\n.datepicker table tr td span.active.disabled.active,\r\n.datepicker table tr td span.active.disabled:hover.active {\r\n  background-color: #003399 \\9;\r\n}\r\n.datepicker table tr td span.old,\r\n.datepicker table tr td span.new {\r\n  color: #999999;\r\n}\r\n.datepicker th.datepicker-switch {\r\n  width: 145px;\r\n}\r\n.datepicker thead tr:first-child th,\r\n.datepicker tfoot tr th {\r\n  cursor: pointer;\r\n}\r\n.datepicker thead tr:first-child th:hover,\r\n.datepicker tfoot tr th:hover {\r\n  background: #eeeeee;\r\n}\r\n.datepicker .cw {\r\n  font-size: 10px;\r\n  width: 12px;\r\n  padding: 0 2px 0 5px;\r\n  vertical-align: middle;\r\n}\r\n.datepicker thead tr:first-child th.cw {\r\n  cursor: default;\r\n  background-color: transparent;\r\n}\r\n.input-append.date .add-on i,\r\n.input-prepend.date .add-on i {\r\n  display: block;\r\n  cursor: pointer;\r\n  width: 16px;\r\n  height: 16px;\r\n}\r\n.input-daterange input {\r\n  text-align: center;\r\n}\r\n.input-daterange input:first-child {\r\n  -webkit-border-radius: 3px 0 0 3px;\r\n  -moz-border-radius: 3px 0 0 3px;\r\n  border-radius: 3px 0 0 3px;\r\n}\r\n.input-daterange input:last-child {\r\n  -webkit-border-radius: 0 3px 3px 0;\r\n  -moz-border-radius: 0 3px 3px 0;\r\n  border-radius: 0 3px 3px 0;\r\n}\r\n.input-daterange .add-on {\r\n  display: inline-block;\r\n  width: auto;\r\n  min-width: 16px;\r\n  height: 18px;\r\n  padding: 4px 5px;\r\n  font-weight: normal;\r\n  line-height: 18px;\r\n  text-align: center;\r\n  text-shadow: 0 1px 0 #ffffff;\r\n  vertical-align: middle;\r\n  background-color: #eeeeee;\r\n  border: 1px solid #ccc;\r\n  margin-left: -5px;\r\n  margin-right: -5px;\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/editable/bootstrap-table-editable.js",
    "content": "/**\n * @author zhixin wen <wenzhixin2010@gmail.com>\n * extensions: https://github.com/vitalets/x-editable\n */\n\nvar Utils = $.fn.bootstrapTable.utils\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  editable: true,\n  onEditableInit () {\n    return false\n  },\n  onEditableSave (field, row, rowIndex, oldValue, $el) {\n    return false\n  },\n  onEditableShown (field, row, $el, editable) {\n    return false\n  },\n  onEditableHidden (field, row, $el, reason) {\n    return false\n  }\n})\n\nObject.assign($.fn.bootstrapTable.columnDefaults, {\n  alwaysUseFormatter: false\n})\n\nObject.assign($.fn.bootstrapTable.events, {\n  'editable-init.bs.table': 'onEditableInit',\n  'editable-save.bs.table': 'onEditableSave',\n  'editable-shown.bs.table': 'onEditableShown',\n  'editable-hidden.bs.table': 'onEditableHidden'\n})\n\n$.BootstrapTable = class extends $.BootstrapTable {\n  initTable () {\n    super.initTable()\n\n    if (!this.options.editable) {\n      return\n    }\n\n    this.editedCells = []\n    $.each(this.columns, (i, column) => {\n      if (!column.editable) {\n        return\n      }\n\n      const editableOptions = {}\n      const editableDataPrefix = 'editable-'\n      const processDataOptions = (key, value) => {\n        // Replace camel case with dashes.\n        const dashKey = key.replace(/([A-Z])/g, $1 => `-${$1.toLowerCase()}`)\n\n        if (dashKey.indexOf(editableDataPrefix) === 0) {\n          editableOptions[dashKey.replace(editableDataPrefix, 'data-')] = value\n        }\n      }\n\n      const formatterIsSet = column.formatter ? true : false\n\n      $.each(this.options, processDataOptions)\n\n      column.formatter = column.formatter || (value => value)\n      column._formatter = column._formatter ? column._formatter : column.formatter\n      column.formatter = (value, row, index, field) => {\n        let result = Utils.calculateObjectValue(column, column._formatter, [value, row, index, field], value)\n\n        result = typeof result === 'undefined' || result === null ? this.options.undefinedText : result\n        if (this.options.uniqueId !== undefined && !column.alwaysUseFormatter) {\n          const uniqueId = Utils.getItemField(row, this.options.uniqueId, false)\n\n          if ($.inArray(column.field + uniqueId, this.editedCells) !== -1) {\n            result = value\n          }\n        }\n\n        $.each(column, processDataOptions)\n\n        const editableOpts = Utils.calculateObjectValue(column,\n          column.editable, [index, row], {})\n        const noEditFormatter = editableOpts.hasOwnProperty('noEditFormatter') &&\n                                editableOpts.noEditFormatter(value, row, index, field)\n\n        if (noEditFormatter) {\n          return noEditFormatter\n        }\n\n        let editableDataMarkup = ''\n\n        $.each(editableOptions, (key, value) => {\n          editableDataMarkup += ` ${key}=\"${value}\"`\n        })\n\n        return `<a href=\"javascript:void(0)\"\n          data-name=\"${column.field}\"\n          data-pk=\"${row[this.options.idField]}\"\n          data-value=\"${value || ''}\"\n          ${editableDataMarkup}>${formatterIsSet ? result : ''}</a>` // expand all data-editable-XXX\n      }\n    })\n  }\n\n  initBody (fixedScroll) {\n    super.initBody(fixedScroll)\n\n    if (!this.options.editable) {\n      return\n    }\n\n    $.each(this.columns, (i, column) => {\n      if (!column.editable) {\n        return\n      }\n\n      const data = this.getData({ escape: true })\n      const $field = this.$body.find(`a[data-name=\"${column.field}\"]`)\n\n      $field.each((i, element) => {\n        const $element = $(element)\n        const $tr = $element.closest('tr')\n        const index = $tr.data('index')\n        const row = data[index]\n\n        const editableOpts = Utils.calculateObjectValue(column,\n          column.editable, [index, row, $element], {})\n\n        $element.editable(editableOpts)\n      })\n\n      $field.off('save').on('save', ({ currentTarget }, { submitValue }) => {\n        const $this = $(currentTarget)\n        const data = this.getData()\n        const rowIndex = $this.parents('tr[data-index]').data('index')\n        const row = data[rowIndex]\n        const oldValue = row[column.field]\n\n        if (this.options.uniqueId !== undefined && !column.alwaysUseFormatter) {\n          const uniqueId = Utils.getItemField(row, this.options.uniqueId, false)\n\n          if ($.inArray(column.field + uniqueId, this.editedCells) === -1) {\n            this.editedCells.push(column.field + uniqueId)\n          }\n        }\n\n        submitValue = Utils.escapeHTML(submitValue)\n        $this.data('value', submitValue)\n        row[column.field] = submitValue\n        this.trigger('editable-save', column.field, row, rowIndex, oldValue, $this)\n        this.initBody()\n      })\n\n      $field.off('shown').on('shown', ({ currentTarget }, editable) => {\n        const $this = $(currentTarget)\n        const data = this.getData()\n        const rowIndex = $this.parents('tr[data-index]').data('index')\n        const row = data[rowIndex]\n\n        this.trigger('editable-shown', column.field, row, $this, editable)\n      })\n\n      $field.off('hidden').on('hidden', ({ currentTarget }, reason) => {\n        const $this = $(currentTarget)\n        const data = this.getData()\n        const rowIndex = $this.parents('tr[data-index]').data('index')\n        const row = data[rowIndex]\n\n        this.trigger('editable-hidden', column.field, row, $this, reason)\n      })\n    })\n    this.trigger('editable-init')\n  }\n\n  getData (params) {\n    const data = super.getData(params)\n\n    if (params && params.escape) {\n      for (const row of data) {\n        for (const [key, value] of Object.entries(row)) {\n          if (typeof(value) !== \"number\") {\n            row[key] = Utils.unescapeHTML(value)\n          }\n        }\n      }\n    }\n\n    return data\n  }\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/export/bootstrap-table-export.js",
    "content": "/**\n * @author zhixin wen <wenzhixin2010@gmail.com>\n * extensions: https://github.com/hhurz/tableExport.jquery.plugin\n */\n\nvar Utils = $.fn.bootstrapTable.utils\n\nconst TYPE_NAME = {\n  json: 'JSON',\n  xml: 'XML',\n  png: 'PNG',\n  csv: 'CSV',\n  txt: 'TXT',\n  sql: 'SQL',\n  doc: 'MS-Word',\n  excel: 'MS-Excel',\n  xlsx: 'MS-Excel (OpenXML)',\n  powerpoint: 'MS-Powerpoint',\n  pdf: 'PDF'\n}\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  showExport: false,\n  exportDataType: 'basic', // basic, all, selected\n  exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel'],\n  exportOptions: {},\n  exportFooter: false\n})\n\nObject.assign($.fn.bootstrapTable.columnDefaults, {\n  forceExport: false,\n  forceHide: false\n})\n\nUtils.assignIcons($.fn.bootstrapTable.icons, 'export', {\n  glyphicon: 'glyphicon-export icon-share',\n  fa: 'fa-download',\n  bi: 'bi-download',\n  icon: 'icon-download',\n  'material-icons': 'file_download'\n})\n\nObject.assign($.fn.bootstrapTable.locales, {\n  formatExport () {\n    return 'Export data'\n  }\n})\nObject.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)\n\n$.fn.bootstrapTable.methods.push('exportTable')\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  // eslint-disable-next-line no-unused-vars\n  onExportSaved (exportedRows) {\n    return false\n  },\n  onExportStarted () {\n    return false\n  }\n})\n\nObject.assign($.fn.bootstrapTable.events, {\n  'export-saved.bs.table': 'onExportSaved',\n  'export-started.bs.table': 'onExportStarted'\n})\n\n$.BootstrapTable = class extends $.BootstrapTable {\n  initToolbar (...args) {\n    const o = this.options\n    let exportTypes = o.exportTypes\n\n    this.showToolbar = this.showToolbar || o.showExport\n\n    if (this.options.showExport) {\n\n      if (typeof exportTypes === 'string') {\n        const types = exportTypes.slice(1, -1).replace(/ /g, '').split(',')\n\n        exportTypes = types.map(t => t.slice(1, -1))\n      }\n\n      if (typeof o.exportOptions === 'string') {\n        o.exportOptions = Utils.calculateObjectValue(null, o.exportOptions)\n      }\n\n      this.$export = this.$toolbar.find('>.columns div.export')\n      if (this.$export.length) {\n        this.updateExportButton()\n        return\n      }\n\n      this.buttons = Object.assign(this.buttons, {\n        export: {\n          html:\n            () => {\n              if (exportTypes.length === 1) {\n                return `\n                  <div class=\"export ${this.constants.classes.buttonsDropdown}\"\n                  data-type=\"${exportTypes[0]}\">\n                  <button class=\"${this.constants.buttonsClass}\"\n                  aria-label=\"${o.formatExport()}\"\n                  type=\"button\"\n                  title=\"${o.formatExport()}\">\n                  ${o.showButtonIcons ? Utils.sprintf(this.constants.html.icon, o.iconsPrefix, o.icons.export) : ''}\n                  ${o.showButtonText ? o.formatExport() : ''}\n                  </button>\n                  </div>\n                `\n              }\n\n              const html = []\n\n              html.push(`\n                <div class=\"export ${this.constants.classes.buttonsDropdown}\">\n                <button class=\"${this.constants.buttonsClass} dropdown-toggle\"\n                aria-label=\"${o.formatExport()}\"\n                ${this.constants.dataToggle}=\"dropdown\"\n                type=\"button\"\n                title=\"${o.formatExport()}\">\n                ${o.showButtonIcons ? Utils.sprintf(this.constants.html.icon, o.iconsPrefix, o.icons.export) : ''}\n                ${o.showButtonText ? o.formatExport() : ''}\n                ${this.constants.html.dropdownCaret}\n                </button>\n                ${this.constants.html.toolbarDropdown[0]}\n              `)\n\n              for (const type of exportTypes) {\n                if (TYPE_NAME.hasOwnProperty(type)) {\n                  const $item = $(Utils.sprintf(this.constants.html.pageDropdownItem, '', TYPE_NAME[type]))\n\n                  $item.attr('data-type', type)\n                  html.push($item.prop('outerHTML'))\n                }\n              }\n\n              html.push(this.constants.html.toolbarDropdown[1], '</div>')\n              return html.join('')\n            }\n        }\n      })\n    }\n\n    super.initToolbar(...args)\n    this.$export = this.$toolbar.find('>.columns div.export')\n\n    if (!this.options.showExport) {\n      return\n    }\n\n    this.updateExportButton()\n    let $exportButtons = this.$export.find('[data-type]')\n\n    if (exportTypes.length === 1) {\n      $exportButtons = this.$export\n    }\n\n    $exportButtons.click(e => {\n      e.preventDefault()\n      this.trigger('export-started')\n      this.exportTable({\n        type: $(e.currentTarget).data('type')\n      })\n    })\n    this.handleToolbar()\n  }\n\n  handleToolbar () {\n    if (!this.$export) {\n      return\n    }\n\n    if (super.handleToolbar) {\n      super.handleToolbar()\n    }\n  }\n\n  exportTable (options) {\n    const o = this.options\n    const stateField = this.header.stateField\n    const isCardView = o.cardView\n\n    const doExport = callback => {\n      if (stateField) {\n        this.hideColumn(stateField)\n      }\n      if (isCardView) {\n        this.toggleView()\n      }\n\n      this.columns.forEach(row => {\n        if (row.forceHide) {\n          this.hideColumn(row.field)\n        }\n      })\n\n      const data = this.getData()\n\n      if (o.detailView && o.detailViewIcon) {\n        const detailViewIndex = o.detailViewAlign === 'left' ? 0 : this.getVisibleFields().length + Utils.getDetailViewIndexOffset(this.options)\n\n        o.exportOptions.ignoreColumn = [detailViewIndex].concat(o.exportOptions.ignoreColumn || [])\n      }\n\n      if (o.exportFooter && o.height) {\n        const $footerRow = this.$tableFooter.find('tr').first()\n        const footerData = {}\n        const footerHtml = []\n\n        $footerRow.children().forEach((footerCell, index) => {\n          const footerCellHtml = $(footerCell).children('.th-inner').first().html()\n\n          footerData[this.columns[index].field] = footerCellHtml === '&nbsp;' ? null : footerCellHtml\n\n          // grab footer cell text into cell index-based array\n          footerHtml.push(footerCellHtml)\n        })\n\n        this.$body.append(this.$body.children().last()[0].outerHTML)\n        const $lastTableRow = this.$body.children().last()\n\n        $lastTableRow.children().forEach((lastTableRowCell, index) => {\n          $(lastTableRowCell).html(footerHtml[index])\n        })\n      }\n\n      const hiddenColumns = this.getHiddenColumns()\n\n      hiddenColumns.forEach(row => {\n        if (row.forceExport) {\n          this.showColumn(row.field)\n        }\n      })\n\n      if (typeof o.exportOptions.fileName === 'function') {\n        options.fileName = o.exportOptions.fileName()\n      }\n\n      this.$el.tableExport(Utils.extend({\n        onAfterSaveToFile: () => {\n          if (o.exportFooter) {\n            this.load(data)\n          }\n\n          if (stateField) {\n            this.showColumn(stateField)\n          }\n          if (isCardView) {\n            this.toggleView()\n          }\n\n          hiddenColumns.forEach(row => {\n            if (row.forceExport) {\n              this.hideColumn(row.field)\n            }\n          })\n\n          this.columns.forEach(row => {\n            if (row.forceHide) {\n              this.showColumn(row.field)\n            }\n          })\n\n          if (callback) callback()\n        }\n      }, o.exportOptions, options))\n    }\n\n    if (o.exportDataType === 'all' && o.pagination) {\n      const eventName = o.sidePagination === 'server' ?\n        'post-body.bs.table' : 'page-change.bs.table'\n      const virtualScroll = this.options.virtualScroll\n\n      this.$el.one(eventName, () => {\n        setTimeout(() => {\n          const data = this.getData()\n\n          doExport(() => {\n            this.options.virtualScroll = virtualScroll\n            this.togglePagination()\n          })\n          this.trigger('export-saved', data)\n        }, 0)\n      })\n      this.options.virtualScroll = false\n      this.togglePagination()\n    } else if (o.exportDataType === 'selected') {\n      let data = this.getData()\n      let selectedData = this.getSelections()\n      const pagination = o.pagination\n\n      if (!selectedData.length) {\n        return\n      }\n\n      if (o.sidePagination === 'server') {\n        data = {\n          total: o.totalRows,\n          [this.options.dataField]: data\n        }\n        selectedData = {\n          total: selectedData.length,\n          [this.options.dataField]: selectedData\n        }\n      }\n\n      this.load(selectedData)\n      if (pagination) {\n        this.togglePagination()\n      }\n      doExport(() => {\n        if (pagination) {\n          this.togglePagination()\n        }\n        this.load(data)\n      })\n      this.trigger('export-saved', selectedData)\n    } else {\n      doExport()\n      this.trigger('export-saved', this.getData(true))\n    }\n  }\n\n  updateSelected () {\n    super.updateSelected()\n    this.updateExportButton()\n  }\n\n  updateExportButton () {\n    if (this.options.exportDataType === 'selected') {\n      this.$export.find('> button')\n        .prop('disabled', !this.getSelections().length)\n    }\n  }\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/mobile/bootstrap-table-mobile.js",
    "content": "/**\n * @author: Dennis Hernández\n * @update zhixin wen <wenzhixin2010@gmail.com>\n */\n\nconst debounce = (func, wait) => {\n  let timeout = 0\n\n  return (...args) => {\n    const later = () => {\n      timeout = 0\n      func(...args)\n    }\n\n    clearTimeout(timeout)\n    timeout = setTimeout(later, wait)\n  }\n}\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  mobileResponsive: false,\n  minWidth: 562,\n  minHeight: undefined,\n  heightThreshold: 100, // just slightly larger than mobile chrome's auto-hiding toolbar\n  checkOnInit: true,\n  columnsHidden: []\n})\n\n$.BootstrapTable = class extends $.BootstrapTable {\n  init (...args) {\n    super.init(...args)\n\n    if (!this.options.mobileResponsive || !this.options.minWidth) {\n      return\n    }\n\n    if (this.options.minWidth < 100 && this.options.resizable) {\n      console.warn('The minWidth when the resizable extension is active should be greater or equal than 100')\n      this.options.minWidth = 100\n    }\n\n    let old = {\n      width: $(window).width(),\n      height: $(window).height()\n    }\n\n    $(window).on('resize orientationchange', debounce(() => {\n      // reset view if height has only changed by at least the threshold.\n      const width = $(window).width()\n      const height = $(window).height()\n      const $activeElement = $(document.activeElement)\n\n      if ($activeElement.length && ['INPUT', 'SELECT', 'TEXTAREA'].includes($activeElement.prop('nodeName'))) {\n        return\n      }\n\n      if (\n        Math.abs(old.height - height) > this.options.heightThreshold ||\n        old.width !== width\n      ) {\n        this.changeView(width, height)\n        old = {\n          width,\n          height\n        }\n      }\n    }, 200))\n\n    if (this.options.checkOnInit) {\n      const width = $(window).width()\n      const height = $(window).height()\n\n      this.changeView(width, height)\n      old = {\n        width,\n        height\n      }\n    }\n  }\n\n  conditionCardView () {\n    this.changeTableView(false)\n    this.showHideColumns(false)\n  }\n\n  conditionFullView () {\n    this.changeTableView(true)\n    this.showHideColumns(true)\n  }\n\n  changeTableView (cardViewState) {\n    this.options.cardView = cardViewState\n    this.toggleView()\n  }\n\n  showHideColumns (checked) {\n    if (this.options.columnsHidden.length > 0) {\n      this.columns.forEach(column => {\n        if (this.options.columnsHidden.includes(column.field)) {\n          if (column.visible !== checked) {\n            this._toggleColumn(this.fieldsColumnsIndex[column.field], checked, true)\n          }\n        }\n      })\n    }\n  }\n\n  changeView (width, height) {\n    if (this.options.minHeight) {\n      if (width <= this.options.minWidth && height <= this.options.minHeight) {\n        this.conditionCardView()\n      } else if (width > this.options.minWidth && height > this.options.minHeight) {\n        this.conditionFullView()\n      }\n    } else if (width <= this.options.minWidth) {\n      this.conditionCardView()\n    } else if (width > this.options.minWidth) {\n      this.conditionFullView()\n    }\n\n    this.resetView()\n  }\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/print/bootstrap-table-print.js",
    "content": "/**\n * @update zhixin wen <wenzhixin2010@gmail.com>\n */\n\nvar Utils = $.fn.bootstrapTable.utils\n\nfunction printPageBuilderDefault (table, styles) {\n  return `\n    <html>\n    <head>\n    ${styles}\n    <style type=\"text/css\" media=\"print\">\n    @page {\n      size: auto;\n      margin: 25px 0 25px 0;\n    }\n    </style>\n    <style type=\"text/css\" media=\"all\">\n    table {\n      border-collapse: collapse;\n      font-size: 12px;\n    }\n    table, th, td {\n      border: 1px solid grey;\n    }\n    th, td {\n      text-align: center;\n      vertical-align: middle;\n    }\n    p {\n      font-weight: bold;\n      margin-left:20px;\n    }\n    table {\n      width: 94%;\n      margin-left: 3%;\n      margin-right: 3%;\n    }\n    div.bs-table-print {\n      text-align: center;\n    }\n    </style>\n    </head>\n    <title>Print Table</title>\n    <body>\n    <p>Printed on: ${new Date} </p>\n    <div class=\"bs-table-print\">${table}</div>\n    </body>\n    </html>\n  `\n}\n\nObject.assign($.fn.bootstrapTable.locales, {\n  formatPrint () {\n    return 'Print'\n  }\n})\nObject.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  showPrint: false,\n  printAsFilteredAndSortedOnUI: true,\n  printSortColumn: undefined,\n  printSortOrder: 'asc',\n  printStyles: [],\n  printPageBuilder (table, styles) {\n    return printPageBuilderDefault(table, styles)\n  }\n})\n\nObject.assign($.fn.bootstrapTable.columnDefaults, {\n  printFilter: undefined,\n  printIgnore: false,\n  printFormatter: undefined\n})\n\nUtils.assignIcons($.fn.bootstrapTable.icons, 'print', {\n  glyphicon: 'glyphicon-print icon-share',\n  fa: 'fa-print',\n  bi: 'bi-printer',\n  icon: 'icon-printer',\n  'material-icons': 'print'\n})\n\n$.BootstrapTable = class extends $.BootstrapTable {\n  init (...args) {\n    super.init(...args)\n\n    if (!this.options.showPrint) {\n      return\n    }\n\n    this.mergedCells = []\n  }\n\n  initToolbar (...args) {\n    this.showToolbar = this.showToolbar || this.options.showPrint\n\n    if (this.options.showPrint) {\n      this.buttons = Object.assign(this.buttons, {\n        print: {\n          text: this.options.formatPrint(),\n          icon: this.options.icons.print,\n          event: () => {\n            this.doPrint(this.options.printAsFilteredAndSortedOnUI ? this.getData() : this.options.data.slice(0))\n          },\n          attributes: {\n            'aria-label': this.options.formatPrint(),\n            title: this.options.formatPrint()\n          }\n        }\n      })\n    }\n\n    super.initToolbar(...args)\n  }\n\n  mergeCells (options) {\n    super.mergeCells(options)\n\n    if (!this.options.showPrint) {\n      return\n    }\n\n    let col = this.getVisibleFields().indexOf(options.field)\n\n    if (Utils.hasDetailViewIcon(this.options)) {\n      col += 1\n    }\n\n    this.mergedCells.push({\n      row: options.index,\n      col,\n      rowspan: +options.rowspan || 1,\n      colspan: +options.colspan || 1\n    })\n  }\n\n  doPrint (data) {\n    const canPrint = column => !column.printIgnore && column.visible\n\n    const formatValue = (row, i, column) => {\n      const value_ = Utils.getItemField(row, column.field, this.options.escape, column.escape)\n      const value = Utils.calculateObjectValue(column,\n        column.printFormatter || column.formatter,\n        [value_, row, i], value_)\n\n      return typeof value === 'undefined' || value === null ?\n        this.options.undefinedText : $('<div>').html(value).html()\n    }\n\n    const buildTable = (data, columnsArray) => {\n      const dir = this.$el.attr('dir') || 'ltr'\n      const html = [`<table dir=\"${dir}\"><thead>`]\n\n      for (const columns of columnsArray) {\n        html.push('<tr>')\n        for (let h = 0; h < columns.length; h++) {\n          if (canPrint(columns[h])) {\n            html.push(\n              `<th\n              ${Utils.sprintf(' rowspan=\"%s\"', columns[h].rowspan)}\n              ${Utils.sprintf(' colspan=\"%s\"', columns[h].colspan)}\n              >${columns[h].title}</th>`)\n          }\n        }\n        html.push('</tr>')\n      }\n\n      html.push('</thead><tbody>')\n\n      const notRender = []\n\n      if (this.mergedCells) {\n        for (let mc = 0; mc < this.mergedCells.length; mc++) {\n          const currentMergedCell = this.mergedCells[mc]\n\n          for (let rs = 0; rs < currentMergedCell.rowspan; rs++) {\n            const row = currentMergedCell.row + rs\n\n            for (let cs = 0; cs < currentMergedCell.colspan; cs++) {\n              const col = currentMergedCell.col + cs\n\n              notRender.push(`${row},${col}`)\n            }\n          }\n        }\n      }\n\n      for (let i = 0; i < data.length; i++) {\n        html.push('<tr>')\n\n        const columns = columnsArray.flat(1)\n\n        columns.sort((c1, c2) => c1.colspanIndex - c2.colspanIndex)\n\n        for (let j = 0; j < columns.length; j++) {\n          if (columns[j].colspanGroup > 0) continue\n\n          let rowspan = 0\n          let colspan = 0\n\n          if (this.mergedCells) {\n            for (let mc = 0; mc < this.mergedCells.length; mc++) {\n              const currentMergedCell = this.mergedCells[mc]\n\n              if (currentMergedCell.col === j && currentMergedCell.row === i) {\n                rowspan = currentMergedCell.rowspan\n                colspan = currentMergedCell.colspan\n              }\n            }\n          }\n\n          if (\n            canPrint(columns[j]) &&\n            (\n              !notRender.includes(`${i},${j}`) ||\n              rowspan > 0 && colspan > 0\n            )\n          ) {\n            if (rowspan > 0 && colspan > 0) {\n              html.push(`<td ${Utils.sprintf(' rowspan=\"%s\"', rowspan)} ${Utils.sprintf(' colspan=\"%s\"', colspan)}>`, formatValue(data[i], i, columns[j]), '</td>')\n            } else {\n              html.push('<td>', formatValue(data[i], i, columns[j]), '</td>')\n            }\n          }\n        }\n\n        html.push('</tr>')\n      }\n\n      html.push('</tbody>')\n      if (this.options.showFooter) {\n        html.push('<footer><tr>')\n\n        for (const columns of columnsArray) {\n          for (let h = 0; h < columns.length; h++) {\n            if (canPrint(columns)) {\n              const footerData = Utils.trToData(columns, this.$el.find('>tfoot>tr'))\n              const footerValue = Utils.calculateObjectValue(columns[h], columns[h].footerFormatter, [data], footerData[0] && footerData[0][columns[h].field] || '')\n\n              html.push(`<th>${footerValue}</th>`)\n            }\n          }\n        }\n\n        html.push('</tr></footer>')\n      }\n      html.push('</table>')\n      return html.join('')\n    }\n\n    const sortRows = (data, colName, sortOrder) => {\n      if (!colName) {\n        return data\n      }\n      let reverse = sortOrder !== 'asc'\n\n      reverse = -(+reverse || -1)\n      return data.sort((a, b) => reverse * a[colName].localeCompare(b[colName]))\n    }\n\n    const filterRow = (row, filters) => {\n      for (let index = 0; index < filters.length; ++index) {\n        if (row[filters[index].colName] !== filters[index].value) {\n          return false\n        }\n      }\n      return true\n    }\n\n    const filterRows = (data, filters) => data.filter(row => filterRow(row, filters))\n    const getColumnFilters = columns => !columns || !columns[0] ? [] : columns[0].filter(col => col.printFilter).map(col => ({\n      colName: col.field,\n      value: col.printFilter\n    }))\n\n    data = filterRows(data, getColumnFilters(this.options.columns))\n    data = sortRows(data, this.options.printSortColumn, this.options.printSortOrder)\n    const table = buildTable(data, this.options.columns)\n    const newWin = window.open('')\n    const printStyles = typeof this.options.printStyles === 'string' ?\n      this.options.printStyles.replace(/\\[|\\]| /g, '').toLowerCase().split(',') :\n      this.options.printStyles\n    const styles = printStyles.map(it =>\n      `<link rel=\"stylesheet\" href=\"${it}\" />`).join('')\n\n    const calculatedPrintPage = Utils.calculateObjectValue(this, this.options.printPageBuilder,\n      [table, styles], printPageBuilderDefault(table, styles))\n    const startPrint = () => {\n      newWin.focus()\n      newWin.print()\n      newWin.close()\n    }\n\n    newWin.document.write(calculatedPrintPage)\n    newWin.document.close()\n\n    if (printStyles.length) {\n      const links = document.getElementsByTagName('link')\n      const lastLink = links[links.length - 1]\n\n      lastLink.onload = startPrint\n    } else {\n      startPrint()\n    }\n  }\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/reorder-columns/bootstrap-table-reorder-columns.js",
    "content": "/**\r\n * @author: Dennis Hernández\r\n * @update: https://github.com/wenzhixin\r\n * @version: v1.2.0\r\n */\r\n\r\n$.akottr.dragtable.prototype._restoreState = function (persistObj) {\r\n  let i = 0\r\n\r\n  for (const [field, value] of Object.entries(persistObj)) {\r\n    const $th = this.originalTable.el.find(`th[data-field=\"${field}\"]`)\r\n\r\n    if (!$th.length) {\r\n      i++\r\n      continue\r\n    }\r\n\r\n    this.originalTable.startIndex = $th.prevAll().length + 1\r\n    this.originalTable.endIndex = parseInt(value, 10) + 1 - i\r\n    this._bubbleCols()\r\n  }\r\n}\r\n\r\n// From MDN site, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter\r\nconst filterFn = () => {\r\n  if (!Array.prototype.filter) {\r\n    Array.prototype.filter = function (fun/* , thisArg*/) {\r\n      if (this === undefined || this === null) {\r\n        throw new TypeError()\r\n      }\r\n\r\n      const t = Object(this)\r\n      const len = t.length >>> 0\r\n\r\n      if (typeof fun !== 'function') {\r\n        throw new TypeError()\r\n      }\r\n\r\n      const res = []\r\n      const thisArg = arguments.length >= 2 ? arguments[1] : undefined\r\n\r\n      for (let i = 0; i < len; i++) {\r\n        if (i in t) {\r\n          const val = t[i]\r\n\r\n          // NOTE: Technically this should Object.defineProperty at\r\n          //       the next index, as push can be affected by\r\n          //       properties on Object.prototype and Array.prototype.\r\n          //       But this method's new, and collisions should be\r\n          //       rare, so use the more-compatible alternative.\r\n          if (fun.call(thisArg, val, i, t)) {\r\n            res.push(val)\r\n          }\r\n        }\r\n      }\r\n\r\n      return res\r\n    }\r\n  }\r\n}\r\n\r\nObject.assign($.fn.bootstrapTable.defaults, {\r\n  reorderableColumns: false,\r\n  maxMovingRows: 10,\r\n  // eslint-disable-next-line no-unused-vars\r\n  onReorderColumn (headerFields) {\r\n    return false\r\n  },\r\n  dragaccept: null\r\n})\r\n\r\nObject.assign($.fn.bootstrapTable.events, {\r\n  'reorder-column.bs.table': 'onReorderColumn'\r\n})\r\n\r\n$.fn.bootstrapTable.methods.push('orderColumns')\r\n\r\n$.BootstrapTable = class extends $.BootstrapTable {\r\n  initHeader (...args) {\r\n    super.initHeader(...args)\r\n\r\n    if (!this.options.reorderableColumns) {\r\n      return\r\n    }\r\n\r\n    this.makeColumnsReorderable()\r\n  }\r\n\r\n  _toggleColumn (...args) {\r\n    super._toggleColumn(...args)\r\n\r\n    if (!this.options.reorderableColumns) {\r\n      return\r\n    }\r\n\r\n    this.makeColumnsReorderable()\r\n  }\r\n\r\n  toggleView (...args) {\r\n    super.toggleView(...args)\r\n\r\n    if (!this.options.reorderableColumns) {\r\n      return\r\n    }\r\n\r\n    if (this.options.cardView) {\r\n      return\r\n    }\r\n\r\n    this.makeColumnsReorderable()\r\n  }\r\n\r\n  resetView (...args) {\r\n    super.resetView(...args)\r\n\r\n    if (!this.options.reorderableColumns) {\r\n      return\r\n    }\r\n\r\n    this.makeColumnsReorderable()\r\n  }\r\n\r\n  makeColumnsReorderable (order = null) {\r\n    try {\r\n      $(this.$el).dragtable('destroy')\r\n    } catch (e) {\r\n      console.error(e)\r\n    }\r\n    $(this.$el).dragtable({\r\n      maxMovingRows: this.options.maxMovingRows,\r\n      dragaccept: this.options.dragaccept,\r\n      clickDelay: 200,\r\n      dragHandle: '.th-inner',\r\n      restoreState: order ? order : this.columnsSortOrder,\r\n      beforeStop: table => {\r\n        const sortOrder = {}\r\n\r\n        table.el.find('th').each((i, el) => {\r\n          if (el.dataset.field !== undefined) {\r\n            sortOrder[el.dataset.field] = i\r\n          }\r\n        })\r\n\r\n        this.columnsSortOrder = sortOrder\r\n        if (this.options.cookie) {\r\n          this.persistReorderColumnsState(this)\r\n        }\r\n\r\n        const ths = []\r\n        const formatters = []\r\n        const columns = []\r\n        let columnsHidden = []\r\n        let columnIndex = -1\r\n        const optionsColumns = []\r\n\r\n        this.$header.find('th:not(.detail)').each((i, el) => {\r\n          ths.push($(el).data('field'))\r\n          formatters.push($(el).data('formatter'))\r\n        })\r\n\r\n        // Exist columns not shown\r\n        if (ths.length < this.columns.length) {\r\n          columnsHidden = this.columns.filter(column => !column.visible)\r\n          for (let i = 0; i < columnsHidden.length; i++) {\r\n            ths.push(columnsHidden[i].field)\r\n            formatters.push(columnsHidden[i].formatter)\r\n          }\r\n        }\r\n\r\n        for (let i = 0; i < ths.length; i++) {\r\n          columnIndex = this.fieldsColumnsIndex[ths[i]]\r\n          if (columnIndex !== -1) {\r\n            this.fieldsColumnsIndex[ths[i]] = i\r\n            this.columns[columnIndex].fieldIndex = i\r\n            columns.push(this.columns[columnIndex])\r\n          }\r\n        }\r\n\r\n        this.columns = columns\r\n\r\n        filterFn() // Support <IE9\r\n        for (const column of this.columns) {\r\n          let found = false\r\n          const field = column.field\r\n\r\n          this.options.columns[0].filter(item => {\r\n            if (!found && item['field'] === field) {\r\n              optionsColumns.push(item)\r\n              found = true\r\n              return false\r\n            }\r\n            return true\r\n          })\r\n        }\r\n\r\n        this.options.columns[0] = optionsColumns\r\n\r\n        this.header.fields = ths\r\n        this.header.formatters = formatters\r\n        this.initHeader()\r\n        this.initToolbar()\r\n        this.initSearchText()\r\n        this.initBody()\r\n        this.resetView()\r\n        this.trigger('reorder-column', ths)\r\n      }\r\n    })\r\n  }\r\n\r\n  orderColumns (order) {\r\n    this.columnsSortOrder = order\r\n    this.makeColumnsReorderable()\r\n  }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/reorder-columns/jquery.dragtable.js",
    "content": "/**\r\n * Minified by jsDelivr using Terser v5.3.5.\r\n * Original file: /gh/akottr/dragtable@master/jquery.dragtable.js\r\n *\r\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\r\n */\r\n/*!\r\n * dragtable\r\n *\r\n * @Version 2.0.15\r\n *\r\n * Copyright (c) 2010-2013, Andres akottr@gmail.com\r\n * Dual licensed under the MIT (MIT-LICENSE.txt)\r\n * and GPL (GPL-LICENSE.txt) licenses.\r\n *\r\n * Inspired by the the dragtable from Dan Vanderkam (danvk.org/dragtable/)\r\n * Thanks to the jquery and jqueryui comitters\r\n *\r\n * Any comment, bug report, feature-request is welcome\r\n * Feel free to contact me.\r\n */\r\n!function(e){e.widget(\"akottr.dragtable\",{options:{revert:!1,dragHandle:\".table-handle\",maxMovingRows:40,excludeFooter:!1,onlyHeaderThreshold:100,dragaccept:null,persistState:null,restoreState:null,exact:!0,clickDelay:10,containment:null,cursor:\"move\",cursorAt:!1,distance:0,tolerance:\"pointer\",axis:\"x\",beforeStart:e.noop,beforeMoving:e.noop,beforeReorganize:e.noop,beforeStop:e.noop},originalTable:{el:null,selectedHandle:null,sortOrder:null,startIndex:0,endIndex:0},sortableTable:{el:e(),selectedHandle:e(),movingRow:e()},persistState:function(){var t=this;this.originalTable.el.find(\"th\").each((function(e){\"\"!==this.id&&(t.originalTable.sortOrder[this.id]=e)})),e.ajax({url:this.options.persistState,data:this.originalTable.sortOrder})},_restoreState:function(t){for(var i in t)this.originalTable.startIndex=e(\"#\"+i).closest(\"th\").prevAll().length+1,this.originalTable.endIndex=parseInt(t[i],10)+1,this._bubbleCols()},_bubbleCols:function(){var e,t,i,o,a=this.originalTable.startIndex,l=this.originalTable.endIndex,s=this.originalTable.el.children();if(this.options.excludeFooter&&(s=s.not(\"tfoot\")),a<l)for(e=a;e<l;e++)for(i=s.find(\"> tr > td:nth-child(\"+e+\")\").add(s.find(\"> tr > th:nth-child(\"+e+\")\")),o=s.find(\"> tr > td:nth-child(\"+(e+1)+\")\").add(s.find(\"> tr > th:nth-child(\"+(e+1)+\")\")),t=0;t<i.length;t++)n(i[t],o[t]);else for(e=a;e>l;e--)for(i=s.find(\"> tr > td:nth-child(\"+e+\")\").add(s.find(\"> tr > th:nth-child(\"+e+\")\")),o=s.find(\"> tr > td:nth-child(\"+(e-1)+\")\").add(s.find(\"> tr > th:nth-child(\"+(e-1)+\")\")),t=0;t<i.length;t++)n(i[t],o[t])},_rearrangeTableBackroundProcessing:function(){var n=this;return function(){n._bubbleCols(),n.options.beforeStop(n.originalTable),n.sortableTable.el.remove(),function(){e(\"#__dragtable_disable_text_selection__\").remove(),t?e(document.body).attr(\"onselectstart\",t):e(document.body).removeAttr(\"onselectstart\");i?e(document.body).attr(\"unselectable\",i):e(document.body).removeAttr(\"unselectable\")}(),null!==n.options.persistState&&(e.isFunction(n.options.persistState)?n.options.persistState(n.originalTable):n.persistState())}},_rearrangeTable:function(){var e=this;return function(){e.originalTable.selectedHandle.removeClass(\"dragtable-handle-selected\"),e.sortableTable.el.sortable(\"disable\"),e.sortableTable.el.addClass(\"dragtable-disabled\"),e.options.beforeReorganize(e.originalTable,e.sortableTable),e.originalTable.endIndex=e.sortableTable.movingRow.prevAll().length+1,setTimeout(e._rearrangeTableBackroundProcessing(),50)}},_generateSortable:function(t){!t.cancelBubble&&(t.cancelBubble=!0);for(var i=this,n=this.originalTable.el[0].attributes,o=\"\",a=0;a<n.length;a++)n[a].nodeValue&&\"id\"!=n[a].nodeName&&\"width\"!=n[a].nodeName&&(o+=n[a].nodeName+'=\"'+n[a].nodeValue+'\" ');var l=[],s=[];this.originalTable.el.find(\"tr\").slice(0,this.options.maxMovingRows).each((function(t,i){for(var n=this.attributes,o=\"\",a=0;a<n.length;a++)n[a].nodeValue&&\"id\"!=n[a].nodeName&&(o+=\" \"+n[a].nodeName+'=\"'+n[a].nodeValue+'\"');l.push(o),s.push(e(this).height())}));var r=[],d=0,h=i.originalTable.el.children();if(this.options.excludeFooter&&(h=h.not(\"tfoot\")),h.find(\"> tr > th\").each((function(t,i){var n=e(this).is(\":visible\")?e(this).outerWidth():0;r.push(n),d+=n})),i.options.exact){var c=d-i.originalTable.el.outerWidth();r[0]-=c}var b='<ul class=\"dragtable-sortable\" style=\"position:absolute; width:'+(d+=2)+'px;\">';h.find(\"> tr > th\").each((function(t,n){var a=e(this).is(\":visible\")?e(this).outerWidth():0;b+='<li style=\"width:'+a+'px;\">',b+=\"<table \"+o+\">\";var r=h.find(\"> tr > th:nth-child(\"+(t+1)+\")\");i.options.maxMovingRows>1&&(r=r.add(h.find(\"> tr > td:nth-child(\"+(t+1)+\")\").slice(0,i.options.maxMovingRows-1))),r.each((function(t){var i=e(this).clone().wrap(\"<div></div>\").parent().html();0===i.toLowerCase().indexOf(\"<th\")&&(b+=\"<thead>\"),b+=\"<tr \"+l[t]+'\" style=\"height:'+s[t]+'px;\">',b+=i,0===i.toLowerCase().indexOf(\"<th\")&&(b+=\"</thead>\"),b+=\"</tr>\"})),b+=\"</table>\",b+=\"</li>\"})),b+=\"</ul>\",this.sortableTable.el=this.originalTable.el.before(b).prev(),this.sortableTable.el.find(\"> li > table\").each((function(t,i){e(this).css(\"width\",r[t]+\"px\")})),this.sortableTable.selectedHandle=this.sortableTable.el.find(\"th .dragtable-handle-selected\");var u,g=this.options.dragaccept?\"li:has(\"+this.options.dragaccept+\")\":\"li\";this.sortableTable.el.sortable({items:g,stop:this._rearrangeTable(),revert:this.options.revert,tolerance:this.options.tolerance,containment:this.options.containment,cursor:this.options.cursor,cursorAt:this.options.cursorAt,distance:this.options.distance,axis:this.options.axis}),this.originalTable.startIndex=e(t.target).closest(\"th\").prevAll().length+1,this.options.beforeMoving(this.originalTable,this.sortableTable),this.sortableTable.movingRow=this.sortableTable.el.find(\"> li:nth-child(\"+this.originalTable.startIndex+\")\"),u=e('<style id=\"__dragtable_disable_text_selection__\" type=\"text/css\">body { -ms-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;user-select:none; }</style>'),e(document.head).append(u),e(document.body).attr(\"onselectstart\",\"return false;\").attr(\"unselectable\",\"on\"),window.getSelection?window.getSelection().removeAllRanges():document.selection.empty(),this.sortableTable.movingRow.trigger(e.extend(e.Event(t.type),{which:1,clientX:t.clientX,clientY:t.clientY,pageX:t.pageX,pageY:t.pageY,screenX:t.screenX,screenY:t.screenY}));var p=this.sortableTable.el.find(\".ui-sortable-placeholder\");!p.height()<=0&&p.css(\"height\",this.sortableTable.el.find(\".ui-sortable-helper\").height()),p.html('<div class=\"outer\" style=\"height:100%;\"><div class=\"inner\" style=\"height:100%;\"></div></div>')},bindTo:{},_create:function(){this.originalTable={el:this.element,selectedHandle:e(),sortOrder:{},startIndex:0,endIndex:0},this.bindTo=this.originalTable.el.find(\"th\"),this.options.dragaccept&&(this.bindTo=this.bindTo.filter(this.options.dragaccept)),this.bindTo.find(this.options.dragHandle).length>0&&(this.bindTo=this.bindTo.find(this.options.dragHandle)),null!==this.options.restoreState&&(e.isFunction(this.options.restoreState)?this.options.restoreState(this.originalTable):this._restoreState(this.options.restoreState));var t=this;this.bindTo.mousedown((function(i){1===i.which&&!1!==t.options.beforeStart(t.originalTable)&&(clearTimeout(this.downTimer),this.downTimer=setTimeout((function(){t.originalTable.selectedHandle=e(this),t.originalTable.selectedHandle.addClass(\"dragtable-handle-selected\"),t._generateSortable(i)}),t.options.clickDelay))})).mouseup((function(e){clearTimeout(this.downTimer)}))},redraw:function(){this.destroy(),this._create()},destroy:function(){this.bindTo.unbind(\"mousedown\"),e.Widget.prototype.destroy.apply(this,arguments)}});var t=e(document.body).attr(\"onselectstart\"),i=e(document.body).attr(\"unselectable\");function n(e,t){var i=e.parentNode,n=e.nextSibling===t?e:e.nextSibling;t.parentNode.insertBefore(e,t),i.insertBefore(t,n)}}(jQuery);\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/reorder-rows/bootstrap-table-reorder-rows.js",
    "content": "/**\n * @author: Dennis Hernández\n * @update zhixin wen <wenzhixin2010@gmail.com>\n */\n\nconst rowAttr = (row, index) => ({\n  id: `customId_${index}`\n})\n\nObject.assign($.fn.bootstrapTable.defaults, {\n  reorderableRows: false,\n  onDragStyle: null,\n  onDropStyle: null,\n  onDragClass: 'reorder-rows-on-drag-class',\n  dragHandle: '>tbody>tr>td:not(.bs-checkbox)',\n  useRowAttrFunc: false,\n  // eslint-disable-next-line no-unused-vars\n  onReorderRowsDrag (row) {\n    return false\n  },\n  // eslint-disable-next-line no-unused-vars\n  onReorderRowsDrop (row) {\n    return false\n  },\n  // eslint-disable-next-line no-unused-vars\n  onReorderRow (newData) {\n    return false\n  },\n  onDragStop () {},\n  onAllowDrop () {\n    return true\n  }\n})\n\nObject.assign($.fn.bootstrapTable.events, {\n  'reorder-row.bs.table': 'onReorderRow'\n})\n\n$.BootstrapTable = class extends $.BootstrapTable {\n  init (...args) {\n    if (!this.options.reorderableRows) {\n      super.init(...args)\n      return\n    }\n\n    if (this.options.useRowAttrFunc) {\n      this.options.rowAttributes = rowAttr\n    }\n\n    const onPostBody = this.options.onPostBody\n\n    this.options.onPostBody = () => {\n      setTimeout(() => {\n        this.makeRowsReorderable()\n        onPostBody.call(this.options, this.options.data)\n      }, 1)\n    }\n\n    super.init(...args)\n  }\n\n  makeRowsReorderable () {\n    this.$el.tableDnD({\n      onDragStyle: this.options.onDragStyle,\n      onDropStyle: this.options.onDropStyle,\n      onDragClass: this.options.onDragClass,\n      onAllowDrop: (hoveredRow, draggedRow) => this.onAllowDrop(hoveredRow, draggedRow),\n      onDragStop: (table, draggedRow) => this.onDragStop(table, draggedRow),\n      onDragStart: (table, droppedRow) => this.onDropStart(table, droppedRow),\n      onDrop: (table, droppedRow) => this.onDrop(table, droppedRow),\n      dragHandle: this.options.dragHandle\n    })\n  }\n\n  onDropStart (table, draggingTd) {\n    this.$draggingTd = $(draggingTd).css('cursor', 'move')\n    this.draggingIndex = $(this.$draggingTd.parent()).data('index')\n    // Call the user defined function\n    this.options.onReorderRowsDrag(this.data[this.draggingIndex])\n  }\n\n  onDragStop (table, draggedRow) {\n    const rowIndexDraggedRow = $(draggedRow).data('index')\n    const draggedRowItem = this.data[rowIndexDraggedRow]\n\n    this.options.onDragStop(table, draggedRowItem, draggedRow)\n  }\n\n  onAllowDrop (hoveredRow, draggedRow) {\n    const rowIndexDraggedRow = $(draggedRow).data('index')\n    const rowIndexHoveredRow = $(hoveredRow).data('index')\n    const draggedRowItem = this.data[rowIndexDraggedRow]\n    const hoveredRowItem = this.data[rowIndexHoveredRow]\n\n    return this.options.onAllowDrop(hoveredRowItem, draggedRowItem, hoveredRow, draggedRow)\n  }\n\n  onDrop (table) {\n    this.$draggingTd.css('cursor', '')\n    const pageNum = this.options.pageNumber\n    const pageSize = this.options.pageSize\n    const newData = []\n\n    for (let i = 0; i < table.tBodies[0].rows.length; i++) {\n      const $tr = $(table.tBodies[0].rows[i])\n\n      newData.push(this.data[$tr.data('index')])\n      $tr.data('index', i)\n    }\n\n    const draggingRow = this.data[this.draggingIndex]\n    const droppedIndex = newData.indexOf(this.data[this.draggingIndex])\n    const droppedRow = this.data[droppedIndex]\n    const index = (pageNum - 1) * pageSize + this.options.data.indexOf(this.data[droppedIndex])\n\n    this.options.data.splice(this.options.data.indexOf(draggingRow), 1)\n    this.options.data.splice(index, 0, draggingRow)\n\n    this.initSearch()\n\n    if (this.options.sidePagination === 'server') {\n      this.data = [...this.options.data]\n    }\n\n    // Call the user defined function\n    this.options.onReorderRowsDrop(droppedRow)\n\n    // Call the event reorder-row\n    this.trigger('reorder-row', newData, draggingRow, droppedRow)\n  }\n\n  initSearch () {\n    this.ignoreInitSort = true\n    super.initSearch()\n  }\n\n  initSort () {\n    if (this.ignoreInitSort) {\n      this.ignoreInitSort = false\n      return\n    }\n\n    super.initSort()\n  }\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/reorder-rows/jquery.tablednd.js",
    "content": "/**\n * TableDnD plug-in for JQuery, allows you to drag and drop table rows\n * You can set up various options to control how the system will work\n * Copyright (c) Denis Howlett <denish@isocra.com>\n * License: MIT.\n * See https://github.com/isocra/TableDnD\n */\n!function ($, window, document, undefined) {\n\nvar startEvent = 'touchstart mousedown',\n    moveEvent  = 'touchmove mousemove',\n    endEvent   = 'touchend mouseup';\n\n$(document).ready(function () {\n    function parseStyle(css) {\n        var objMap = {},\n            parts = css.match(/([^;:]+)/g) || [];\n        while (parts.length)\n            objMap[parts.shift()] = parts.shift().trim();\n\n        return objMap;\n    }\n    $('table').each(function () {\n        if ($(this).data('table') === 'dnd') {\n\n            $(this).tableDnD({\n                onDragStyle: $(this).data('ondragstyle') && parseStyle($(this).data('ondragstyle')) || null,\n                onDropStyle: $(this).data('ondropstyle') && parseStyle($(this).data('ondropstyle')) || null,\n                onDragClass: $(this).data('ondragclass') === undefined && \"tDnD_whileDrag\" || $(this).data('ondragclass'),\n                onDrop: $(this).data('ondrop') && new Function('table', 'row', $(this).data('ondrop')), // 'return eval(\"'+$(this).data('ondrop')+'\");') || null,\n                onDragStart: $(this).data('ondragstart') && new Function('table', 'row' ,$(this).data('ondragstart')), // 'return eval(\"'+$(this).data('ondragstart')+'\");') || null,\n                onDragStop: $(this).data('ondragstop') && new Function('table', 'row' ,$(this).data('ondragstop')),\n                scrollAmount: $(this).data('scrollamount') || 5,\n                sensitivity: $(this).data('sensitivity') || 10,\n                hierarchyLevel: $(this).data('hierarchylevel') || 0,\n                indentArtifact: $(this).data('indentartifact') || '<div class=\"indent\">&nbsp;</div>',\n                autoWidthAdjust: $(this).data('autowidthadjust') || true,\n                autoCleanRelations: $(this).data('autocleanrelations') || true,\n                jsonPretifySeparator: $(this).data('jsonpretifyseparator') || '\\t',\n                serializeRegexp: $(this).data('serializeregexp') && new RegExp($(this).data('serializeregexp')) || /[^\\-]*$/,\n                serializeParamName: $(this).data('serializeparamname') || false,\n                dragHandle: $(this).data('draghandle') || null\n            });\n        }\n\n\n    });\n});\n\njQuery.tableDnD = {\n    /** Keep hold of the current table being dragged */\n    currentTable: null,\n    /** Keep hold of the current drag object if any */\n    dragObject: null,\n    /** The current mouse offset */\n    mouseOffset: null,\n    /** Remember the old value of X and Y so that we don't do too much processing */\n    oldX: 0,\n    oldY: 0,\n\n    /** Actually build the structure */\n    build: function(options) {\n        // Set up the defaults if any\n\n        this.each(function() {\n            // This is bound to each matching table, set up the defaults and override with user options\n            this.tableDnDConfig = $.extend({\n                onDragStyle: null,\n                onDropStyle: null,\n                // Add in the default class for whileDragging\n                onDragClass: \"tDnD_whileDrag\",\n                onDrop: null,\n                onDragStart: null,\n                onDragStop: null,\n                scrollAmount: 5,\n                /** Sensitivity setting will throttle the trigger rate for movement detection */\n                sensitivity: 10,\n                /** Hierarchy level to support parent child. 0 switches this functionality off */\n                hierarchyLevel: 0,\n                /** The html artifact to prepend the first cell with as indentation */\n                indentArtifact: '<div class=\"indent\">&nbsp;</div>',\n                /** Automatically adjust width of first cell */\n                autoWidthAdjust: true,\n                /** Automatic clean-up to ensure relationship integrity */\n                autoCleanRelations: true,\n                /** Specify a number (4) as number of spaces or any indent string for JSON.stringify */\n                jsonPretifySeparator: '\\t',\n                /** The regular expression to use to trim row IDs */\n                serializeRegexp: /[^\\-]*$/,\n                /** If you want to specify another parameter name instead of the table ID */\n                serializeParamName: false,\n                /** If you give the name of a class here, then only Cells with this class will be draggable */\n                dragHandle: null\n            }, options || {});\n\n            // Now make the rows draggable\n            $.tableDnD.makeDraggable(this);\n            // Prepare hierarchy support\n            this.tableDnDConfig.hierarchyLevel\n                && $.tableDnD.makeIndented(this);\n        });\n\n        // Don't break the chain\n        return this;\n    },\n    makeIndented: function (table) {\n        var config = table.tableDnDConfig,\n            rows = table.rows,\n            firstCell = $(rows).first().find('td:first')[0],\n            indentLevel = 0,\n            cellWidth = 0,\n            longestCell,\n            tableStyle;\n\n        if ($(table).hasClass('indtd'))\n            return null;\n\n        tableStyle = $(table).addClass('indtd').attr('style');\n        $(table).css({whiteSpace: \"nowrap\"});\n\n        for (var w = 0; w < rows.length; w++) {\n            if (cellWidth < $(rows[w]).find('td:first').text().length) {\n                cellWidth = $(rows[w]).find('td:first').text().length;\n                longestCell = w;\n            }\n        }\n        $(firstCell).css({width: 'auto'});\n        for (w = 0; w < config.hierarchyLevel; w++)\n            $(rows[longestCell]).find('td:first').prepend(config.indentArtifact);\n        firstCell && $(firstCell).css({width: firstCell.offsetWidth});\n        tableStyle && $(table).css(tableStyle);\n\n        for (w = 0; w < config.hierarchyLevel; w++)\n            $(rows[longestCell]).find('td:first').children(':first').remove();\n\n        config.hierarchyLevel\n            && $(rows).each(function () {\n                indentLevel = $(this).data('level') || 0;\n                indentLevel <= config.hierarchyLevel\n                    && $(this).data('level', indentLevel)\n                    || $(this).data('level', 0);\n                for (var i = 0; i < $(this).data('level'); i++)\n                    $(this).find('td:first').prepend(config.indentArtifact);\n            });\n\n        return this;\n    },\n    /** This function makes all the rows on the table draggable apart from those marked as \"NoDrag\" */\n    makeDraggable: function(table) {\n        var config = table.tableDnDConfig;\n\n        config.dragHandle\n            // We only need to add the event to the specified cells\n            && $(config.dragHandle, table).each(function() {\n                if (! $(this).hasClass(\"nodrag\")) {\n                    // The cell is bound to \"this\"\n                    $(this).bind(startEvent, function(e) {\n                        if (e.target.tagName === \"TD\" && event.target.className !== \"nodrag\") {\n                    \t    $.tableDnD.initialiseDrag($(this).parents('tr')[0], table, this, e, config);\n                            return false;\n                \t    }\n                        return true;\n                    });\n                }\n            })\n            // For backwards compatibility, we add the event to the whole row\n            // get all the rows as a wrapped set\n            || $(table.rows).each(function() {\n                // Iterate through each row, the row is bound to \"this\"\n                if (! $(this).hasClass(\"nodrag\")) {\n                    $(this).bind(startEvent, function(e) {\n                        if (e.target.tagName === \"TD\" && event.target.className !== \"nodrag\") {\n                            $.tableDnD.initialiseDrag(this, table, this, e, config);\n                            return false;\n                        }\n                    }).css(\"cursor\", \"move\"); // Store the tableDnD object\n                } else {\n                    $(this).css(\"cursor\", \"\"); // Remove the cursor if we don't have the nodrag class\n                }\n            });\n    },\n    currentOrder: function() {\n        var rows = this.currentTable.rows;\n        return $.map(rows, function (val) {\n            return ($(val).data('level') + val.id).replace(/\\s/g, '');\n        }).join('');\n    },\n    initialiseDrag: function(dragObject, table, target, e, config) {\n        this.dragObject    = dragObject;\n        this.currentTable  = table;\n        this.mouseOffset   = this.getMouseOffset(target, e);\n        this.originalOrder = this.currentOrder();\n\n        // Now we need to capture the mouse up and mouse move event\n        // We can use bind so that we don't interfere with other event handlers\n        $(document)\n            .bind(moveEvent, this.mousemove)\n            .bind(endEvent, this.mouseup);\n\n        // Call the onDragStart method if there is one\n        config.onDragStart\n            && config.onDragStart(table, target);\n    },\n    updateTables: function() {\n        this.each(function() {\n            // this is now bound to each matching table\n            if (this.tableDnDConfig)\n                $.tableDnD.makeDraggable(this);\n        });\n    },\n    /** Get the mouse coordinates from the event (allowing for browser differences) */\n    mouseCoords: function(e) {\n        if (e.originalEvent.changedTouches)\n            return {\n                x: e.originalEvent.changedTouches[0].clientX,\n                y: e.originalEvent.changedTouches[0].clientY\n            };\n\n        if(e.pageX || e.pageY)\n            return {\n                x: e.pageX,\n                y: e.pageY\n            };\n\n        return {\n            x: e.clientX + document.body.scrollLeft - document.body.clientLeft,\n            y: e.clientY + document.body.scrollTop  - document.body.clientTop\n        };\n    },\n    /** Given a target element and a mouse eent, get the mouse offset from that element.\n     To do this we need the element's position and the mouse position */\n    getMouseOffset: function(target, e) {\n        var mousePos,\n            docPos;\n\n        e = e || window.event;\n\n        docPos    = this.getPosition(target);\n        mousePos  = this.mouseCoords(e);\n\n        return {\n            x: mousePos.x - docPos.x,\n            y: mousePos.y - docPos.y\n        };\n    },\n    /** Get the position of an element by going up the DOM tree and adding up all the offsets */\n    getPosition: function(element) {\n        var left = 0,\n            top  = 0;\n\n        // Safari fix -- thanks to Luis Chato for this!\n        // Safari 2 doesn't correctly grab the offsetTop of a table row\n        // this is detailed here:\n        // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/\n        // the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.\n        // note that firefox will return a text node as a first child, so designing a more thorough\n        // solution may need to take that into account, for now this seems to work in firefox, safari, ie\n        if (element.offsetHeight === 0)\n            element = element.firstChild; // a table cell\n\n        while (element.offsetParent) {\n            left   += element.offsetLeft;\n            top    += element.offsetTop;\n            element = element.offsetParent;\n        }\n\n        left += element.offsetLeft;\n        top  += element.offsetTop;\n\n        return {\n            x: left,\n            y: top\n        };\n    },\n    autoScroll: function (mousePos) {\n      var config       = this.currentTable.tableDnDConfig,\n          yOffset      = window.pageYOffset,\n          windowHeight = window.innerHeight\n            ? window.innerHeight\n            : document.documentElement.clientHeight\n            ? document.documentElement.clientHeight\n            : document.body.clientHeight;\n\n        // Windows version\n        // yOffset=document.body.scrollTop;\n        if (document.all)\n            if (typeof document.compatMode !== 'undefined'\n                && document.compatMode !== 'BackCompat')\n                yOffset = document.documentElement.scrollTop;\n            else if (typeof document.body !== 'undefined')\n                yOffset = document.body.scrollTop;\n\n        mousePos.y - yOffset < config.scrollAmount\n            && window.scrollBy(0, - config.scrollAmount)\n        || windowHeight - (mousePos.y - yOffset) < config.scrollAmount\n            && window.scrollBy(0, config.scrollAmount);\n\n    },\n    moveVerticle: function (moving, currentRow) {\n\n        if (0 !== moving.vertical\n            // If we're over a row then move the dragged row to there so that the user sees the\n            // effect dynamically\n            && currentRow\n            && this.dragObject !== currentRow\n            && this.dragObject.parentNode === currentRow.parentNode)\n            0 > moving.vertical\n                && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow.nextSibling)\n            || 0 < moving.vertical\n                && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow);\n\n    },\n    moveHorizontal: function (moving, currentRow) {\n        var config       = this.currentTable.tableDnDConfig,\n            currentLevel;\n\n        if (!config.hierarchyLevel\n            || 0 === moving.horizontal\n            // We only care if moving left or right on the current row\n            || !currentRow\n            || this.dragObject !== currentRow)\n                return null;\n\n            currentLevel = $(currentRow).data('level');\n\n            0 < moving.horizontal\n                && currentLevel > 0\n                && $(currentRow).find('td:first').children(':first').remove()\n                && $(currentRow).data('level', --currentLevel);\n\n            0 > moving.horizontal\n                && currentLevel < config.hierarchyLevel\n                && $(currentRow).prev().data('level') >= currentLevel\n                && $(currentRow).children(':first').prepend(config.indentArtifact)\n                && $(currentRow).data('level', ++currentLevel);\n\n    },\n    mousemove: function(e) {\n        var dragObj      = $($.tableDnD.dragObject),\n            config       = $.tableDnD.currentTable.tableDnDConfig,\n            currentRow,\n            mousePos,\n            moving,\n            x,\n            y;\n\n        e && e.preventDefault();\n\n        if (!$.tableDnD.dragObject)\n            return false;\n\n        // prevent touch device screen scrolling\n        e.type === 'touchmove'\n            && event.preventDefault(); // TODO verify this is event and not really e\n\n        // update the style to show we're dragging\n        config.onDragClass\n            && dragObj.addClass(config.onDragClass)\n            || dragObj.css(config.onDragStyle);\n\n        mousePos = $.tableDnD.mouseCoords(e);\n        x = mousePos.x - $.tableDnD.mouseOffset.x;\n        y = mousePos.y - $.tableDnD.mouseOffset.y;\n\n        // auto scroll the window\n        $.tableDnD.autoScroll(mousePos);\n\n        currentRow = $.tableDnD.findDropTargetRow(dragObj, y);\n        moving = $.tableDnD.findDragDirection(x, y);\n\n        $.tableDnD.moveVerticle(moving, currentRow);\n        $.tableDnD.moveHorizontal(moving, currentRow);\n\n        return false;\n    },\n    findDragDirection: function (x,y) {\n        var sensitivity = this.currentTable.tableDnDConfig.sensitivity,\n            oldX        = this.oldX,\n            oldY        = this.oldY,\n            xMin        = oldX - sensitivity,\n            xMax        = oldX + sensitivity,\n            yMin        = oldY - sensitivity,\n            yMax        = oldY + sensitivity,\n            moving      = {\n                horizontal: x >= xMin && x <= xMax ? 0 : x > oldX ? -1 : 1,\n                vertical  : y >= yMin && y <= yMax ? 0 : y > oldY ? -1 : 1\n            };\n\n        // update the old value\n        if (moving.horizontal !== 0)\n            this.oldX    = x;\n        if (moving.vertical   !== 0)\n            this.oldY    = y;\n\n        return moving;\n    },\n    /** We're only worried about the y position really, because we can only move rows up and down */\n    findDropTargetRow: function(draggedRow, y) {\n        var rowHeight = 0,\n            rows      = this.currentTable.rows,\n            config    = this.currentTable.tableDnDConfig,\n            rowY      = 0,\n            row       = null;\n\n        for (var i = 0; i < rows.length; i++) {\n            row       = rows[i];\n            rowY      = this.getPosition(row).y;\n            rowHeight = parseInt(row.offsetHeight) / 2;\n            if (row.offsetHeight === 0) {\n                rowY      = this.getPosition(row.firstChild).y;\n                rowHeight = parseInt(row.firstChild.offsetHeight) / 2;\n            }\n            // Because we always have to insert before, we need to offset the height a bit\n            if (y > (rowY - rowHeight) && y < (rowY + rowHeight))\n                // that's the row we're over\n                // If it's the same as the current row, ignore it\n                if (draggedRow.is(row)\n                    || (config.onAllowDrop\n                    && !config.onAllowDrop(draggedRow, row))\n                    // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic)\n                    || $(row).hasClass(\"nodrop\"))\n                        return null;\n                else\n                    return row;\n        }\n        return null;\n    },\n    processMouseup: function() {\n        if (!this.currentTable || !this.dragObject)\n            return null;\n\n        var config      = this.currentTable.tableDnDConfig,\n            droppedRow  = this.dragObject,\n            parentLevel = 0,\n            myLevel     = 0;\n\n        // Unbind the event handlers\n        $(document)\n            .unbind(moveEvent, this.mousemove)\n            .unbind(endEvent,  this.mouseup);\n\n        config.hierarchyLevel\n            && config.autoCleanRelations\n            && $(this.currentTable.rows).first().find('td:first').children().each(function () {\n                myLevel = $(this).parents('tr:first').data('level');\n                myLevel\n                    && $(this).parents('tr:first').data('level', --myLevel)\n                    && $(this).remove();\n            })\n            && config.hierarchyLevel > 1\n            && $(this.currentTable.rows).each(function () {\n                myLevel = $(this).data('level');\n                if (myLevel > 1) {\n                    parentLevel = $(this).prev().data('level');\n                    while (myLevel > parentLevel + 1) {\n                        $(this).find('td:first').children(':first').remove();\n                        $(this).data('level', --myLevel);\n                    }\n                }\n            });\n\n        // If we have a dragObject, then we need to release it,\n        // The row will already have been moved to the right place so we just reset stuff\n        config.onDragClass\n            && $(droppedRow).removeClass(config.onDragClass)\n            || $(droppedRow).css(config.onDropStyle);\n\n        this.dragObject = null;\n        // Call the onDrop method if there is one\n        config.onDrop\n            && this.originalOrder !== this.currentOrder()\n            && $(droppedRow).hide().fadeIn('fast')\n            && config.onDrop(this.currentTable, droppedRow);\n\n        // Call the onDragStop method if there is one\n        config.onDragStop\n            && config.onDragStop(this.currentTable, droppedRow);\n\n        this.currentTable = null; // let go of the table too\n    },\n    mouseup: function(e) {\n        e && e.preventDefault();\n        $.tableDnD.processMouseup();\n        return false;\n    },\n    jsonize: function(pretify) {\n        var table = this.currentTable;\n        if (pretify)\n            return JSON.stringify(\n                this.tableData(table),\n                null,\n                table.tableDnDConfig.jsonPretifySeparator\n            );\n        return JSON.stringify(this.tableData(table));\n    },\n    serialize: function() {\n        return $.param(this.tableData(this.currentTable));\n    },\n    serializeTable: function(table) {\n        var result = \"\";\n        var paramName = table.tableDnDConfig.serializeParamName || table.id;\n        var rows = table.rows;\n        for (var i=0; i<rows.length; i++) {\n            if (result.length > 0) result += \"&\";\n            var rowId = rows[i].id;\n            if (rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) {\n                rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0];\n                result += paramName + '[]=' + rowId;\n            }\n        }\n        return result;\n    },\n    serializeTables: function() {\n        var result = [];\n        $('table').each(function() {\n            this.id && result.push($.param($.tableDnD.tableData(this)));\n        });\n        return result.join('&');\n    },\n    tableData: function (table) {\n        var config = table.tableDnDConfig,\n            previousIDs  = [],\n            currentLevel = 0,\n            indentLevel  = 0,\n            rowID        = null,\n            data         = {},\n            getSerializeRegexp,\n            paramName,\n            currentID,\n            rows;\n\n        if (!table)\n            table = this.currentTable;\n        if (!table || !table.rows || !table.rows.length)\n            return {error: { code: 500, message: \"Not a valid table.\"}};\n        if (!table.id && !config.serializeParamName)\n            return {error: { code: 500, message: \"No serializable unique id provided.\"}};\n        \n        rows      = config.autoCleanRelations\n                        && table.rows\n                        || $.makeArray(table.rows);\n        paramName = config.serializeParamName || table.id;\n        currentID = paramName;\n\n        getSerializeRegexp = function (rowId) {\n            if (rowId && config && config.serializeRegexp)\n                return rowId.match(config.serializeRegexp)[0];\n            return rowId;\n        };\n\n        data[currentID] = [];\n        !config.autoCleanRelations\n            && $(rows[0]).data('level')\n            && rows.unshift({id: 'undefined'});\n\n\n\n        for (var i=0; i < rows.length; i++) {\n            if (config.hierarchyLevel) {\n                indentLevel = $(rows[i]).data('level') || 0;\n                if (indentLevel === 0) {\n                    currentID   = paramName;\n                    previousIDs = [];\n                }\n                else if (indentLevel > currentLevel) {\n                    previousIDs.push([currentID, currentLevel]);\n                    currentID = getSerializeRegexp(rows[i-1].id);\n                }\n                else if (indentLevel < currentLevel) {\n                    for (var h = 0; h < previousIDs.length; h++) {\n                        if (previousIDs[h][1] === indentLevel)\n                            currentID         = previousIDs[h][0];\n                        if (previousIDs[h][1] >= currentLevel)\n                            previousIDs[h][1] = 0;\n                    }\n                }\n                currentLevel = indentLevel;\n\n                if (!$.isArray(data[currentID]))\n                    data[currentID] = [];\n                rowID = getSerializeRegexp(rows[i].id);\n                rowID && data[currentID].push(rowID);\n            }\n            else {\n                rowID = getSerializeRegexp(rows[i].id);\n                rowID && data[currentID].push(rowID);\n            }\n        }\n        return data;\n    }\n};\n\njQuery.fn.extend(\n    {\n        tableDnD             : $.tableDnD.build,\n        tableDnDUpdate       : $.tableDnD.updateTables,\n        tableDnDSerialize    : $.proxy($.tableDnD.serialize, $.tableDnD),\n        tableDnDSerializeAll : $.tableDnD.serializeTables,\n        tableDnDData         : $.proxy($.tableDnD.tableData, $.tableDnD)\n    }\n);\n\n}(jQuery, window, window.document);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/resizable/bootstrap-table-resizable.js",
    "content": "/**\r\n * @author: Dennis Hernández\r\n * @version: v2.0.0\r\n */\r\n\r\nconst isInit = that => that.$el.data('resizableColumns') !== undefined\r\n\r\nconst initResizable = that => {\r\n  if (\r\n    that.options.resizable &&\r\n    !that.options.cardView &&\r\n    !isInit(that) &&\r\n    that.$el.is(':visible')\r\n  ) {\r\n    that.$el.resizableColumns({\r\n      store: window.store\r\n    })\r\n  }\r\n}\r\n\r\nconst destroy = that => {\r\n  if (isInit(that)) {\r\n    that.$el.data('resizableColumns').destroy()\r\n  }\r\n}\r\n\r\nconst reInitResizable = that => {\r\n  destroy(that)\r\n  initResizable(that)\r\n}\r\n\r\nObject.assign($.fn.bootstrapTable.defaults, {\r\n  resizable: false\r\n})\r\n\r\n$.BootstrapTable = class extends $.BootstrapTable {\r\n\r\n  initBody (...args) {\r\n    super.initBody(...args)\r\n\r\n    this.$el.off('column-switch.bs.table page-change.bs.table')\r\n      .on('column-switch.bs.table page-change.bs.table', () => {\r\n        reInitResizable(this)\r\n      })\r\n\r\n    reInitResizable(this)\r\n  }\r\n\r\n  toggleView (...args) {\r\n    super.toggleView(...args)\r\n\r\n    if (this.options.resizable && this.options.cardView) {\r\n      // Destroy the plugin\r\n      destroy(this)\r\n    }\r\n  }\r\n\r\n  resetView (...args) {\r\n    super.resetView(...args)\r\n\r\n    if (this.options.resizable) {\r\n      // because in fitHeader function, we use setTimeout(func, 100);\r\n      setTimeout(() => {\r\n        initResizable(this)\r\n      }, 100)\r\n    }\r\n  }\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/tree/bootstrap-table-tree.js",
    "content": "/**\n * 基于bootstrapTreeTable/bootstrap-table-treegrid修改\n * Copyright (c) 2019 ruoyi\n */\n(function($) {\n    \"use strict\";\n\n    $.fn.bootstrapTreeTable = function(options, param) {\n        var target = $(this).data('bootstrap.tree.table');\n        target = target ? target : $(this);\n        // 如果是调用方法\n        if (typeof options == 'string') {\n            return $.fn.bootstrapTreeTable.methods[options](target, param);\n        }\n        // 如果是初始化组件\n        options = $.extend({}, $.fn.bootstrapTreeTable.defaults, options || {});\n        target.hasSelectItem = false;    // 是否有radio或checkbox\n        target.data_list = null;         // 用于缓存格式化后的数据-按父分组\n        target.data_obj = null;          // 用于缓存格式化后的数据-按id存对象\n        target.hiddenColumns = [];       // 用于存放被隐藏列的field\n        target.lastAjaxParams;           // 用户最后一次请求的参数\n        target.isFixWidth=false;         // 是否有固定宽度\n        target.totalRows = 0;            // 记录总数\n        target.totalPages = 0;           // 总页数\n        // 初始化\n        var init = function() {\n            // 初始化容器\n            initContainer();\n            // 初始化工具栏\n            initToolbar();\n            // 初始化表头\n            initHeader();\n            // 初始化表体\n            initBody();\n            // 初始化数据服务\n            initServer();\n            // 动态设置表头宽度\n            autoTheadWidth(true);\n            // 缓存target对象\n            target.data('bootstrap.tree.table', target);\n        }\n        // 初始化容器\n        var initContainer = function() {\n            // 在外层包装一下div，样式用的bootstrap-table的\n            var $main_div = $(\"<div class='bootstrap-tree-table'></div>\");\n            var $treetable = $(\"<div class='treetable-table'></div>\");\n            target.before($main_div);\n            $main_div.append($treetable);\n            $treetable.append(target);\n            target.addClass(\"table\");\n            if (options.striped) {\n                target.addClass('table-striped');\n            }\n            if (options.bordered) {\n                target.addClass('table-bordered');\n            }\n            if (options.hover) {\n                target.addClass('table-hover');\n            }\n            if (options.condensed) {\n                target.addClass('table-condensed');\n            }\n            target.html(\"\");\n        }\n        // 初始化工具栏\n        var initToolbar = function() {\n            var $toolbar = $(\"<div class='treetable-bars'></div>\");\n            if (options.toolbar) {\n                $(options.toolbar).addClass('tool-left');\n                $toolbar.append($(options.toolbar));\n            }\n            var $rightToolbar = $('<div class=\"btn-group tool-right\">');\n            $toolbar.append($rightToolbar);\n            target.parent().before($toolbar);\n            // ruoyi 是否显示检索信息\n            if (options.showSearch) {\n                var $searchBtn = $('<button class=\"btn btn-default btn-outline\" type=\"button\" aria-label=\"search\" title=\"搜索\"><i class=\"glyphicon glyphicon-search\"></i></button>');\n                $rightToolbar.append($searchBtn);\n                registerSearchBtnClickEvent($searchBtn);\n            }\n            // 是否显示刷新按钮\n            if (options.showRefresh) {\n                var $refreshBtn = $('<button class=\"btn btn-default btn-outline\" type=\"button\" aria-label=\"refresh\" title=\"刷新\"><i class=\"glyphicon glyphicon-repeat\"></i></button>');\n                $rightToolbar.append($refreshBtn);\n                registerRefreshBtnClickEvent($refreshBtn);\n            }\n            // 是否显示列选项\n            if (options.showColumns) {\n                var $columns_div = $('<div class=\"btn-group pull-right\" title=\"列\"><button type=\"button\" aria-label=\"columns\" class=\"btn btn-default btn-outline dropdown-toggle\" data-toggle=\"dropdown\" aria-expanded=\"false\"><i class=\"glyphicon glyphicon-list\"></i> <span class=\"caret\"></span></button></div>');\n                var $columns_ul = $('<ul class=\"dropdown-menu columns\" role=\"menu\"></ul>');\n                $.each(options.columns, function(i, column) {\n                    if (column.field != 'selectItem') {\n                        var _li = null;\n                        if(typeof column.visible == \"undefined\"||column.visible==true){\n                            _li = $('<li role=\"menuitem\"><label><input type=\"checkbox\" checked=\"checked\" data-field=\"'+column.field+'\" value=\"'+column.field+'\" > '+column.title+'</label></li>');\n                        }else{\n                            _li = $('<li role=\"menuitem\"><label><input type=\"checkbox\" data-field=\"'+column.field+'\" value=\"'+column.field+'\" > '+column.title+'</label></li>');\n                            target.hiddenColumns.push(column.field);\n                        }\n                        $columns_ul.append(_li);\n                    }\n                });\n                $columns_div.append($columns_ul);\n                $rightToolbar.append($columns_div);\n                // 注册列选项事件\n                registerColumnClickEvent();\n            }else{\n                $.each(options.columns, function(i, column) {\n                    if (column.field != 'selectItem') {\n                        if(!(typeof column.visible == \"undefined\"||column.visible==true)){\n                            target.hiddenColumns.push(column.field);\n                        }\n                    }\n                });\n            }\n        }\n        // 初始化隐藏列\n        var initHiddenColumns = function(){\n            $.each(target.hiddenColumns, function(i, field) {\n                target.find(\".\"+field+\"_cls\").hide();\n            });\n        }\n        // 初始化表头\n        var initHeader = function() {\n            var $thr = $('<tr></tr>');\n            $.each(options.columns, function(i, column) {\n                var $th = null;\n                // 判断有没有选择列\n                if (i == 0 && column.field == 'selectItem') {\n                    target.hasSelectItem = true;\n                    $th = $('<th style=\"width:36px\"></th>');\n                } else {\n                    $th = $('<th style=\"' + ((column.width) ? ('width:' + column.width + ((column.widthUnit) ? column.widthUnit : 'px')) : '') + '\" class=\"' + column.field + '_cls\"></th>');\n                    if (column.align) {\n                        $th.css(\"text-align\", column.align);\n                    }\n                }\n                if((!target.isFixWidth)&& column.width){\n                    target.isFixWidth = column.width.indexOf(\"px\")>-1?true:false;\n                }\n                $th.html(column.title);\n                $thr.append($th);\n            });\n            var $thead = $('<thead class=\"treetable-thead\"></thead>');\n            $thead.append($thr);\n            target.append($thead);\n        }\n        // 初始化表体\n        var initBody = function() {\n            var $tbody = $('<tbody class=\"treetable-tbody\"></tbody>');\n            target.append($tbody);\n            // 默认高度\n            if (options.height) {\n                $tbody.css(\"height\", options.height);\n            }\n            if (options.pagination) {\n                var $pagination = $('<div class=\"fixed-table-pagination\"></div>');\n                target.append($pagination);\n            }\n        }\n        // 初始化数据服务\n        var initServer = function(parms) {\n            if (options.pagination) {\n                if(parms == undefined || parms == null) {\n                    parms = {};\n                }\n                parms[options.parentCode] = options.rootIdValue;\n            }\n            // 加载数据前先清空\n            target.data_list = {};\n            target.data_obj = {};\n            // 设置请求分页参数\n            if (options.pagination) {\n                if (target.lastAjaxParams) {\n                    parms = $.extend({}, target.lastAjaxParams, parms);\n                }\n                var params = {};\n                params.offset = options.pageSize * (options.pageNumber - 1);\n                params.limit = options.pageSize;\n                var curParams = { pageSize: params.limit, pageNum: params.offset / params.limit + 1 };\n                parms = $.extend(curParams, parms);\n            }\n            var $tbody = target.find(\"tbody\");\n            // 添加加载loading\n            var $loading = '<tr><td colspan=\"' + options.columns.length + '\"><div style=\"display: block;text-align: center;\">正在努力地加载数据中，请稍候……</div></td></tr>'\n            $tbody.html($loading);\n            if (options.url) {\n                $.ajax({\n                    type: options.type,\n                    url: options.url,\n                    data: $.extend(parms, options.ajaxParams),\n                    dataType: \"json\",\n                    success: function(data, textStatus, jqXHR) {\n                    \tdata = calculateObjectValue(options, options.responseHandler, [data], data);\n                        renderTable(data);\n                        calculateObjectValue(options, options.onLoadSuccess, [data], data);\n                    },\n                    error: function(xhr, textStatus) {\n                        var _errorMsg = '<tr><td colspan=\"' + options.columns.length + '\"><div style=\"display: block;text-align: center;\">' + xhr.responseText + '</div></td></tr>'\n                        $tbody.html(_errorMsg);\n                    }\n                });\n            } else {\n                renderTable(options.data);\n            }\n        }\n        // 加载完数据后渲染表格\n        var renderTable = function(data) {\n            var list, totalPage = 0, currPage = 0;\n            if (options.pagination) {\n            \tlist = data.rows;  // 数据\n                currPage = options.pageNumber; // 当前页\n                totalPage = ~~((data.total - 1) / options.pageSize) + 1 // 总页数\n                target.totalPages  = totalPage;\n                target.totalRows = data.total; // 总记录数\n            } else {\n            \tlist = data;\n            }\n            data = list;\n            var $tbody = target.find(\"tbody\");\n            // 先清空\n            $tbody.html(\"\");\n            if (!data || data.length <= 0) {\n                var _empty = '<tr><td colspan=\"' + options.columns.length + '\"><div style=\"display: block;text-align: center;\">没有找到匹配的记录</div></td></tr>'\n                $tbody.html(_empty);\n                options.pageNumber = 1;\n                initPagination(0, 0);\n                return;\n            }\n            // 缓存并格式化数据\n            formatData(data);\n            // 获取所有根节点\n            var rootNode = target.data_list[\"_root_\"];\n            // 开始绘制\n            if (rootNode) {\n                $.each(rootNode, function(i, item) {\n                    var _child_row_id = \"row_id_\" + i\n                    recursionNode(item, 1, _child_row_id, \"row_root\", item[options.code]);\n                });\n            }\n            // 下边的操作主要是为了查询时让一些没有根节点的节点显示\n            $.each(data, function(i, item) {\n                if (!item.isShow) {\n                    var tr = renderRow(item, false, 1, \"\", \"\", options.pagination, item[options.code]);\n                    $tbody.append(tr);\n                }\n            });\n            registerExpanderEvent();\n            registerRowClickEvent();\n            initHiddenColumns();\n            // 动态设置表头宽度\n            autoTheadWidth();\n            if (options.pagination) {\n                initPagination(totalPage, currPage);\n            }\n            // 移动端适配\n            var treetableTable = $(target).parent('.treetable-table');\n            var availableHeight = treetableTable.outerWidth();\n            if($.common.isMobile() || availableHeight < 769){\n                var tableStyle = \"width: \" + availableHeight + \"px;overflow: auto;position: relative;\";\n                treetableTable.attr('style', tableStyle);\n                var w = 0;\n                $.each(options.columns, function(i, column) {\n                    if (i == 0 && column.field == 'selectItem') {\n                        w += 36;\n                    } else {\n                        w += 200;\n                    }\n                });\n                $(target).attr('style','width:' + w +'px');\n            }\n        }\n        // 初始化分页\n        var initPagination = function (totalPage,currPage) {\n            var $pagination = target.find(\".fixed-table-pagination\");\n            $pagination.empty();\n            var html = [];\n            var pageFrom = (options.pageNumber - 1) * options.pageSize + 1;\n            var pageTo = options.pageNumber * options.pageSize;\n            if (pageTo > target.totalRows) {\n                pageTo = target.totalRows;\n            }\n            if (pageFrom > pageTo) {\n                pageFrom = pageTo;\n            }\n            html.push('<div class=\"pull-left pagination-detail\">');\n            html.push('<span class=\"pagination-info\">' + formatShowingRows(pageFrom, pageTo, target.totalRows) + '</span>');\n            var pageList = false;\n            $.each(options.pageList, function (i, page) {\n                if(target.totalRows > page){\n                    pageList = true;\n                }\n            })\n            if(pageList){\n                var _page_list = [];\n                _page_list.push('<span class=\"page-list\">');\n                _page_list.push('<span class=\"btn-group dropup\">');\n                _page_list.push('<button type=\"button\" class=\"btn btn-default btn-outline dropdown-toggle\" data-toggle=\"dropdown\">');\n                _page_list.push('<span class=\"page-size\">' + options.pageSize + '</span>');\n                _page_list.push('<span class=\"caret\"></span>');\n                _page_list.push('</button>');\n                _page_list.push('<ul class=\"dropdown-menu\" role=\"menu\">');\n                $.each(options.pageList, function (i, page) {\n                    if(page == options.pageSize){\n                        _page_list.push('<li class=\"active\"><a href=\"javascript:void(0)\">' + page + '</a></li>');\n                    }\n                    else if(page >= target.totalRows && i === 1){\n                        _page_list.push('<li><a href=\"javascript:void(0)\">' + page + '</a></li>');\n                    }\n                    else if(page <= target.totalRows){\n                        _page_list.push('<li><a href=\"javascript:void(0)\">' + page + '</a></li>');\n                    }\n                })\n                _page_list.push('</ul>');\n                _page_list.push('</span>');\n                html.push(formatRecordsPerPage(_page_list.join('')))\n                html.push('</span>');\n            }\n            html.push('</div>');\n\n            if(totalPage > 1){\n                html.push('<div class=\"pull-right pagination\">');\n                html.push('<ul class=\"pagination pagination-outline\">');\n                html.push('<li class=\"page-pre\"><a href=\"javascript:void(0)\">' + options.paginationPreText + '</a></li>');\n                var from, to;\n                if (totalPage < 5) {\n                    from = 1;\n                    to = totalPage;\n                } else {\n                    from = currPage - 2;\n                    to = from + 4;\n                    if (from < 1) {\n                        from = 1;\n                        to = 5;\n                    }\n                    if (to > totalPage) {\n                        to = totalPage;\n                        from = to - 4;\n                    }\n                }\n\n                if (totalPage >= 6) {\n                    if (currPage >= 3) {\n                        html.push('<li class=\"page-first' + (1 == currPage ? ' active' : '') + '\">', '<a href=\"javascript:void(0)\">', 1, '</a>', '</li>');\n                        from++;\n                    }\n                    if (currPage >= 4) {\n                        if (currPage == 4 || totalPage == 6 || totalPage == 7) {\n                            from--;\n                        } else {\n                            html.push('<li class=\"page-first-separator disabled\">', '<a href=\"javascript:void(0)\">...</a>', '</li>');\n                        }\n                        to--;\n                    }\n                }\n\n                if (totalPage >= 7) {\n                    if (currPage >= (totalPage - 2)) {\n                        from--;\n                    }\n                }\n                if (totalPage == 6) {\n                    if (currPage >= (totalPage - 2)) {\n                        to++;\n                    }\n                } else if (totalPage >= 7) {\n                    if (totalPage == 7 || currPage >= (totalPage - 3)) {\n                        to++;\n                    }\n                }\n\n                for (var i = from; i <= to; i++) {\n                    html.push('<li class=\"page-number' + (i == currPage ? ' active' : '') + '\">', '<a href=\"javascript:void(0)\">', i, '</a>', '</li>');\n                }\n\n                if (totalPage >= 8) {\n                    if (currPage <= (totalPage - 4)) {\n                        html.push('<li class=\"page-last-separator disabled\">', '<a href=\"javascript:void(0)\">...</a>', '</li>');\n                    }\n                }\n\n                if (totalPage >= 6) {\n                    if (currPage <= (totalPage - 3)) {\n                        html.push('<li class=\"page-last' + (totalPage === currPage ? ' active' : '') + '\">', '<a href=\"javascript:void(0)\">', totalPage, '</a>', '</li>');\n                    }\n                }\n\n                html.push('<li class=\"page-next\"><a href=\"javascript:void(0)\">' + options.paginationNextText + '</a></li>');\n                html.push('</ul></div>');\n            }\n\n            $pagination.append(html.join(''));\n\n            var $pageList = $pagination.find('.page-list a');\n            var $pre = $pagination.find('.page-pre');\n            var $next = $pagination.find('.page-next');\n            var $number = $pagination.find('.page-number');\n            var $first = $pagination.find('.page-first');\n            var $last = $pagination.find('.page-last');\n            $pre.off('click').on('click', $.proxy(onPagePre, this));\n            $pageList.off('click').on('click', $.proxy(onPageListChange, this));\n            $number.off('click').on('click', $.proxy(onPageNumber, this));\n            $first.off('click').on('click', $.proxy(onPageFirst, this));\n            $last.off('click').on('click', $.proxy(onPageLast, this));\n            $next.off('click').on('click', $.proxy(onPageNext, this));\n        }\n        var onPageListChange = function(event){\n            var $this = $(event.currentTarget);\n            $this.parent().addClass('active').siblings().removeClass('active');\n            var $pagination = target.find(\".fixed-table-pagination\");\n            options.pageSize = $this.text().toUpperCase() === target.totalRows ? target.totalRows : + $this.text();\n            \n            if(target.totalRows < options.pageSize * options.pageNumber){\n                options.pageNumber = 1;\n            }\n            $pagination.find('.page-size').text(options.pageSize);\n            initServer();\n        }\n        var onPagePre = function(event){\n            if ((options.pageNumber - 1) === 0) {\n                options.pageNumber = target.totalPages;\n            } else {\n                options.pageNumber--;\n            }\n            initServer();\n        }\n        var onPageNumber = function(event){\n            if (options.pageNumber == $(event.currentTarget).text()) {\n                return;\n            }\n            options.pageNumber = $(event.currentTarget).text();\n            initServer();\n        }\n        var onPageFirst = function(event){\n            options.pageNumber = 1;\n            initServer();\n        }\n        var onPageLast = function (event) {\n            options.pageNumber = target.totalPages;\n            initServer();\n        }\n        var onPageNext = function(event){\n            if ((options.pageNumber + 1) > target.totalPages) {\n                options.pageNumber = 1;\n            } else {\n                options.pageNumber++;\n            }\n            initServer();\n        }\n        // 动态设置表头宽度\n        var autoTheadWidth = function(initFlag) {\n            if(options.height>0){\n                var $thead = target.find(\"thead\");\n                var $tbody = target.find(\"tbody\");\n                var borderWidth = parseInt(target.css(\"border-left-width\")) + parseInt(target.css(\"border-right-width\"))\n                \n                $thead.css(\"width\", $tbody.children(\":first\").width());\n                if(initFlag){\n                    var resizeWaiter = false;\n                    $(window).resize(function() {\n                        if(!resizeWaiter){\n                            resizeWaiter = true;\n                            setTimeout(function(){\n                                if(!target.isFixWidth){\n                                    $tbody.css(\"width\", target.parent().width()-borderWidth);\n                                }\n                                $thead.css(\"width\", $tbody.children(\":first\").width());\n                                resizeWaiter = false;\n                            }, 300);\n                        }\n                    });\n                }\n            }\n        \n        }\n        // 缓存并格式化数据\n        var formatData = function(data) {\n            var _root = options.rootIdValue ? options.rootIdValue : null;\n            // 父节点属性列表\n            var parentCodes = [];\n            var rootFlag = false;\n            $.each(data, function(index, item) {\n            \tif($.inArray(item[options.parentCode], parentCodes) == -1){\n            \t\tparentCodes.push(item[options.parentCode]);\n                }\n            });\n            $.each(data, function(index, item) {\n                // 添加一个默认属性，用来判断当前节点有没有被显示\n                item.isShow = false;\n                // 是否分页\n                if (options.pagination) {\n                    if (item.isTreeLeaf == undefined || item.isTreeLeaf == null) {\n                        item.isTreeLeaf = false;\n                    } else {\n                        item.isTreeLeaf = (item[\"isTreeLeaf\"] == 1 ? true: false) || ((item[\"isTreeLeaf\"] == 'true' || item[\"isTreeLeaf\"] == true) ? true: false);\n                    }\n                }\n                // 顶级节点校验判断，兼容0,'0','',null\n                var _defaultRootFlag = item[options.parentCode] == '0' ||\n                item[options.parentCode] == 0 ||\n                item[options.parentCode] == null ||\n                item[options.parentCode] == '' ||\n                $.inArray(item[options.code], parentCodes) > 0 && !rootFlag;\n                if (!item[options.parentCode] || (_root ? (item[options.parentCode] == options.rootIdValue) : _defaultRootFlag)) {\n                \trootFlag = true;\n                \tif (!target.data_list[\"_root_\"]) {\n                        target.data_list[\"_root_\"] = [];\n                    }\n                    if (!target.data_obj[\"id_\" + item[options.code]]) {\n                        target.data_list[\"_root_\"].push(item);\n                    }\n                } else {\n                    if (!target.data_list[\"_n_\" + item[options.parentCode]]) {\n                        target.data_list[\"_n_\" + item[options.parentCode]] = [];\n                    }\n                    if (!target.data_obj[\"id_\" + item[options.code]]) {\n                        target.data_list[\"_n_\" + item[options.parentCode]].push(item);\n                    }\n                }\n                target.data_obj[\"id_\" + item[options.code]] = item;\n            });\n        }\n        // 递归获取子节点并且设置子节点\n        var recursionNode = function(parentNode, lv, row_id, p_id, k) {\n            var $tbody = target.find(\"tbody\");\n            var _ls = target.data_list[\"_n_\" + parentNode[options.code]];\n            var $tr = renderRow(parentNode, _ls ? true : false, lv, row_id, p_id, options.pagination, k);\n            $tbody.append($tr);\n            if (_ls) {\n                $.each(_ls, function(i, item) {\n                    var _child_row_id = row_id + \"_\" + i\n                    recursionNode(item, (lv + 1), _child_row_id, row_id, item[options.code])\n                });\n            }\n        };\n        // 绘制行\n        var renderRow = function(item, isP, lv, row_id, p_id, _pagination, k) {\n            // 标记已显示\n            item.isShow = true;\n            item.row_id = row_id;\n            item.p_id = p_id;\n            item.lv = lv;\n            var $tr = $('<tr id=\"' + row_id + '\" data-id=\"' + k + '\"pid=\"' + p_id + '\"></tr>');\n            var _icon = options.expanderCollapsedClass;\n            if (options.expandAll) {\n                $tr.css(\"display\", \"table\");\n                _icon = options.expanderExpandedClass;\n            } else if (lv == 1) {\n                $tr.css(\"display\", \"table\");\n                _icon = (options.expandFirst) ? options.expanderExpandedClass : options.expanderCollapsedClass;\n            } else if (lv == 2) {\n                if (options.expandFirst) {\n                    $tr.css(\"display\", \"table\");\n                } else {\n                    $tr.css(\"display\", \"none\");\n                }\n                _icon = options.expanderCollapsedClass;\n            } else if (_pagination) {\n                if (item.isTreeLeaf) {\n                    _icon = options.expanderCollapsedClass;\n                }\n            } else {\n                $tr.css(\"display\", \"none\");\n                _icon = options.expanderCollapsedClass;\n            }\n            $.each(options.columns, function(index, column) {\n                // 判断有没有选择列\n                if (column.field == 'selectItem') {\n                    target.hasSelectItem = true;\n                    var $td = $('<td style=\"text-align:center;width:36px\"></td>');\n                    if (column.radio) {\n                        var _ipt = $('<input name=\"select_item\" type=\"radio\" value=\"' + item[options.code] + '\"></input>');\n                        $td.append(_ipt);\n                    }\n                    if (column.checkbox) {\n                        var _ipt = $('<input name=\"select_item\" type=\"checkbox\" value=\"' + item[options.code] + '\"></input>');\n                        $td.append(_ipt);\n                    }\n                    $tr.append($td);\n                } else {\n                    var $td = $('<td name=\"' + column.field + '\" class=\"' + column.field + '_cls\"></td>');\n                    if(column.width){\n                        $td.css(\"width\",column.width + (column.widthUnit ? column.widthUnit : 'px'));\n                    }\n                    if(column.align){\n                        $td.css(\"text-align\",column.align);\n                    }\n                    if(options.expandColumn == index){\n                        $td.css(\"text-align\",\"left\");\n                    }\n                    if(column.valign){\n                        $td.css(\"vertical-align\",column.valign);\n                    }\n                    if(options.showTitle){\n                        $td.addClass(\"ellipsis\");\n                    }\n                    // 增加formatter渲染\n                    if (column.formatter) {\n                        $td.html(column.formatter.call(this, getItemField(item, column.field), item, index));\n                    } else {\n                        if(options.showTitle){\n                            // 只在字段没有formatter时才添加title属性\n                            $td.attr(\"title\",item[column.field]);\n                        }\n                        $td.text(getItemField(item, column.field));\n                    }\n                    if (options.expandColumn == index) {\n                    \tif (_pagination) {\n                    \t    if (item[\"isTreeLeaf\"]) {\n                    \t        $td.prepend('<span class=\"treetable-expander ' + _icon + '\"></span>');\n                    \t    } else {\n                    \t        $td.prepend('<span class=\"treetable-expander\"></span>')\n                    \t    }\n                    \t} else {\n\t                        if (!isP) {\n\t                            $td.prepend('<span class=\"treetable-expander\"></span>')\n\t                        } else {\n\t                            $td.prepend('<span class=\"treetable-expander ' + _icon + '\"></span>');\n\t                        }\n                    \t}\n                    \tfor (var int = 0; int < (lv - options.expandColumn); int++) {\n                            $td.prepend('<span class=\"treetable-indent\"></span>')\n                        }\n                    }\n                    $tr.append($td);\n                }\n            });\n            return $tr;\n        }\n        // 检索信息按钮点击事件\n        var registerSearchBtnClickEvent = function(btn) {\n            $(btn).off('click').on('click', function () {\n                $(\".search-collapse\").slideToggle();\n            });\n        }\n        // 注册刷新按钮点击事件\n        var registerRefreshBtnClickEvent = function(btn) {\n            $(btn).off('click').on('click', function () {\n                target.refresh();\n            });\n        }\n        // 注册列选项事件\n        var registerColumnClickEvent = function() {\n            $(\".bootstrap-tree-table .treetable-bars .columns label input\").off('click').on('click', function () {\n                var $this = $(this);\n                if($this.prop('checked')){\n                    target.showColumn($(this).val());\n                }else{\n                    target.hideColumn($(this).val());\n                }\n            });\n        }\n        // 注册行点击选中事件\n        var registerRowClickEvent = function() {\n            target.find(\"tbody\").find(\"tr\").unbind();\n            target.find(\"tbody\").find(\"tr\").click(function() {\n                if (target.hasSelectItem) {\n                    var _ipt = $(this).find(\"input[name='select_item']\");\n                    if (_ipt.attr(\"type\") == \"radio\") {\n                        _ipt.prop('checked', true);\n                        target.find(\"tbody\").find(\"tr\").removeClass(\"treetable-selected\");\n                        $(this).addClass(\"treetable-selected\");\n                    } else if (_ipt.attr(\"type\") == \"checkbox\") {\n                    \tif (_ipt.prop('checked')) {\n                    \t\t_ipt.prop('checked', true);\n                    \t\ttarget.find(\"tbody\").find(\"tr\").removeClass(\"treetable-selected\");\n                    \t\t$(this).addClass(\"treetable-selected\");\n                    \t} else {\n                    \t\t_ipt.prop('checked', false);\n                    \t\ttarget.find(\"tbody\").find(\"tr\").removeClass(\"treetable-selected\");\n                    \t}\n                    } else {\n                        if (_ipt.prop('checked')) {\n                            _ipt.prop('checked', false);\n                            $(this).removeClass(\"treetable-selected\");\n                        } else {\n                            _ipt.prop('checked', true);\n                            $(this).addClass(\"treetable-selected\");\n                        }\n                    }\n                    var _rowData = target.data_obj[\"id_\" + $(this).data('id')];\n                    calculateObjectValue(options, options.onClickRow, [_rowData], _rowData);\n                }\n            });\n        }\n        // 注册小图标点击事件--展开缩起\n        var registerExpanderEvent = function() {\n            target.find(\"tbody\").find(\"tr\").find(\".treetable-expander\").unbind();\n            target.find(\"tbody\").find(\"tr\").find(\".treetable-expander\").click(function() {\n                var _isExpanded = $(this).hasClass(options.expanderExpandedClass);\n                var _isCollapsed = $(this).hasClass(options.expanderCollapsedClass);\n                if (_isExpanded || _isCollapsed) {\n                    var tr = $(this).parent().parent();\n                    var row_id = tr.attr(\"id\");\n                    var row_pid = tr.attr(\"pid\");\n                    var _id = tr.attr(\"data-id\");\n                    var _ls = target.find(\"tbody\").find(\"tr[id^='\" + row_id + \"_']\");\n                    if (!options.pagination) {\n\t                    if (_isExpanded) {\n\t                        $(this).removeClass(options.expanderExpandedClass);\n\t                        $(this).addClass(options.expanderCollapsedClass);\n\t                        if (_ls && _ls.length > 0) {\n\t                            $.each(_ls, function(index, item) {\n\t                                $(item).css(\"display\", \"none\");\n\t                            });\n\t                        }\n\t                    } else {\n\t                        $(this).removeClass(options.expanderCollapsedClass);\n\t                        $(this).addClass(options.expanderExpandedClass);\n\t                        if (_ls && _ls.length > 0) {\n\t                            $.each(_ls, function(index, item) {\n\t                                var _p_icon = $(\"#\" + $(item).attr(\"pid\")).children().eq(options.expandColumn).find(\".treetable-expander\");\n\t                                var _p_display = $(\"#\" + $(item).attr(\"pid\")).css('display');\n\t                                if (_p_icon.hasClass(options.expanderExpandedClass) && _p_display == 'table') {\n\t                                    $(item).css(\"display\", \"table\");\n\t                                }\n\t                            });\n\t                        }\n\t                    }\n                    } else {\n                        var _ls = target.find(\"tbody\").find(\"tr[id^='\" + row_id + \"_']\");\n                        if (_ls && _ls.length > 0) {\n                            if (_isExpanded) {\n                                if (row_pid == \"row_root\") {\n                                    $('table tr[id^=\"' + row_id + '_\"]').css(\"display\", \"none\");\n                                    $('table tr[id^=\"' + row_id + '_\"]').each(function(i,n) {\n                                        var _isExpanded = $(n).find(\".treetable-expander\").hasClass(options.expanderExpandedClass);\n                                        if (_isExpanded) {\n                                            $(n).find(\".treetable-expander\").trigger(\"click\");\n                                        }\n                                    })\n                                } else {\n                                    $.each(_ls, function(index, item) {\n                                        $(item).css(\"display\", \"none\");\n                                        var _isExpanded = $(item).find(\".treetable-expander\").hasClass(options.expanderExpandedClass);\n                                        if (_isExpanded) {\n                                            $(item).find(\".treetable-expander\").trigger(\"click\");\n                                        }\n                                     });\n                            \t}\n                            } else {\n                                if (row_pid == \"row_root\") {\n                                    $('table tr[pid=\"' + row_id + '\"]').css(\"display\", \"table\");\n                                } else {\n\t                                $.each(_ls, function(index, item) {\n\t                                    var _p_icon = $(\"#\" + $(item).attr(\"pid\")).children().eq(options.expandColumn).find(\".treetable-expander\");\n                                        var _isExpanded = _p_icon.hasClass(options.expanderExpandedClass);\n                                        var _isCollapsed = _p_icon.hasClass(options.expanderCollapsedClass);\n\t                                    if (row_id == $(item).attr(\"pid\")) {\n\t\t                                    $(item).css(\"display\", \"table\");\n\t                                    }\n\t                                });\n                                }\n                            }\n                        } else {\n                            if (options.pagination) {\n                                var parms = {};\n                                parms[options.parentCode] = _id;\n                                if (options.dataUrl) {\n                                    $.ajax({\n                                        type: options.type,\n                                        url: options.dataUrl,\n                                        data: parms,\n                                        dataType: \"json\",\n                                        success: function(data, textStatus, jqXHR) {\n                                            $(\"#\" + row_id + \"_load\").remove();\n                                            var list = data;\n                                            data = list;\n                                            target.appendData(data)\n                                        },\n                                        error: function(xhr, textStatus) {\n                                            var _errorMsg = '<tr><td colspan=\"' + options.columns.length + '\"><div style=\"display: block;text-align: center;\">' + xhr.responseText + '</div></td></tr>'\n                                            $(\"#\" + row_id).after(_errorMsg);\n                                        }\n                                    });\n                                }\n                            }\n                        }\n                        if (_isExpanded) {\n                            $(this).removeClass(options.expanderExpandedClass);\n                            $(this).addClass(options.expanderCollapsedClass);\n                        } else {\n                            $(this).removeClass(options.expanderCollapsedClass);\n                            $(this).addClass(options.expanderExpandedClass);\n                        }\n                    }\n                }\n            });\n        }\n        // 刷新数据\n        target.refresh = function(parms) {\n            if(parms){\n                target.lastAjaxParams=parms;\n            }\n            initServer(target.lastAjaxParams);\n        }\n        // 添加数据刷新表格\n        target.appendData = function(data) {\n            data.reverse()\n            // 下边的操作主要是为了查询时让一些没有根节点的节点显示\n            $.each(data, function(i, item) {\n                if (options.pagination) {\n                    item.__nodes = (item[\"nodes\"] == 1 ? true: false) || ((item[\"nodes\"] == 'true' || item[\"nodes\"] == true) ? true: false);\n                }\n                var _data = target.data_obj[\"id_\" + item[options.code]];\n                var _p_data = target.data_obj[\"id_\" + item[options.parentCode]];\n                var _c_list = target.data_list[\"_n_\" + item[options.parentCode]];\n                var row_id = \"\"; //行id\n                var p_id = \"\"; //父行id\n                var _lv = 1; //如果没有父就是1默认显示\n                var tr; //要添加行的对象\n                if (_data && _data.row_id && _data.row_id != \"\") {\n                    row_id = _data.row_id; // 如果已经存在了，就直接引用原来的\n                }\n                if (_p_data) {\n                    p_id = _p_data.row_id;\n                    if (row_id == \"\") {\n                        var _tmp = 0\n                        if (_c_list && _c_list.length > 0) {\n                            _tmp = _c_list.length;\n                        }\n                        row_id = _p_data.row_id + \"_\" + _tmp;\n                    }\n                    _lv = _p_data.lv + 1; //如果有父\n                    // 绘制行\n                    tr = renderRow(item, true, _lv, row_id, p_id, options.pagination, item[options.code]);\n\n                    var _p_icon = $(\"#\" + _p_data.row_id).children().eq(options.expandColumn).find(\".treetable-expander\");\n                    var _isExpanded = _p_icon.hasClass(options.expanderExpandedClass);\n                    var _isCollapsed = _p_icon.hasClass(options.expanderCollapsedClass);\n                    // 父节点有没有展开收缩按钮\n                    if (_isExpanded || _isCollapsed) {\n                        // 父节点展开状态显示新加行\n                        if (_isExpanded) {\n                            tr.css(\"display\", \"table\");\n                        }\n                    } else {\n                        // 父节点没有展开收缩按钮则添加\n                        _p_icon.addClass(options.expanderCollapsedClass);\n                    }\n\n                    if (_data) {\n                        $(\"#\" + _data.row_id).before(tr);\n                        $(\"#\" + _data.row_id).remove();\n                    } else {\n                        // 计算父的同级下一行\n                        var _tmp_ls = _p_data.row_id.split(\"_\");\n                        var _p_next = _p_data.row_id.substring(0, _p_data.row_id.length - (_tmp_ls[_tmp_ls.length - 1] + \"\").length) + (parseInt(_tmp_ls[_tmp_ls.length - 1]) + 1);\n                        $(\"#\" + _p_data.row_id).after(tr);\n                    }\n                } else {\n                    tr = renderRow(item, false, _lv, row_id, p_id, options.pagination, item[options.code]);\n                    if (_data) {\n                        $(\"#\" + _data.row_id).before(tr);\n                        $(\"#\" + _data.row_id).remove();\n                    } else {\n                        // 画上\n                        var tbody = target.find(\"tbody\");\n                        tbody.append(tr);\n                    }\n                }\n                item.isShow = true;\n                // 缓存并格式化数据\n                formatData([item]);\n            });\n            registerExpanderEvent();\n            registerRowClickEvent();\n            initHiddenColumns();\n        }\n\n        // 展开/折叠指定的行\n        target.toggleRow=function(id) {\n            var _rowData = target.data_obj[\"id_\" + id];\n            var $row_expander = $(\"#\"+_rowData.row_id).find(\".treetable-expander\");\n            $row_expander.trigger(\"click\");\n        }\n        // 展开指定的行\n        target.expandRow=function(id) {\n            var _rowData = target.data_obj[\"id_\" + id];\n            var $row_expander = $(\"#\"+_rowData.row_id).find(\".treetable-expander\");\n            var _isCollapsed = $row_expander.hasClass(target.options.expanderCollapsedClass);\n            if (_isCollapsed) {\n                $row_expander.trigger(\"click\");\n            }\n        }\n        // 折叠 指定的行\n        target.collapseRow=function(id) {\n            var _rowData = target.data_obj[\"id_\" + id];\n            var $row_expander = $(\"#\"+_rowData.row_id).find(\".treetable-expander\");\n            var _isExpanded = $row_expander.hasClass(target.options.expanderExpandedClass);\n            if (_isExpanded) {\n                $row_expander.trigger(\"click\");\n            }\n        }\n        // 展开所有的行\n        target.expandAll=function() {\n            target.find(\"tbody\").find(\"tr\").find(\".treetable-expander\").each(function(i,n){\n                var _isCollapsed = $(n).hasClass(options.expanderCollapsedClass);\n                if (_isCollapsed) {\n                    $(n).trigger(\"click\");\n                }\n            })\n        }\n        // 折叠所有的行\n        target.collapseAll=function() {\n            target.find(\"tbody\").find(\"tr\").find(\".treetable-expander\").each(function(i,n){\n                var _isExpanded = $(n).hasClass(options.expanderExpandedClass);\n                if (_isExpanded) {\n                    $(n).trigger(\"click\");\n                }\n            })\n        }\n        // 显示指定列\n        target.showColumn=function(field,flag) {\n            var _index = $.inArray(field, target.hiddenColumns);\n            if (_index > -1) {\n                target.hiddenColumns.splice(_index, 1);\n            }\n            target.find(\".\"+field+\"_cls\").show();\n            //是否更新列选项状态\n            if(flag&&options.showColumns){\n                var $input = $(\".bootstrap-tree-table .treetable-bars .columns label\").find(\"input[value='\"+field+\"']\")\n                $input.prop(\"checked\", 'checked');\n            }\n        }\n        // 隐藏指定列\n        target.hideColumn=function(field,flag) {\n            target.hiddenColumns.push(field);\n            target.find(\".\"+field+\"_cls\").hide();\n            //是否更新列选项状态\n            if(flag&&options.showColumns){\n                var $input = $(\".bootstrap-tree-table .treetable-bars .columns label\").find(\"input[value='\"+field+\"']\")\n                $input.prop(\"checked\", '');\n            }\n        }\n        // ruoyi 解析数据，支持多层级访问\n        var getItemField = function (item, field) {\n            var value = item;\n\n            if (typeof field !== 'string' || item.hasOwnProperty(field)) {\n                return item[field];\n            }\n            var props = field.split('.');\n            for (var p in props) {\n                value = value && value[props[p]];\n            }\n            return value;\n        };\n        // ruoyi 发起对目标(target)函数的调用\n        var calculateObjectValue = function (self, name, args, defaultValue) {\n            var func = name;\n\n            if (typeof name === 'string') {\n                var names = name.split('.');\n\n                if (names.length > 1) {\n                    func = window;\n                    $.each(names, function (i, f) {\n                        func = func[f];\n                    });\n                } else {\n                    func = window[name];\n                }\n            }\n            if (typeof func === 'object') {\n                return func;\n            }\n            if (typeof func === 'function') {\n                return func.apply(self, args);\n            }\n            if (!func && typeof name === 'string' && sprintf.apply(this, [name].concat(args))) {\n                return sprintf.apply(this, [name].concat(args));\n            }\n            return defaultValue;\n        };\n        var  formatRecordsPerPage =  function (pageNumber) {\n            return '每页显示 ' + pageNumber + ' 条记录';\n        };\n        var formatShowingRows = function (pageFrom, pageTo, totalRows) {\n        \treturn '显示第 ' + pageFrom + ' 到第 ' + pageTo + ' 条记录，总共 ' + totalRows + ' 条记录。';\n        };\n        // 初始化\n        init();\n        return target;\n    };\n\n    // 组件方法封装........\n    $.fn.bootstrapTreeTable.methods = {\n        // 为了兼容bootstrap-table的写法，统一返回数组，这里返回了表格显示列的数据\n        getSelections: function(target, data) {\n            // 所有被选中的记录input\n            var _ipt = target.find(\"tbody\").find(\"tr\").find(\"input[name='select_item']:checked\");\n            var chk_value = [];\n            // 如果是radio\n            if (_ipt.attr(\"type\") == \"radio\") {\n                var _data = target.data_obj[\"id_\" + _ipt.val()];\n                chk_value.push(_data);\n            } else {\n                _ipt.each(function(_i, _item) {\n                    var _data = target.data_obj[\"id_\" + $(_item).val()];\n                    chk_value.push(_data);\n                });\n            }\n            return chk_value;\n        },\n        // 刷新记录\n        refresh: function(target, parms) {\n            if (parms) {\n                target.refresh(parms);\n            } else {\n                target.refresh();\n            }\n        },\n        // 添加数据到表格\n        appendData: function(target, data) {\n            if (data) {\n                target.appendData(data);\n            }\n        },\n        // 展开/折叠指定的行\n        toggleRow: function(target, id) {\n            target.toggleRow(id);\n        },\n        // 展开指定的行\n        expandRow: function(target, id) {\n            target.expandRow(id);\n        },\n        // 折叠 指定的行\n        collapseRow: function(target, id) {\n            target.collapseRow(id);\n        },\n        // 展开所有的行\n        expandAll: function(target) {\n            target.expandAll();\n        },\n        // 折叠所有的行\n        collapseAll: function(target) {\n            target.collapseAll();\n        },\n        // 显示指定列\n        showColumn: function(target,field) {\n            target.showColumn(field,true);\n        },\n        // 隐藏指定列\n        hideColumn: function(target,field) {\n            target.hideColumn(field,true);\n        }\n        // 组件的其他方法也可以进行类似封装........\n    };\n\n    $.fn.bootstrapTreeTable.defaults = {\n        code: 'code',              // 选取记录返回的值,用于设置父子关系\n        parentCode: 'parentCode',  // 用于设置父子关系\n        rootIdValue: 0,            // 设置根节点id值----可指定根节点，默认为null,\"\",0,\"0\"\n        data: null,                // 构造table的数据集合\n        type: \"GET\",               // 请求数据的ajax类型\n        url: null,                 // 请求数据的ajax的url\n        ajaxParams: {},            // 请求数据的ajax的data属性\n        expandColumn: 1,           // 在哪一列上面显示展开按钮\n        expandAll: false,          // 是否全部展开\n        expandFirst: true,         // 是否默认第一级展开--expandAll为false时生效\n        striped: false,            // 是否各行渐变色\n        bordered: false,           // 是否显示边框\n        hover: true,               // 是否鼠标悬停\n        condensed: false,          // 是否紧缩表格\n        columns: [],               // 列\n        toolbar: null,             // 顶部工具条\n        height: 0,                 // 表格高度\n        pagination: false,         // 是否显示分页\n        dataUrl: null,             // 加载子节点异步请求数据url\n        pageNumber: 1,             // 当前页条数\n        pageSize: 10,              // 每页的记录行数\n        onClickRow: null,          // 单击某行事件\n        pageList: [10, 25, 50],    // 可供选择的每页的行数\n        showTitle: true,           // 是否采用title属性显示字段内容（被formatter格式化的字段不会显示）\n        showSearch: true,          // 是否显示检索信息\n        showColumns: true,         // 是否显示内容列下拉框\n        showRefresh: true,         // 是否显示刷新按钮\n        paginationPreText: '&lsaquo;',\n        paginationNextText: '&rsaquo;',\n        expanderExpandedClass: 'glyphicon glyphicon-chevron-down',   // 展开的按钮的图标\n        expanderCollapsedClass: 'glyphicon glyphicon-chevron-right', // 缩起的按钮的图标\n        responseHandler: function(res) {\n            return false;\n        },\n        onLoadSuccess: function(res) {\n            return false;\n        }\n    };\n})(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/locale/bootstrap-table-zh-CN.js",
    "content": "/**\r\n * Bootstrap Table Chinese translation\r\n * Author: Zhixin Wen<wenzhixin2010@gmail.com>\r\n */\r\n$.fn.bootstrapTable.locales['zh-CN'] = {\r\n  formatShowSearch: function formatShowSearch() {\r\n    return '隐藏/显示搜索';\r\n  },\r\n  formatPageGo: function formatPageGo() {\r\n    return '跳转';\r\n  },\r\n  formatCopyRows: function formatCopyRows() {\r\n    return '复制行';\r\n  },\r\n  formatPrint: function formatPrint() {\r\n    return '打印';\r\n  },\r\n  formatLoadingMessage: function formatLoadingMessage() {\r\n    return '正在努力地加载数据中，请稍候';\r\n  },\r\n  formatRecordsPerPage: function formatRecordsPerPage(pageNumber) {\r\n    return \"每页显示 \".concat(pageNumber, \" 条记录\");\r\n  },\r\n  formatShowingRows: function formatShowingRows(pageFrom, pageTo, totalRows, totalNotFiltered) {\r\n    if (totalNotFiltered !== undefined && totalNotFiltered > 0 && totalNotFiltered > totalRows) {\r\n      return \"显示第 \".concat(pageFrom, \" 到第 \").concat(pageTo, \" 条记录，总共 \").concat(totalRows, \" 条记录（从 \").concat(totalNotFiltered, \" 总记录中过滤）\");\r\n    }\r\n    return \"显示第 \".concat(pageFrom, \" 到第 \").concat(pageTo, \" 条记录，总共 \").concat(totalRows, \" 条记录\");\r\n  },\r\n  formatSRPaginationPreText: function formatSRPaginationPreText() {\r\n    return '上一页';\r\n  },\r\n  formatSRPaginationPageText: function formatSRPaginationPageText(page) {\r\n    return \"第\".concat(page, \"页\");\r\n  },\r\n  formatSRPaginationNextText: function formatSRPaginationNextText() {\r\n    return '下一页';\r\n  },\r\n  formatDetailPagination: function formatDetailPagination(totalRows) {\r\n    return \"总共 \".concat(totalRows, \" 条记录\");\r\n  },\r\n  formatClearSearch: function formatClearSearch() {\r\n    return '清空过滤';\r\n  },\r\n  formatSearch: function formatSearch() {\r\n    return '搜索';\r\n  },\r\n  formatNoMatches: function formatNoMatches() {\r\n    return '没有找到匹配的记录';\r\n  },\r\n  formatPaginationSwitch: function formatPaginationSwitch() {\r\n    return '隐藏/显示分页';\r\n  },\r\n  formatPaginationSwitchDown: function formatPaginationSwitchDown() {\r\n    return '显示分页';\r\n  },\r\n  formatPaginationSwitchUp: function formatPaginationSwitchUp() {\r\n    return '隐藏分页';\r\n  },\r\n  formatRefresh: function formatRefresh() {\r\n    return '刷新';\r\n  },\r\n  formatToggle: function formatToggle() {\r\n    return '切换';\r\n  },\r\n  formatToggleOn: function formatToggleOn() {\r\n    return '显示卡片视图';\r\n  },\r\n  formatToggleOff: function formatToggleOff() {\r\n    return '隐藏卡片视图';\r\n  },\r\n  formatColumns: function formatColumns() {\r\n    return '列';\r\n  },\r\n  formatColumnsToggleAll: function formatColumnsToggleAll() {\r\n    return '切换所有';\r\n  },\r\n  formatFullscreen: function formatFullscreen() {\r\n    return '全屏';\r\n  },\r\n  formatAllRows: function formatAllRows() {\r\n    return '所有';\r\n  },\r\n  formatAutoRefresh: function formatAutoRefresh() {\r\n    return '自动刷新';\r\n  },\r\n  formatExport: function formatExport() {\r\n    return '导出数据';\r\n  },\r\n  formatJumpTo: function formatJumpTo() {\r\n    return '跳转';\r\n  },\r\n  formatAdvancedSearch: function formatAdvancedSearch() {\r\n    return '高级搜索';\r\n  },\r\n  formatAdvancedCloseButton: function formatAdvancedCloseButton() {\r\n    return '关闭';\r\n  },\r\n  formatFilterControlSwitch: function formatFilterControlSwitch() {\r\n    return '隐藏/显示过滤控制';\r\n  },\r\n  formatFilterControlSwitchHide: function formatFilterControlSwitchHide() {\r\n    return '隐藏过滤控制';\r\n  },\r\n  formatFilterControlSwitchShow: function formatFilterControlSwitchShow() {\r\n    return '显示过滤控制';\r\n  }\r\n};\r\n$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['zh-CN']);\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/cropper/cropper.css",
    "content": "/*!\n * Cropper.js v1.5.12\n * https://fengyuanchen.github.io/cropperjs\n *\n * Copyright 2015-present Chen Fengyuan\n * Released under the MIT license\n *\n * Date: 2021-06-12T08:00:11.623Z\n */\n\n.cropper-container {\n  direction: ltr;\n  font-size: 0;\n  line-height: 0;\n  position: relative;\n  -ms-touch-action: none;\n  touch-action: none;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.cropper-container img {\n  display: block;\n  height: 100%;\n  image-orientation: 0deg;\n  max-height: none !important;\n  max-width: none !important;\n  min-height: 0 !important;\n  min-width: 0 !important;\n  width: 100%;\n}\n\n.cropper-wrap-box,\n.cropper-canvas,\n.cropper-drag-box,\n.cropper-crop-box,\n.cropper-modal {\n  bottom: 0;\n  left: 0;\n  position: absolute;\n  right: 0;\n  top: 0;\n}\n\n.cropper-wrap-box,\n.cropper-canvas {\n  overflow: hidden;\n}\n\n.cropper-drag-box {\n  background-color: #fff;\n  opacity: 0;\n}\n\n.cropper-modal {\n  background-color: #000;\n  opacity: 0.5;\n}\n\n.cropper-view-box {\n  display: block;\n  height: 100%;\n  outline: 1px solid #39f;\n  outline-color: rgba(51, 153, 255, 0.75);\n  overflow: hidden;\n  width: 100%;\n}\n\n.cropper-dashed {\n  border: 0 dashed #eee;\n  display: block;\n  opacity: 0.5;\n  position: absolute;\n}\n\n.cropper-dashed.dashed-h {\n  border-bottom-width: 1px;\n  border-top-width: 1px;\n  height: calc(100% / 3);\n  left: 0;\n  top: calc(100% / 3);\n  width: 100%;\n}\n\n.cropper-dashed.dashed-v {\n  border-left-width: 1px;\n  border-right-width: 1px;\n  height: 100%;\n  left: calc(100% / 3);\n  top: 0;\n  width: calc(100% / 3);\n}\n\n.cropper-center {\n  display: block;\n  height: 0;\n  left: 50%;\n  opacity: 0.75;\n  position: absolute;\n  top: 50%;\n  width: 0;\n}\n\n.cropper-center::before,\n.cropper-center::after {\n  background-color: #eee;\n  content: ' ';\n  display: block;\n  position: absolute;\n}\n\n.cropper-center::before {\n  height: 1px;\n  left: -3px;\n  top: 0;\n  width: 7px;\n}\n\n.cropper-center::after {\n  height: 7px;\n  left: 0;\n  top: -3px;\n  width: 1px;\n}\n\n.cropper-face,\n.cropper-line,\n.cropper-point {\n  display: block;\n  height: 100%;\n  opacity: 0.1;\n  position: absolute;\n  width: 100%;\n}\n\n.cropper-face {\n  background-color: #fff;\n  left: 0;\n  top: 0;\n}\n\n.cropper-line {\n  background-color: #39f;\n}\n\n.cropper-line.line-e {\n  cursor: ew-resize;\n  right: -3px;\n  top: 0;\n  width: 5px;\n}\n\n.cropper-line.line-n {\n  cursor: ns-resize;\n  height: 5px;\n  left: 0;\n  top: -3px;\n}\n\n.cropper-line.line-w {\n  cursor: ew-resize;\n  left: -3px;\n  top: 0;\n  width: 5px;\n}\n\n.cropper-line.line-s {\n  bottom: -3px;\n  cursor: ns-resize;\n  height: 5px;\n  left: 0;\n}\n\n.cropper-point {\n  background-color: #39f;\n  height: 5px;\n  opacity: 0.75;\n  width: 5px;\n}\n\n.cropper-point.point-e {\n  cursor: ew-resize;\n  margin-top: -3px;\n  right: -3px;\n  top: 50%;\n}\n\n.cropper-point.point-n {\n  cursor: ns-resize;\n  left: 50%;\n  margin-left: -3px;\n  top: -3px;\n}\n\n.cropper-point.point-w {\n  cursor: ew-resize;\n  left: -3px;\n  margin-top: -3px;\n  top: 50%;\n}\n\n.cropper-point.point-s {\n  bottom: -3px;\n  cursor: s-resize;\n  left: 50%;\n  margin-left: -3px;\n}\n\n.cropper-point.point-ne {\n  cursor: nesw-resize;\n  right: -3px;\n  top: -3px;\n}\n\n.cropper-point.point-nw {\n  cursor: nwse-resize;\n  left: -3px;\n  top: -3px;\n}\n\n.cropper-point.point-sw {\n  bottom: -3px;\n  cursor: nesw-resize;\n  left: -3px;\n}\n\n.cropper-point.point-se {\n  bottom: -3px;\n  cursor: nwse-resize;\n  height: 20px;\n  opacity: 1;\n  right: -3px;\n  width: 20px;\n}\n\n@media (min-width: 768px) {\n  .cropper-point.point-se {\n    height: 15px;\n    width: 15px;\n  }\n}\n\n@media (min-width: 992px) {\n  .cropper-point.point-se {\n    height: 10px;\n    width: 10px;\n  }\n}\n\n@media (min-width: 1200px) {\n  .cropper-point.point-se {\n    height: 5px;\n    opacity: 0.75;\n    width: 5px;\n  }\n}\n\n.cropper-point.point-se::before {\n  background-color: #39f;\n  bottom: -50%;\n  content: ' ';\n  display: block;\n  height: 200%;\n  opacity: 0;\n  position: absolute;\n  right: -50%;\n  width: 200%;\n}\n\n.cropper-invisible {\n  opacity: 0;\n}\n\n.cropper-bg {\n  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');\n}\n\n.cropper-hide {\n  display: block;\n  height: 0;\n  position: absolute;\n  width: 0;\n}\n\n.cropper-hidden {\n  display: none !important;\n}\n\n.cropper-move {\n  cursor: move;\n}\n\n.cropper-crop {\n  cursor: crosshair;\n}\n\n.cropper-disabled .cropper-drag-box,\n.cropper-disabled .cropper-face,\n.cropper-disabled .cropper-line,\n.cropper-disabled .cropper-point {\n  cursor: not-allowed;\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/cropper/cropper.js",
    "content": "/*!\n * Cropper.js v1.5.12\n * https://fengyuanchen.github.io/cropperjs\n *\n * Copyright 2015-present Chen Fengyuan\n * Released under the MIT license\n *\n * Date: 2021-06-12T08:00:17.411Z\n */\n\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n  typeof define === 'function' && define.amd ? define(factory) :\n  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Cropper = factory());\n}(this, (function () { 'use strict';\n\n  function ownKeys(object, enumerableOnly) {\n    var keys = Object.keys(object);\n\n    if (Object.getOwnPropertySymbols) {\n      var symbols = Object.getOwnPropertySymbols(object);\n\n      if (enumerableOnly) {\n        symbols = symbols.filter(function (sym) {\n          return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n        });\n      }\n\n      keys.push.apply(keys, symbols);\n    }\n\n    return keys;\n  }\n\n  function _objectSpread2(target) {\n    for (var i = 1; i < arguments.length; i++) {\n      var source = arguments[i] != null ? arguments[i] : {};\n\n      if (i % 2) {\n        ownKeys(Object(source), true).forEach(function (key) {\n          _defineProperty(target, key, source[key]);\n        });\n      } else if (Object.getOwnPropertyDescriptors) {\n        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));\n      } else {\n        ownKeys(Object(source)).forEach(function (key) {\n          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n        });\n      }\n    }\n\n    return target;\n  }\n\n  function _typeof(obj) {\n    \"@babel/helpers - typeof\";\n\n    if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n      _typeof = function (obj) {\n        return typeof obj;\n      };\n    } else {\n      _typeof = function (obj) {\n        return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n      };\n    }\n\n    return _typeof(obj);\n  }\n\n  function _classCallCheck(instance, Constructor) {\n    if (!(instance instanceof Constructor)) {\n      throw new TypeError(\"Cannot call a class as a function\");\n    }\n  }\n\n  function _defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      Object.defineProperty(target, descriptor.key, descriptor);\n    }\n  }\n\n  function _createClass(Constructor, protoProps, staticProps) {\n    if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) _defineProperties(Constructor, staticProps);\n    return Constructor;\n  }\n\n  function _defineProperty(obj, key, value) {\n    if (key in obj) {\n      Object.defineProperty(obj, key, {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    } else {\n      obj[key] = value;\n    }\n\n    return obj;\n  }\n\n  function _toConsumableArray(arr) {\n    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();\n  }\n\n  function _arrayWithoutHoles(arr) {\n    if (Array.isArray(arr)) return _arrayLikeToArray(arr);\n  }\n\n  function _iterableToArray(iter) {\n    if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter);\n  }\n\n  function _unsupportedIterableToArray(o, minLen) {\n    if (!o) return;\n    if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n    var n = Object.prototype.toString.call(o).slice(8, -1);\n    if (n === \"Object\" && o.constructor) n = o.constructor.name;\n    if (n === \"Map\" || n === \"Set\") return Array.from(o);\n    if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n  }\n\n  function _arrayLikeToArray(arr, len) {\n    if (len == null || len > arr.length) len = arr.length;\n\n    for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n\n    return arr2;\n  }\n\n  function _nonIterableSpread() {\n    throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n  }\n\n  var IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== 'undefined';\n  var WINDOW = IS_BROWSER ? window : {};\n  var IS_TOUCH_DEVICE = IS_BROWSER && WINDOW.document.documentElement ? 'ontouchstart' in WINDOW.document.documentElement : false;\n  var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;\n  var NAMESPACE = 'cropper'; // Actions\n\n  var ACTION_ALL = 'all';\n  var ACTION_CROP = 'crop';\n  var ACTION_MOVE = 'move';\n  var ACTION_ZOOM = 'zoom';\n  var ACTION_EAST = 'e';\n  var ACTION_WEST = 'w';\n  var ACTION_SOUTH = 's';\n  var ACTION_NORTH = 'n';\n  var ACTION_NORTH_EAST = 'ne';\n  var ACTION_NORTH_WEST = 'nw';\n  var ACTION_SOUTH_EAST = 'se';\n  var ACTION_SOUTH_WEST = 'sw'; // Classes\n\n  var CLASS_CROP = \"\".concat(NAMESPACE, \"-crop\");\n  var CLASS_DISABLED = \"\".concat(NAMESPACE, \"-disabled\");\n  var CLASS_HIDDEN = \"\".concat(NAMESPACE, \"-hidden\");\n  var CLASS_HIDE = \"\".concat(NAMESPACE, \"-hide\");\n  var CLASS_INVISIBLE = \"\".concat(NAMESPACE, \"-invisible\");\n  var CLASS_MODAL = \"\".concat(NAMESPACE, \"-modal\");\n  var CLASS_MOVE = \"\".concat(NAMESPACE, \"-move\"); // Data keys\n\n  var DATA_ACTION = \"\".concat(NAMESPACE, \"Action\");\n  var DATA_PREVIEW = \"\".concat(NAMESPACE, \"Preview\"); // Drag modes\n\n  var DRAG_MODE_CROP = 'crop';\n  var DRAG_MODE_MOVE = 'move';\n  var DRAG_MODE_NONE = 'none'; // Events\n\n  var EVENT_CROP = 'crop';\n  var EVENT_CROP_END = 'cropend';\n  var EVENT_CROP_MOVE = 'cropmove';\n  var EVENT_CROP_START = 'cropstart';\n  var EVENT_DBLCLICK = 'dblclick';\n  var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';\n  var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';\n  var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';\n  var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;\n  var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;\n  var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;\n  var EVENT_READY = 'ready';\n  var EVENT_RESIZE = 'resize';\n  var EVENT_WHEEL = 'wheel';\n  var EVENT_ZOOM = 'zoom'; // Mime types\n\n  var MIME_TYPE_JPEG = 'image/jpeg'; // RegExps\n\n  var REGEXP_ACTIONS = /^e|w|s|n|se|sw|ne|nw|all|crop|move|zoom$/;\n  var REGEXP_DATA_URL = /^data:/;\n  var REGEXP_DATA_URL_JPEG = /^data:image\\/jpeg;base64,/;\n  var REGEXP_TAG_NAME = /^img|canvas$/i; // Misc\n  // Inspired by the default width and height of a canvas element.\n\n  var MIN_CONTAINER_WIDTH = 200;\n  var MIN_CONTAINER_HEIGHT = 100;\n\n  var DEFAULTS = {\n    // Define the view mode of the cropper\n    viewMode: 0,\n    // 0, 1, 2, 3\n    // Define the dragging mode of the cropper\n    dragMode: DRAG_MODE_CROP,\n    // 'crop', 'move' or 'none'\n    // Define the initial aspect ratio of the crop box\n    initialAspectRatio: NaN,\n    // Define the aspect ratio of the crop box\n    aspectRatio: NaN,\n    // An object with the previous cropping result data\n    data: null,\n    // A selector for adding extra containers to preview\n    preview: '',\n    // Re-render the cropper when resize the window\n    responsive: true,\n    // Restore the cropped area after resize the window\n    restore: true,\n    // Check if the current image is a cross-origin image\n    checkCrossOrigin: true,\n    // Check the current image's Exif Orientation information\n    checkOrientation: true,\n    // Show the black modal\n    modal: true,\n    // Show the dashed lines for guiding\n    guides: true,\n    // Show the center indicator for guiding\n    center: true,\n    // Show the white modal to highlight the crop box\n    highlight: true,\n    // Show the grid background\n    background: true,\n    // Enable to crop the image automatically when initialize\n    autoCrop: true,\n    // Define the percentage of automatic cropping area when initializes\n    autoCropArea: 0.8,\n    // Enable to move the image\n    movable: true,\n    // Enable to rotate the image\n    rotatable: true,\n    // Enable to scale the image\n    scalable: true,\n    // Enable to zoom the image\n    zoomable: true,\n    // Enable to zoom the image by dragging touch\n    zoomOnTouch: true,\n    // Enable to zoom the image by wheeling mouse\n    zoomOnWheel: true,\n    // Define zoom ratio when zoom the image by wheeling mouse\n    wheelZoomRatio: 0.1,\n    // Enable to move the crop box\n    cropBoxMovable: true,\n    // Enable to resize the crop box\n    cropBoxResizable: true,\n    // Toggle drag mode between \"crop\" and \"move\" when click twice on the cropper\n    toggleDragModeOnDblclick: true,\n    // Size limitation\n    minCanvasWidth: 0,\n    minCanvasHeight: 0,\n    minCropBoxWidth: 0,\n    minCropBoxHeight: 0,\n    minContainerWidth: MIN_CONTAINER_WIDTH,\n    minContainerHeight: MIN_CONTAINER_HEIGHT,\n    // Shortcuts of events\n    ready: null,\n    cropstart: null,\n    cropmove: null,\n    cropend: null,\n    crop: null,\n    zoom: null\n  };\n\n  var TEMPLATE = '<div class=\"cropper-container\" touch-action=\"none\">' + '<div class=\"cropper-wrap-box\">' + '<div class=\"cropper-canvas\"></div>' + '</div>' + '<div class=\"cropper-drag-box\"></div>' + '<div class=\"cropper-crop-box\">' + '<span class=\"cropper-view-box\"></span>' + '<span class=\"cropper-dashed dashed-h\"></span>' + '<span class=\"cropper-dashed dashed-v\"></span>' + '<span class=\"cropper-center\"></span>' + '<span class=\"cropper-face\"></span>' + '<span class=\"cropper-line line-e\" data-cropper-action=\"e\"></span>' + '<span class=\"cropper-line line-n\" data-cropper-action=\"n\"></span>' + '<span class=\"cropper-line line-w\" data-cropper-action=\"w\"></span>' + '<span class=\"cropper-line line-s\" data-cropper-action=\"s\"></span>' + '<span class=\"cropper-point point-e\" data-cropper-action=\"e\"></span>' + '<span class=\"cropper-point point-n\" data-cropper-action=\"n\"></span>' + '<span class=\"cropper-point point-w\" data-cropper-action=\"w\"></span>' + '<span class=\"cropper-point point-s\" data-cropper-action=\"s\"></span>' + '<span class=\"cropper-point point-ne\" data-cropper-action=\"ne\"></span>' + '<span class=\"cropper-point point-nw\" data-cropper-action=\"nw\"></span>' + '<span class=\"cropper-point point-sw\" data-cropper-action=\"sw\"></span>' + '<span class=\"cropper-point point-se\" data-cropper-action=\"se\"></span>' + '</div>' + '</div>';\n\n  /**\n   * Check if the given value is not a number.\n   */\n\n  var isNaN = Number.isNaN || WINDOW.isNaN;\n  /**\n   * Check if the given value is a number.\n   * @param {*} value - The value to check.\n   * @returns {boolean} Returns `true` if the given value is a number, else `false`.\n   */\n\n  function isNumber(value) {\n    return typeof value === 'number' && !isNaN(value);\n  }\n  /**\n   * Check if the given value is a positive number.\n   * @param {*} value - The value to check.\n   * @returns {boolean} Returns `true` if the given value is a positive number, else `false`.\n   */\n\n  var isPositiveNumber = function isPositiveNumber(value) {\n    return value > 0 && value < Infinity;\n  };\n  /**\n   * Check if the given value is undefined.\n   * @param {*} value - The value to check.\n   * @returns {boolean} Returns `true` if the given value is undefined, else `false`.\n   */\n\n  function isUndefined(value) {\n    return typeof value === 'undefined';\n  }\n  /**\n   * Check if the given value is an object.\n   * @param {*} value - The value to check.\n   * @returns {boolean} Returns `true` if the given value is an object, else `false`.\n   */\n\n  function isObject(value) {\n    return _typeof(value) === 'object' && value !== null;\n  }\n  var hasOwnProperty = Object.prototype.hasOwnProperty;\n  /**\n   * Check if the given value is a plain object.\n   * @param {*} value - The value to check.\n   * @returns {boolean} Returns `true` if the given value is a plain object, else `false`.\n   */\n\n  function isPlainObject(value) {\n    if (!isObject(value)) {\n      return false;\n    }\n\n    try {\n      var _constructor = value.constructor;\n      var prototype = _constructor.prototype;\n      return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');\n    } catch (error) {\n      return false;\n    }\n  }\n  /**\n   * Check if the given value is a function.\n   * @param {*} value - The value to check.\n   * @returns {boolean} Returns `true` if the given value is a function, else `false`.\n   */\n\n  function isFunction(value) {\n    return typeof value === 'function';\n  }\n  var slice = Array.prototype.slice;\n  /**\n   * Convert array-like or iterable object to an array.\n   * @param {*} value - The value to convert.\n   * @returns {Array} Returns a new array.\n   */\n\n  function toArray(value) {\n    return Array.from ? Array.from(value) : slice.call(value);\n  }\n  /**\n   * Iterate the given data.\n   * @param {*} data - The data to iterate.\n   * @param {Function} callback - The process function for each element.\n   * @returns {*} The original data.\n   */\n\n  function forEach(data, callback) {\n    if (data && isFunction(callback)) {\n      if (Array.isArray(data) || isNumber(data.length)\n      /* array-like */\n      ) {\n          toArray(data).forEach(function (value, key) {\n            callback.call(data, value, key, data);\n          });\n        } else if (isObject(data)) {\n        Object.keys(data).forEach(function (key) {\n          callback.call(data, data[key], key, data);\n        });\n      }\n    }\n\n    return data;\n  }\n  /**\n   * Extend the given object.\n   * @param {*} target - The target object to extend.\n   * @param {*} args - The rest objects for merging to the target object.\n   * @returns {Object} The extended object.\n   */\n\n  var assign = Object.assign || function assign(target) {\n    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n      args[_key - 1] = arguments[_key];\n    }\n\n    if (isObject(target) && args.length > 0) {\n      args.forEach(function (arg) {\n        if (isObject(arg)) {\n          Object.keys(arg).forEach(function (key) {\n            target[key] = arg[key];\n          });\n        }\n      });\n    }\n\n    return target;\n  };\n  var REGEXP_DECIMALS = /\\.\\d*(?:0|9){12}\\d*$/;\n  /**\n   * Normalize decimal number.\n   * Check out {@link https://0.30000000000000004.com/}\n   * @param {number} value - The value to normalize.\n   * @param {number} [times=100000000000] - The times for normalizing.\n   * @returns {number} Returns the normalized number.\n   */\n\n  function normalizeDecimalNumber(value) {\n    var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000;\n    return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value;\n  }\n  var REGEXP_SUFFIX = /^width|height|left|top|marginLeft|marginTop$/;\n  /**\n   * Apply styles to the given element.\n   * @param {Element} element - The target element.\n   * @param {Object} styles - The styles for applying.\n   */\n\n  function setStyle(element, styles) {\n    var style = element.style;\n    forEach(styles, function (value, property) {\n      if (REGEXP_SUFFIX.test(property) && isNumber(value)) {\n        value = \"\".concat(value, \"px\");\n      }\n\n      style[property] = value;\n    });\n  }\n  /**\n   * Check if the given element has a special class.\n   * @param {Element} element - The element to check.\n   * @param {string} value - The class to search.\n   * @returns {boolean} Returns `true` if the special class was found.\n   */\n\n  function hasClass(element, value) {\n    return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;\n  }\n  /**\n   * Add classes to the given element.\n   * @param {Element} element - The target element.\n   * @param {string} value - The classes to be added.\n   */\n\n  function addClass(element, value) {\n    if (!value) {\n      return;\n    }\n\n    if (isNumber(element.length)) {\n      forEach(element, function (elem) {\n        addClass(elem, value);\n      });\n      return;\n    }\n\n    if (element.classList) {\n      element.classList.add(value);\n      return;\n    }\n\n    var className = element.className.trim();\n\n    if (!className) {\n      element.className = value;\n    } else if (className.indexOf(value) < 0) {\n      element.className = \"\".concat(className, \" \").concat(value);\n    }\n  }\n  /**\n   * Remove classes from the given element.\n   * @param {Element} element - The target element.\n   * @param {string} value - The classes to be removed.\n   */\n\n  function removeClass(element, value) {\n    if (!value) {\n      return;\n    }\n\n    if (isNumber(element.length)) {\n      forEach(element, function (elem) {\n        removeClass(elem, value);\n      });\n      return;\n    }\n\n    if (element.classList) {\n      element.classList.remove(value);\n      return;\n    }\n\n    if (element.className.indexOf(value) >= 0) {\n      element.className = element.className.replace(value, '');\n    }\n  }\n  /**\n   * Add or remove classes from the given element.\n   * @param {Element} element - The target element.\n   * @param {string} value - The classes to be toggled.\n   * @param {boolean} added - Add only.\n   */\n\n  function toggleClass(element, value, added) {\n    if (!value) {\n      return;\n    }\n\n    if (isNumber(element.length)) {\n      forEach(element, function (elem) {\n        toggleClass(elem, value, added);\n      });\n      return;\n    } // IE10-11 doesn't support the second parameter of `classList.toggle`\n\n\n    if (added) {\n      addClass(element, value);\n    } else {\n      removeClass(element, value);\n    }\n  }\n  var REGEXP_CAMEL_CASE = /([a-z\\d])([A-Z])/g;\n  /**\n   * Transform the given string from camelCase to kebab-case\n   * @param {string} value - The value to transform.\n   * @returns {string} The transformed value.\n   */\n\n  function toParamCase(value) {\n    return value.replace(REGEXP_CAMEL_CASE, '$1-$2').toLowerCase();\n  }\n  /**\n   * Get data from the given element.\n   * @param {Element} element - The target element.\n   * @param {string} name - The data key to get.\n   * @returns {string} The data value.\n   */\n\n  function getData(element, name) {\n    if (isObject(element[name])) {\n      return element[name];\n    }\n\n    if (element.dataset) {\n      return element.dataset[name];\n    }\n\n    return element.getAttribute(\"data-\".concat(toParamCase(name)));\n  }\n  /**\n   * Set data to the given element.\n   * @param {Element} element - The target element.\n   * @param {string} name - The data key to set.\n   * @param {string} data - The data value.\n   */\n\n  function setData(element, name, data) {\n    if (isObject(data)) {\n      element[name] = data;\n    } else if (element.dataset) {\n      element.dataset[name] = data;\n    } else {\n      element.setAttribute(\"data-\".concat(toParamCase(name)), data);\n    }\n  }\n  /**\n   * Remove data from the given element.\n   * @param {Element} element - The target element.\n   * @param {string} name - The data key to remove.\n   */\n\n  function removeData(element, name) {\n    if (isObject(element[name])) {\n      try {\n        delete element[name];\n      } catch (error) {\n        element[name] = undefined;\n      }\n    } else if (element.dataset) {\n      // #128 Safari not allows to delete dataset property\n      try {\n        delete element.dataset[name];\n      } catch (error) {\n        element.dataset[name] = undefined;\n      }\n    } else {\n      element.removeAttribute(\"data-\".concat(toParamCase(name)));\n    }\n  }\n  var REGEXP_SPACES = /\\s\\s*/;\n\n  var onceSupported = function () {\n    var supported = false;\n\n    if (IS_BROWSER) {\n      var once = false;\n\n      var listener = function listener() {};\n\n      var options = Object.defineProperty({}, 'once', {\n        get: function get() {\n          supported = true;\n          return once;\n        },\n\n        /**\n         * This setter can fix a `TypeError` in strict mode\n         * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}\n         * @param {boolean} value - The value to set\n         */\n        set: function set(value) {\n          once = value;\n        }\n      });\n      WINDOW.addEventListener('test', listener, options);\n      WINDOW.removeEventListener('test', listener, options);\n    }\n\n    return supported;\n  }();\n  /**\n   * Remove event listener from the target element.\n   * @param {Element} element - The event target.\n   * @param {string} type - The event type(s).\n   * @param {Function} listener - The event listener.\n   * @param {Object} options - The event options.\n   */\n\n\n  function removeListener(element, type, listener) {\n    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};\n    var handler = listener;\n    type.trim().split(REGEXP_SPACES).forEach(function (event) {\n      if (!onceSupported) {\n        var listeners = element.listeners;\n\n        if (listeners && listeners[event] && listeners[event][listener]) {\n          handler = listeners[event][listener];\n          delete listeners[event][listener];\n\n          if (Object.keys(listeners[event]).length === 0) {\n            delete listeners[event];\n          }\n\n          if (Object.keys(listeners).length === 0) {\n            delete element.listeners;\n          }\n        }\n      }\n\n      element.removeEventListener(event, handler, options);\n    });\n  }\n  /**\n   * Add event listener to the target element.\n   * @param {Element} element - The event target.\n   * @param {string} type - The event type(s).\n   * @param {Function} listener - The event listener.\n   * @param {Object} options - The event options.\n   */\n\n  function addListener(element, type, listener) {\n    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};\n    var _handler = listener;\n    type.trim().split(REGEXP_SPACES).forEach(function (event) {\n      if (options.once && !onceSupported) {\n        var _element$listeners = element.listeners,\n            listeners = _element$listeners === void 0 ? {} : _element$listeners;\n\n        _handler = function handler() {\n          delete listeners[event][listener];\n          element.removeEventListener(event, _handler, options);\n\n          for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n            args[_key2] = arguments[_key2];\n          }\n\n          listener.apply(element, args);\n        };\n\n        if (!listeners[event]) {\n          listeners[event] = {};\n        }\n\n        if (listeners[event][listener]) {\n          element.removeEventListener(event, listeners[event][listener], options);\n        }\n\n        listeners[event][listener] = _handler;\n        element.listeners = listeners;\n      }\n\n      element.addEventListener(event, _handler, options);\n    });\n  }\n  /**\n   * Dispatch event on the target element.\n   * @param {Element} element - The event target.\n   * @param {string} type - The event type(s).\n   * @param {Object} data - The additional event data.\n   * @returns {boolean} Indicate if the event is default prevented or not.\n   */\n\n  function dispatchEvent(element, type, data) {\n    var event; // Event and CustomEvent on IE9-11 are global objects, not constructors\n\n    if (isFunction(Event) && isFunction(CustomEvent)) {\n      event = new CustomEvent(type, {\n        detail: data,\n        bubbles: true,\n        cancelable: true\n      });\n    } else {\n      event = document.createEvent('CustomEvent');\n      event.initCustomEvent(type, true, true, data);\n    }\n\n    return element.dispatchEvent(event);\n  }\n  /**\n   * Get the offset base on the document.\n   * @param {Element} element - The target element.\n   * @returns {Object} The offset data.\n   */\n\n  function getOffset(element) {\n    var box = element.getBoundingClientRect();\n    return {\n      left: box.left + (window.pageXOffset - document.documentElement.clientLeft),\n      top: box.top + (window.pageYOffset - document.documentElement.clientTop)\n    };\n  }\n  var location = WINDOW.location;\n  var REGEXP_ORIGINS = /^(\\w+:)\\/\\/([^:/?#]*):?(\\d*)/i;\n  /**\n   * Check if the given URL is a cross origin URL.\n   * @param {string} url - The target URL.\n   * @returns {boolean} Returns `true` if the given URL is a cross origin URL, else `false`.\n   */\n\n  function isCrossOriginURL(url) {\n    var parts = url.match(REGEXP_ORIGINS);\n    return parts !== null && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);\n  }\n  /**\n   * Add timestamp to the given URL.\n   * @param {string} url - The target URL.\n   * @returns {string} The result URL.\n   */\n\n  function addTimestamp(url) {\n    var timestamp = \"timestamp=\".concat(new Date().getTime());\n    return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp;\n  }\n  /**\n   * Get transforms base on the given object.\n   * @param {Object} obj - The target object.\n   * @returns {string} A string contains transform values.\n   */\n\n  function getTransforms(_ref) {\n    var rotate = _ref.rotate,\n        scaleX = _ref.scaleX,\n        scaleY = _ref.scaleY,\n        translateX = _ref.translateX,\n        translateY = _ref.translateY;\n    var values = [];\n\n    if (isNumber(translateX) && translateX !== 0) {\n      values.push(\"translateX(\".concat(translateX, \"px)\"));\n    }\n\n    if (isNumber(translateY) && translateY !== 0) {\n      values.push(\"translateY(\".concat(translateY, \"px)\"));\n    } // Rotate should come first before scale to match orientation transform\n\n\n    if (isNumber(rotate) && rotate !== 0) {\n      values.push(\"rotate(\".concat(rotate, \"deg)\"));\n    }\n\n    if (isNumber(scaleX) && scaleX !== 1) {\n      values.push(\"scaleX(\".concat(scaleX, \")\"));\n    }\n\n    if (isNumber(scaleY) && scaleY !== 1) {\n      values.push(\"scaleY(\".concat(scaleY, \")\"));\n    }\n\n    var transform = values.length ? values.join(' ') : 'none';\n    return {\n      WebkitTransform: transform,\n      msTransform: transform,\n      transform: transform\n    };\n  }\n  /**\n   * Get the max ratio of a group of pointers.\n   * @param {string} pointers - The target pointers.\n   * @returns {number} The result ratio.\n   */\n\n  function getMaxZoomRatio(pointers) {\n    var pointers2 = _objectSpread2({}, pointers);\n\n    var maxRatio = 0;\n    forEach(pointers, function (pointer, pointerId) {\n      delete pointers2[pointerId];\n      forEach(pointers2, function (pointer2) {\n        var x1 = Math.abs(pointer.startX - pointer2.startX);\n        var y1 = Math.abs(pointer.startY - pointer2.startY);\n        var x2 = Math.abs(pointer.endX - pointer2.endX);\n        var y2 = Math.abs(pointer.endY - pointer2.endY);\n        var z1 = Math.sqrt(x1 * x1 + y1 * y1);\n        var z2 = Math.sqrt(x2 * x2 + y2 * y2);\n        var ratio = (z2 - z1) / z1;\n\n        if (Math.abs(ratio) > Math.abs(maxRatio)) {\n          maxRatio = ratio;\n        }\n      });\n    });\n    return maxRatio;\n  }\n  /**\n   * Get a pointer from an event object.\n   * @param {Object} event - The target event object.\n   * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not.\n   * @returns {Object} The result pointer contains start and/or end point coordinates.\n   */\n\n  function getPointer(_ref2, endOnly) {\n    var pageX = _ref2.pageX,\n        pageY = _ref2.pageY;\n    var end = {\n      endX: pageX,\n      endY: pageY\n    };\n    return endOnly ? end : _objectSpread2({\n      startX: pageX,\n      startY: pageY\n    }, end);\n  }\n  /**\n   * Get the center point coordinate of a group of pointers.\n   * @param {Object} pointers - The target pointers.\n   * @returns {Object} The center point coordinate.\n   */\n\n  function getPointersCenter(pointers) {\n    var pageX = 0;\n    var pageY = 0;\n    var count = 0;\n    forEach(pointers, function (_ref3) {\n      var startX = _ref3.startX,\n          startY = _ref3.startY;\n      pageX += startX;\n      pageY += startY;\n      count += 1;\n    });\n    pageX /= count;\n    pageY /= count;\n    return {\n      pageX: pageX,\n      pageY: pageY\n    };\n  }\n  /**\n   * Get the max sizes in a rectangle under the given aspect ratio.\n   * @param {Object} data - The original sizes.\n   * @param {string} [type='contain'] - The adjust type.\n   * @returns {Object} The result sizes.\n   */\n\n  function getAdjustedSizes(_ref4) // or 'cover'\n  {\n    var aspectRatio = _ref4.aspectRatio,\n        height = _ref4.height,\n        width = _ref4.width;\n    var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'contain';\n    var isValidWidth = isPositiveNumber(width);\n    var isValidHeight = isPositiveNumber(height);\n\n    if (isValidWidth && isValidHeight) {\n      var adjustedWidth = height * aspectRatio;\n\n      if (type === 'contain' && adjustedWidth > width || type === 'cover' && adjustedWidth < width) {\n        height = width / aspectRatio;\n      } else {\n        width = height * aspectRatio;\n      }\n    } else if (isValidWidth) {\n      height = width / aspectRatio;\n    } else if (isValidHeight) {\n      width = height * aspectRatio;\n    }\n\n    return {\n      width: width,\n      height: height\n    };\n  }\n  /**\n   * Get the new sizes of a rectangle after rotated.\n   * @param {Object} data - The original sizes.\n   * @returns {Object} The result sizes.\n   */\n\n  function getRotatedSizes(_ref5) {\n    var width = _ref5.width,\n        height = _ref5.height,\n        degree = _ref5.degree;\n    degree = Math.abs(degree) % 180;\n\n    if (degree === 90) {\n      return {\n        width: height,\n        height: width\n      };\n    }\n\n    var arc = degree % 90 * Math.PI / 180;\n    var sinArc = Math.sin(arc);\n    var cosArc = Math.cos(arc);\n    var newWidth = width * cosArc + height * sinArc;\n    var newHeight = width * sinArc + height * cosArc;\n    return degree > 90 ? {\n      width: newHeight,\n      height: newWidth\n    } : {\n      width: newWidth,\n      height: newHeight\n    };\n  }\n  /**\n   * Get a canvas which drew the given image.\n   * @param {HTMLImageElement} image - The image for drawing.\n   * @param {Object} imageData - The image data.\n   * @param {Object} canvasData - The canvas data.\n   * @param {Object} options - The options.\n   * @returns {HTMLCanvasElement} The result canvas.\n   */\n\n  function getSourceCanvas(image, _ref6, _ref7, _ref8) {\n    var imageAspectRatio = _ref6.aspectRatio,\n        imageNaturalWidth = _ref6.naturalWidth,\n        imageNaturalHeight = _ref6.naturalHeight,\n        _ref6$rotate = _ref6.rotate,\n        rotate = _ref6$rotate === void 0 ? 0 : _ref6$rotate,\n        _ref6$scaleX = _ref6.scaleX,\n        scaleX = _ref6$scaleX === void 0 ? 1 : _ref6$scaleX,\n        _ref6$scaleY = _ref6.scaleY,\n        scaleY = _ref6$scaleY === void 0 ? 1 : _ref6$scaleY;\n    var aspectRatio = _ref7.aspectRatio,\n        naturalWidth = _ref7.naturalWidth,\n        naturalHeight = _ref7.naturalHeight;\n    var _ref8$fillColor = _ref8.fillColor,\n        fillColor = _ref8$fillColor === void 0 ? 'transparent' : _ref8$fillColor,\n        _ref8$imageSmoothingE = _ref8.imageSmoothingEnabled,\n        imageSmoothingEnabled = _ref8$imageSmoothingE === void 0 ? true : _ref8$imageSmoothingE,\n        _ref8$imageSmoothingQ = _ref8.imageSmoothingQuality,\n        imageSmoothingQuality = _ref8$imageSmoothingQ === void 0 ? 'low' : _ref8$imageSmoothingQ,\n        _ref8$maxWidth = _ref8.maxWidth,\n        maxWidth = _ref8$maxWidth === void 0 ? Infinity : _ref8$maxWidth,\n        _ref8$maxHeight = _ref8.maxHeight,\n        maxHeight = _ref8$maxHeight === void 0 ? Infinity : _ref8$maxHeight,\n        _ref8$minWidth = _ref8.minWidth,\n        minWidth = _ref8$minWidth === void 0 ? 0 : _ref8$minWidth,\n        _ref8$minHeight = _ref8.minHeight,\n        minHeight = _ref8$minHeight === void 0 ? 0 : _ref8$minHeight;\n    var canvas = document.createElement('canvas');\n    var context = canvas.getContext('2d');\n    var maxSizes = getAdjustedSizes({\n      aspectRatio: aspectRatio,\n      width: maxWidth,\n      height: maxHeight\n    });\n    var minSizes = getAdjustedSizes({\n      aspectRatio: aspectRatio,\n      width: minWidth,\n      height: minHeight\n    }, 'cover');\n    var width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth));\n    var height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight)); // Note: should always use image's natural sizes for drawing as\n    // imageData.naturalWidth === canvasData.naturalHeight when rotate % 180 === 90\n\n    var destMaxSizes = getAdjustedSizes({\n      aspectRatio: imageAspectRatio,\n      width: maxWidth,\n      height: maxHeight\n    });\n    var destMinSizes = getAdjustedSizes({\n      aspectRatio: imageAspectRatio,\n      width: minWidth,\n      height: minHeight\n    }, 'cover');\n    var destWidth = Math.min(destMaxSizes.width, Math.max(destMinSizes.width, imageNaturalWidth));\n    var destHeight = Math.min(destMaxSizes.height, Math.max(destMinSizes.height, imageNaturalHeight));\n    var params = [-destWidth / 2, -destHeight / 2, destWidth, destHeight];\n    canvas.width = normalizeDecimalNumber(width);\n    canvas.height = normalizeDecimalNumber(height);\n    context.fillStyle = fillColor;\n    context.fillRect(0, 0, width, height);\n    context.save();\n    context.translate(width / 2, height / 2);\n    context.rotate(rotate * Math.PI / 180);\n    context.scale(scaleX, scaleY);\n    context.imageSmoothingEnabled = imageSmoothingEnabled;\n    context.imageSmoothingQuality = imageSmoothingQuality;\n    context.drawImage.apply(context, [image].concat(_toConsumableArray(params.map(function (param) {\n      return Math.floor(normalizeDecimalNumber(param));\n    }))));\n    context.restore();\n    return canvas;\n  }\n  var fromCharCode = String.fromCharCode;\n  /**\n   * Get string from char code in data view.\n   * @param {DataView} dataView - The data view for read.\n   * @param {number} start - The start index.\n   * @param {number} length - The read length.\n   * @returns {string} The read result.\n   */\n\n  function getStringFromCharCode(dataView, start, length) {\n    var str = '';\n    length += start;\n\n    for (var i = start; i < length; i += 1) {\n      str += fromCharCode(dataView.getUint8(i));\n    }\n\n    return str;\n  }\n  var REGEXP_DATA_URL_HEAD = /^data:.*,/;\n  /**\n   * Transform Data URL to array buffer.\n   * @param {string} dataURL - The Data URL to transform.\n   * @returns {ArrayBuffer} The result array buffer.\n   */\n\n  function dataURLToArrayBuffer(dataURL) {\n    var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, '');\n    var binary = atob(base64);\n    var arrayBuffer = new ArrayBuffer(binary.length);\n    var uint8 = new Uint8Array(arrayBuffer);\n    forEach(uint8, function (value, i) {\n      uint8[i] = binary.charCodeAt(i);\n    });\n    return arrayBuffer;\n  }\n  /**\n   * Transform array buffer to Data URL.\n   * @param {ArrayBuffer} arrayBuffer - The array buffer to transform.\n   * @param {string} mimeType - The mime type of the Data URL.\n   * @returns {string} The result Data URL.\n   */\n\n  function arrayBufferToDataURL(arrayBuffer, mimeType) {\n    var chunks = []; // Chunk Typed Array for better performance (#435)\n\n    var chunkSize = 8192;\n    var uint8 = new Uint8Array(arrayBuffer);\n\n    while (uint8.length > 0) {\n      // XXX: Babel's `toConsumableArray` helper will throw error in IE or Safari 9\n      // eslint-disable-next-line prefer-spread\n      chunks.push(fromCharCode.apply(null, toArray(uint8.subarray(0, chunkSize))));\n      uint8 = uint8.subarray(chunkSize);\n    }\n\n    return \"data:\".concat(mimeType, \";base64,\").concat(btoa(chunks.join('')));\n  }\n  /**\n   * Get orientation value from given array buffer.\n   * @param {ArrayBuffer} arrayBuffer - The array buffer to read.\n   * @returns {number} The read orientation value.\n   */\n\n  function resetAndGetOrientation(arrayBuffer) {\n    var dataView = new DataView(arrayBuffer);\n    var orientation; // Ignores range error when the image does not have correct Exif information\n\n    try {\n      var littleEndian;\n      var app1Start;\n      var ifdStart; // Only handle JPEG image (start by 0xFFD8)\n\n      if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {\n        var length = dataView.byteLength;\n        var offset = 2;\n\n        while (offset + 1 < length) {\n          if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {\n            app1Start = offset;\n            break;\n          }\n\n          offset += 1;\n        }\n      }\n\n      if (app1Start) {\n        var exifIDCode = app1Start + 4;\n        var tiffOffset = app1Start + 10;\n\n        if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {\n          var endianness = dataView.getUint16(tiffOffset);\n          littleEndian = endianness === 0x4949;\n\n          if (littleEndian || endianness === 0x4D4D\n          /* bigEndian */\n          ) {\n              if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {\n                var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);\n\n                if (firstIFDOffset >= 0x00000008) {\n                  ifdStart = tiffOffset + firstIFDOffset;\n                }\n              }\n            }\n        }\n      }\n\n      if (ifdStart) {\n        var _length = dataView.getUint16(ifdStart, littleEndian);\n\n        var _offset;\n\n        var i;\n\n        for (i = 0; i < _length; i += 1) {\n          _offset = ifdStart + i * 12 + 2;\n\n          if (dataView.getUint16(_offset, littleEndian) === 0x0112\n          /* Orientation */\n          ) {\n              // 8 is the offset of the current tag's value\n              _offset += 8; // Get the original orientation value\n\n              orientation = dataView.getUint16(_offset, littleEndian); // Override the orientation with its default value\n\n              dataView.setUint16(_offset, 1, littleEndian);\n              break;\n            }\n        }\n      }\n    } catch (error) {\n      orientation = 1;\n    }\n\n    return orientation;\n  }\n  /**\n   * Parse Exif Orientation value.\n   * @param {number} orientation - The orientation to parse.\n   * @returns {Object} The parsed result.\n   */\n\n  function parseOrientation(orientation) {\n    var rotate = 0;\n    var scaleX = 1;\n    var scaleY = 1;\n\n    switch (orientation) {\n      // Flip horizontal\n      case 2:\n        scaleX = -1;\n        break;\n      // Rotate left 180°\n\n      case 3:\n        rotate = -180;\n        break;\n      // Flip vertical\n\n      case 4:\n        scaleY = -1;\n        break;\n      // Flip vertical and rotate right 90°\n\n      case 5:\n        rotate = 90;\n        scaleY = -1;\n        break;\n      // Rotate right 90°\n\n      case 6:\n        rotate = 90;\n        break;\n      // Flip horizontal and rotate right 90°\n\n      case 7:\n        rotate = 90;\n        scaleX = -1;\n        break;\n      // Rotate left 90°\n\n      case 8:\n        rotate = -90;\n        break;\n    }\n\n    return {\n      rotate: rotate,\n      scaleX: scaleX,\n      scaleY: scaleY\n    };\n  }\n\n  var render = {\n    render: function render() {\n      this.initContainer();\n      this.initCanvas();\n      this.initCropBox();\n      this.renderCanvas();\n\n      if (this.cropped) {\n        this.renderCropBox();\n      }\n    },\n    initContainer: function initContainer() {\n      var element = this.element,\n          options = this.options,\n          container = this.container,\n          cropper = this.cropper;\n      var minWidth = Number(options.minContainerWidth);\n      var minHeight = Number(options.minContainerHeight);\n      addClass(cropper, CLASS_HIDDEN);\n      removeClass(element, CLASS_HIDDEN);\n      var containerData = {\n        width: Math.max(container.offsetWidth, minWidth >= 0 ? minWidth : MIN_CONTAINER_WIDTH),\n        height: Math.max(container.offsetHeight, minHeight >= 0 ? minHeight : MIN_CONTAINER_HEIGHT)\n      };\n      this.containerData = containerData;\n      setStyle(cropper, {\n        width: containerData.width,\n        height: containerData.height\n      });\n      addClass(element, CLASS_HIDDEN);\n      removeClass(cropper, CLASS_HIDDEN);\n    },\n    // Canvas (image wrapper)\n    initCanvas: function initCanvas() {\n      var containerData = this.containerData,\n          imageData = this.imageData;\n      var viewMode = this.options.viewMode;\n      var rotated = Math.abs(imageData.rotate) % 180 === 90;\n      var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth;\n      var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight;\n      var aspectRatio = naturalWidth / naturalHeight;\n      var canvasWidth = containerData.width;\n      var canvasHeight = containerData.height;\n\n      if (containerData.height * aspectRatio > containerData.width) {\n        if (viewMode === 3) {\n          canvasWidth = containerData.height * aspectRatio;\n        } else {\n          canvasHeight = containerData.width / aspectRatio;\n        }\n      } else if (viewMode === 3) {\n        canvasHeight = containerData.width / aspectRatio;\n      } else {\n        canvasWidth = containerData.height * aspectRatio;\n      }\n\n      var canvasData = {\n        aspectRatio: aspectRatio,\n        naturalWidth: naturalWidth,\n        naturalHeight: naturalHeight,\n        width: canvasWidth,\n        height: canvasHeight\n      };\n      this.canvasData = canvasData;\n      this.limited = viewMode === 1 || viewMode === 2;\n      this.limitCanvas(true, true);\n      canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth);\n      canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight);\n      canvasData.left = (containerData.width - canvasData.width) / 2;\n      canvasData.top = (containerData.height - canvasData.height) / 2;\n      canvasData.oldLeft = canvasData.left;\n      canvasData.oldTop = canvasData.top;\n      this.initialCanvasData = assign({}, canvasData);\n    },\n    limitCanvas: function limitCanvas(sizeLimited, positionLimited) {\n      var options = this.options,\n          containerData = this.containerData,\n          canvasData = this.canvasData,\n          cropBoxData = this.cropBoxData;\n      var viewMode = options.viewMode;\n      var aspectRatio = canvasData.aspectRatio;\n      var cropped = this.cropped && cropBoxData;\n\n      if (sizeLimited) {\n        var minCanvasWidth = Number(options.minCanvasWidth) || 0;\n        var minCanvasHeight = Number(options.minCanvasHeight) || 0;\n\n        if (viewMode > 1) {\n          minCanvasWidth = Math.max(minCanvasWidth, containerData.width);\n          minCanvasHeight = Math.max(minCanvasHeight, containerData.height);\n\n          if (viewMode === 3) {\n            if (minCanvasHeight * aspectRatio > minCanvasWidth) {\n              minCanvasWidth = minCanvasHeight * aspectRatio;\n            } else {\n              minCanvasHeight = minCanvasWidth / aspectRatio;\n            }\n          }\n        } else if (viewMode > 0) {\n          if (minCanvasWidth) {\n            minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0);\n          } else if (minCanvasHeight) {\n            minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0);\n          } else if (cropped) {\n            minCanvasWidth = cropBoxData.width;\n            minCanvasHeight = cropBoxData.height;\n\n            if (minCanvasHeight * aspectRatio > minCanvasWidth) {\n              minCanvasWidth = minCanvasHeight * aspectRatio;\n            } else {\n              minCanvasHeight = minCanvasWidth / aspectRatio;\n            }\n          }\n        }\n\n        var _getAdjustedSizes = getAdjustedSizes({\n          aspectRatio: aspectRatio,\n          width: minCanvasWidth,\n          height: minCanvasHeight\n        });\n\n        minCanvasWidth = _getAdjustedSizes.width;\n        minCanvasHeight = _getAdjustedSizes.height;\n        canvasData.minWidth = minCanvasWidth;\n        canvasData.minHeight = minCanvasHeight;\n        canvasData.maxWidth = Infinity;\n        canvasData.maxHeight = Infinity;\n      }\n\n      if (positionLimited) {\n        if (viewMode > (cropped ? 0 : 1)) {\n          var newCanvasLeft = containerData.width - canvasData.width;\n          var newCanvasTop = containerData.height - canvasData.height;\n          canvasData.minLeft = Math.min(0, newCanvasLeft);\n          canvasData.minTop = Math.min(0, newCanvasTop);\n          canvasData.maxLeft = Math.max(0, newCanvasLeft);\n          canvasData.maxTop = Math.max(0, newCanvasTop);\n\n          if (cropped && this.limited) {\n            canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width));\n            canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height));\n            canvasData.maxLeft = cropBoxData.left;\n            canvasData.maxTop = cropBoxData.top;\n\n            if (viewMode === 2) {\n              if (canvasData.width >= containerData.width) {\n                canvasData.minLeft = Math.min(0, newCanvasLeft);\n                canvasData.maxLeft = Math.max(0, newCanvasLeft);\n              }\n\n              if (canvasData.height >= containerData.height) {\n                canvasData.minTop = Math.min(0, newCanvasTop);\n                canvasData.maxTop = Math.max(0, newCanvasTop);\n              }\n            }\n          }\n        } else {\n          canvasData.minLeft = -canvasData.width;\n          canvasData.minTop = -canvasData.height;\n          canvasData.maxLeft = containerData.width;\n          canvasData.maxTop = containerData.height;\n        }\n      }\n    },\n    renderCanvas: function renderCanvas(changed, transformed) {\n      var canvasData = this.canvasData,\n          imageData = this.imageData;\n\n      if (transformed) {\n        var _getRotatedSizes = getRotatedSizes({\n          width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1),\n          height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1),\n          degree: imageData.rotate || 0\n        }),\n            naturalWidth = _getRotatedSizes.width,\n            naturalHeight = _getRotatedSizes.height;\n\n        var width = canvasData.width * (naturalWidth / canvasData.naturalWidth);\n        var height = canvasData.height * (naturalHeight / canvasData.naturalHeight);\n        canvasData.left -= (width - canvasData.width) / 2;\n        canvasData.top -= (height - canvasData.height) / 2;\n        canvasData.width = width;\n        canvasData.height = height;\n        canvasData.aspectRatio = naturalWidth / naturalHeight;\n        canvasData.naturalWidth = naturalWidth;\n        canvasData.naturalHeight = naturalHeight;\n        this.limitCanvas(true, false);\n      }\n\n      if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) {\n        canvasData.left = canvasData.oldLeft;\n      }\n\n      if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) {\n        canvasData.top = canvasData.oldTop;\n      }\n\n      canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth);\n      canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight);\n      this.limitCanvas(false, true);\n      canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft);\n      canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop);\n      canvasData.oldLeft = canvasData.left;\n      canvasData.oldTop = canvasData.top;\n      setStyle(this.canvas, assign({\n        width: canvasData.width,\n        height: canvasData.height\n      }, getTransforms({\n        translateX: canvasData.left,\n        translateY: canvasData.top\n      })));\n      this.renderImage(changed);\n\n      if (this.cropped && this.limited) {\n        this.limitCropBox(true, true);\n      }\n    },\n    renderImage: function renderImage(changed) {\n      var canvasData = this.canvasData,\n          imageData = this.imageData;\n      var width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth);\n      var height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight);\n      assign(imageData, {\n        width: width,\n        height: height,\n        left: (canvasData.width - width) / 2,\n        top: (canvasData.height - height) / 2\n      });\n      setStyle(this.image, assign({\n        width: imageData.width,\n        height: imageData.height\n      }, getTransforms(assign({\n        translateX: imageData.left,\n        translateY: imageData.top\n      }, imageData))));\n\n      if (changed) {\n        this.output();\n      }\n    },\n    initCropBox: function initCropBox() {\n      var options = this.options,\n          canvasData = this.canvasData;\n      var aspectRatio = options.aspectRatio || options.initialAspectRatio;\n      var autoCropArea = Number(options.autoCropArea) || 0.8;\n      var cropBoxData = {\n        width: canvasData.width,\n        height: canvasData.height\n      };\n\n      if (aspectRatio) {\n        if (canvasData.height * aspectRatio > canvasData.width) {\n          cropBoxData.height = cropBoxData.width / aspectRatio;\n        } else {\n          cropBoxData.width = cropBoxData.height * aspectRatio;\n        }\n      }\n\n      this.cropBoxData = cropBoxData;\n      this.limitCropBox(true, true); // Initialize auto crop area\n\n      cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth);\n      cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); // The width/height of auto crop area must large than \"minWidth/Height\"\n\n      cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea);\n      cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea);\n      cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2;\n      cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2;\n      cropBoxData.oldLeft = cropBoxData.left;\n      cropBoxData.oldTop = cropBoxData.top;\n      this.initialCropBoxData = assign({}, cropBoxData);\n    },\n    limitCropBox: function limitCropBox(sizeLimited, positionLimited) {\n      var options = this.options,\n          containerData = this.containerData,\n          canvasData = this.canvasData,\n          cropBoxData = this.cropBoxData,\n          limited = this.limited;\n      var aspectRatio = options.aspectRatio;\n\n      if (sizeLimited) {\n        var minCropBoxWidth = Number(options.minCropBoxWidth) || 0;\n        var minCropBoxHeight = Number(options.minCropBoxHeight) || 0;\n        var maxCropBoxWidth = limited ? Math.min(containerData.width, canvasData.width, canvasData.width + canvasData.left, containerData.width - canvasData.left) : containerData.width;\n        var maxCropBoxHeight = limited ? Math.min(containerData.height, canvasData.height, canvasData.height + canvasData.top, containerData.height - canvasData.top) : containerData.height; // The min/maxCropBoxWidth/Height must be less than container's width/height\n\n        minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width);\n        minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height);\n\n        if (aspectRatio) {\n          if (minCropBoxWidth && minCropBoxHeight) {\n            if (minCropBoxHeight * aspectRatio > minCropBoxWidth) {\n              minCropBoxHeight = minCropBoxWidth / aspectRatio;\n            } else {\n              minCropBoxWidth = minCropBoxHeight * aspectRatio;\n            }\n          } else if (minCropBoxWidth) {\n            minCropBoxHeight = minCropBoxWidth / aspectRatio;\n          } else if (minCropBoxHeight) {\n            minCropBoxWidth = minCropBoxHeight * aspectRatio;\n          }\n\n          if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) {\n            maxCropBoxHeight = maxCropBoxWidth / aspectRatio;\n          } else {\n            maxCropBoxWidth = maxCropBoxHeight * aspectRatio;\n          }\n        } // The minWidth/Height must be less than maxWidth/Height\n\n\n        cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth);\n        cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight);\n        cropBoxData.maxWidth = maxCropBoxWidth;\n        cropBoxData.maxHeight = maxCropBoxHeight;\n      }\n\n      if (positionLimited) {\n        if (limited) {\n          cropBoxData.minLeft = Math.max(0, canvasData.left);\n          cropBoxData.minTop = Math.max(0, canvasData.top);\n          cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width;\n          cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height;\n        } else {\n          cropBoxData.minLeft = 0;\n          cropBoxData.minTop = 0;\n          cropBoxData.maxLeft = containerData.width - cropBoxData.width;\n          cropBoxData.maxTop = containerData.height - cropBoxData.height;\n        }\n      }\n    },\n    renderCropBox: function renderCropBox() {\n      var options = this.options,\n          containerData = this.containerData,\n          cropBoxData = this.cropBoxData;\n\n      if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) {\n        cropBoxData.left = cropBoxData.oldLeft;\n      }\n\n      if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) {\n        cropBoxData.top = cropBoxData.oldTop;\n      }\n\n      cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth);\n      cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight);\n      this.limitCropBox(false, true);\n      cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft);\n      cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop);\n      cropBoxData.oldLeft = cropBoxData.left;\n      cropBoxData.oldTop = cropBoxData.top;\n\n      if (options.movable && options.cropBoxMovable) {\n        // Turn to move the canvas when the crop box is equal to the container\n        setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width && cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL);\n      }\n\n      setStyle(this.cropBox, assign({\n        width: cropBoxData.width,\n        height: cropBoxData.height\n      }, getTransforms({\n        translateX: cropBoxData.left,\n        translateY: cropBoxData.top\n      })));\n\n      if (this.cropped && this.limited) {\n        this.limitCanvas(true, true);\n      }\n\n      if (!this.disabled) {\n        this.output();\n      }\n    },\n    output: function output() {\n      this.preview();\n      dispatchEvent(this.element, EVENT_CROP, this.getData());\n    }\n  };\n\n  var preview = {\n    initPreview: function initPreview() {\n      var element = this.element,\n          crossOrigin = this.crossOrigin;\n      var preview = this.options.preview;\n      var url = crossOrigin ? this.crossOriginUrl : this.url;\n      var alt = element.alt || 'The image to preview';\n      var image = document.createElement('img');\n\n      if (crossOrigin) {\n        image.crossOrigin = crossOrigin;\n      }\n\n      image.src = url;\n      image.alt = alt;\n      this.viewBox.appendChild(image);\n      this.viewBoxImage = image;\n\n      if (!preview) {\n        return;\n      }\n\n      var previews = preview;\n\n      if (typeof preview === 'string') {\n        previews = element.ownerDocument.querySelectorAll(preview);\n      } else if (preview.querySelector) {\n        previews = [preview];\n      }\n\n      this.previews = previews;\n      forEach(previews, function (el) {\n        var img = document.createElement('img'); // Save the original size for recover\n\n        setData(el, DATA_PREVIEW, {\n          width: el.offsetWidth,\n          height: el.offsetHeight,\n          html: el.innerHTML\n        });\n\n        if (crossOrigin) {\n          img.crossOrigin = crossOrigin;\n        }\n\n        img.src = url;\n        img.alt = alt;\n        /**\n         * Override img element styles\n         * Add `display:block` to avoid margin top issue\n         * Add `height:auto` to override `height` attribute on IE8\n         * (Occur only when margin-top <= -height)\n         */\n\n        img.style.cssText = 'display:block;' + 'width:100%;' + 'height:auto;' + 'min-width:0!important;' + 'min-height:0!important;' + 'max-width:none!important;' + 'max-height:none!important;' + 'image-orientation:0deg!important;\"';\n        el.innerHTML = '';\n        el.appendChild(img);\n      });\n    },\n    resetPreview: function resetPreview() {\n      forEach(this.previews, function (element) {\n        var data = getData(element, DATA_PREVIEW);\n        setStyle(element, {\n          width: data.width,\n          height: data.height\n        });\n        element.innerHTML = data.html;\n        removeData(element, DATA_PREVIEW);\n      });\n    },\n    preview: function preview() {\n      var imageData = this.imageData,\n          canvasData = this.canvasData,\n          cropBoxData = this.cropBoxData;\n      var cropBoxWidth = cropBoxData.width,\n          cropBoxHeight = cropBoxData.height;\n      var width = imageData.width,\n          height = imageData.height;\n      var left = cropBoxData.left - canvasData.left - imageData.left;\n      var top = cropBoxData.top - canvasData.top - imageData.top;\n\n      if (!this.cropped || this.disabled) {\n        return;\n      }\n\n      setStyle(this.viewBoxImage, assign({\n        width: width,\n        height: height\n      }, getTransforms(assign({\n        translateX: -left,\n        translateY: -top\n      }, imageData))));\n      forEach(this.previews, function (element) {\n        var data = getData(element, DATA_PREVIEW);\n        var originalWidth = data.width;\n        var originalHeight = data.height;\n        var newWidth = originalWidth;\n        var newHeight = originalHeight;\n        var ratio = 1;\n\n        if (cropBoxWidth) {\n          ratio = originalWidth / cropBoxWidth;\n          newHeight = cropBoxHeight * ratio;\n        }\n\n        if (cropBoxHeight && newHeight > originalHeight) {\n          ratio = originalHeight / cropBoxHeight;\n          newWidth = cropBoxWidth * ratio;\n          newHeight = originalHeight;\n        }\n\n        setStyle(element, {\n          width: newWidth,\n          height: newHeight\n        });\n        setStyle(element.getElementsByTagName('img')[0], assign({\n          width: width * ratio,\n          height: height * ratio\n        }, getTransforms(assign({\n          translateX: -left * ratio,\n          translateY: -top * ratio\n        }, imageData))));\n      });\n    }\n  };\n\n  var events = {\n    bind: function bind() {\n      var element = this.element,\n          options = this.options,\n          cropper = this.cropper;\n\n      if (isFunction(options.cropstart)) {\n        addListener(element, EVENT_CROP_START, options.cropstart);\n      }\n\n      if (isFunction(options.cropmove)) {\n        addListener(element, EVENT_CROP_MOVE, options.cropmove);\n      }\n\n      if (isFunction(options.cropend)) {\n        addListener(element, EVENT_CROP_END, options.cropend);\n      }\n\n      if (isFunction(options.crop)) {\n        addListener(element, EVENT_CROP, options.crop);\n      }\n\n      if (isFunction(options.zoom)) {\n        addListener(element, EVENT_ZOOM, options.zoom);\n      }\n\n      addListener(cropper, EVENT_POINTER_DOWN, this.onCropStart = this.cropStart.bind(this));\n\n      if (options.zoomable && options.zoomOnWheel) {\n        addListener(cropper, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {\n          passive: false,\n          capture: true\n        });\n      }\n\n      if (options.toggleDragModeOnDblclick) {\n        addListener(cropper, EVENT_DBLCLICK, this.onDblclick = this.dblclick.bind(this));\n      }\n\n      addListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove = this.cropMove.bind(this));\n      addListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd = this.cropEnd.bind(this));\n\n      if (options.responsive) {\n        addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this));\n      }\n    },\n    unbind: function unbind() {\n      var element = this.element,\n          options = this.options,\n          cropper = this.cropper;\n\n      if (isFunction(options.cropstart)) {\n        removeListener(element, EVENT_CROP_START, options.cropstart);\n      }\n\n      if (isFunction(options.cropmove)) {\n        removeListener(element, EVENT_CROP_MOVE, options.cropmove);\n      }\n\n      if (isFunction(options.cropend)) {\n        removeListener(element, EVENT_CROP_END, options.cropend);\n      }\n\n      if (isFunction(options.crop)) {\n        removeListener(element, EVENT_CROP, options.crop);\n      }\n\n      if (isFunction(options.zoom)) {\n        removeListener(element, EVENT_ZOOM, options.zoom);\n      }\n\n      removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart);\n\n      if (options.zoomable && options.zoomOnWheel) {\n        removeListener(cropper, EVENT_WHEEL, this.onWheel, {\n          passive: false,\n          capture: true\n        });\n      }\n\n      if (options.toggleDragModeOnDblclick) {\n        removeListener(cropper, EVENT_DBLCLICK, this.onDblclick);\n      }\n\n      removeListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove);\n      removeListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd);\n\n      if (options.responsive) {\n        removeListener(window, EVENT_RESIZE, this.onResize);\n      }\n    }\n  };\n\n  var handlers = {\n    resize: function resize() {\n      if (this.disabled) {\n        return;\n      }\n\n      var options = this.options,\n          container = this.container,\n          containerData = this.containerData;\n      var ratioX = container.offsetWidth / containerData.width;\n      var ratioY = container.offsetHeight / containerData.height;\n      var ratio = Math.abs(ratioX - 1) > Math.abs(ratioY - 1) ? ratioX : ratioY; // Resize when width changed or height changed\n\n      if (ratio !== 1) {\n        var canvasData;\n        var cropBoxData;\n\n        if (options.restore) {\n          canvasData = this.getCanvasData();\n          cropBoxData = this.getCropBoxData();\n        }\n\n        this.render();\n\n        if (options.restore) {\n          this.setCanvasData(forEach(canvasData, function (n, i) {\n            canvasData[i] = n * ratio;\n          }));\n          this.setCropBoxData(forEach(cropBoxData, function (n, i) {\n            cropBoxData[i] = n * ratio;\n          }));\n        }\n      }\n    },\n    dblclick: function dblclick() {\n      if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) {\n        return;\n      }\n\n      this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP);\n    },\n    wheel: function wheel(event) {\n      var _this = this;\n\n      var ratio = Number(this.options.wheelZoomRatio) || 0.1;\n      var delta = 1;\n\n      if (this.disabled) {\n        return;\n      }\n\n      event.preventDefault(); // Limit wheel speed to prevent zoom too fast (#21)\n\n      if (this.wheeling) {\n        return;\n      }\n\n      this.wheeling = true;\n      setTimeout(function () {\n        _this.wheeling = false;\n      }, 50);\n\n      if (event.deltaY) {\n        delta = event.deltaY > 0 ? 1 : -1;\n      } else if (event.wheelDelta) {\n        delta = -event.wheelDelta / 120;\n      } else if (event.detail) {\n        delta = event.detail > 0 ? 1 : -1;\n      }\n\n      this.zoom(-delta * ratio, event);\n    },\n    cropStart: function cropStart(event) {\n      var buttons = event.buttons,\n          button = event.button;\n\n      if (this.disabled // Handle mouse event and pointer event and ignore touch event\n      || (event.type === 'mousedown' || event.type === 'pointerdown' && event.pointerType === 'mouse') && ( // No primary button (Usually the left button)\n      isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu\n      || event.ctrlKey)) {\n        return;\n      }\n\n      var options = this.options,\n          pointers = this.pointers;\n      var action;\n\n      if (event.changedTouches) {\n        // Handle touch event\n        forEach(event.changedTouches, function (touch) {\n          pointers[touch.identifier] = getPointer(touch);\n        });\n      } else {\n        // Handle mouse event and pointer event\n        pointers[event.pointerId || 0] = getPointer(event);\n      }\n\n      if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) {\n        action = ACTION_ZOOM;\n      } else {\n        action = getData(event.target, DATA_ACTION);\n      }\n\n      if (!REGEXP_ACTIONS.test(action)) {\n        return;\n      }\n\n      if (dispatchEvent(this.element, EVENT_CROP_START, {\n        originalEvent: event,\n        action: action\n      }) === false) {\n        return;\n      } // This line is required for preventing page zooming in iOS browsers\n\n\n      event.preventDefault();\n      this.action = action;\n      this.cropping = false;\n\n      if (action === ACTION_CROP) {\n        this.cropping = true;\n        addClass(this.dragBox, CLASS_MODAL);\n      }\n    },\n    cropMove: function cropMove(event) {\n      var action = this.action;\n\n      if (this.disabled || !action) {\n        return;\n      }\n\n      var pointers = this.pointers;\n      event.preventDefault();\n\n      if (dispatchEvent(this.element, EVENT_CROP_MOVE, {\n        originalEvent: event,\n        action: action\n      }) === false) {\n        return;\n      }\n\n      if (event.changedTouches) {\n        forEach(event.changedTouches, function (touch) {\n          // The first parameter should not be undefined (#432)\n          assign(pointers[touch.identifier] || {}, getPointer(touch, true));\n        });\n      } else {\n        assign(pointers[event.pointerId || 0] || {}, getPointer(event, true));\n      }\n\n      this.change(event);\n    },\n    cropEnd: function cropEnd(event) {\n      if (this.disabled) {\n        return;\n      }\n\n      var action = this.action,\n          pointers = this.pointers;\n\n      if (event.changedTouches) {\n        forEach(event.changedTouches, function (touch) {\n          delete pointers[touch.identifier];\n        });\n      } else {\n        delete pointers[event.pointerId || 0];\n      }\n\n      if (!action) {\n        return;\n      }\n\n      event.preventDefault();\n\n      if (!Object.keys(pointers).length) {\n        this.action = '';\n      }\n\n      if (this.cropping) {\n        this.cropping = false;\n        toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal);\n      }\n\n      dispatchEvent(this.element, EVENT_CROP_END, {\n        originalEvent: event,\n        action: action\n      });\n    }\n  };\n\n  var change = {\n    change: function change(event) {\n      var options = this.options,\n          canvasData = this.canvasData,\n          containerData = this.containerData,\n          cropBoxData = this.cropBoxData,\n          pointers = this.pointers;\n      var action = this.action;\n      var aspectRatio = options.aspectRatio;\n      var left = cropBoxData.left,\n          top = cropBoxData.top,\n          width = cropBoxData.width,\n          height = cropBoxData.height;\n      var right = left + width;\n      var bottom = top + height;\n      var minLeft = 0;\n      var minTop = 0;\n      var maxWidth = containerData.width;\n      var maxHeight = containerData.height;\n      var renderable = true;\n      var offset; // Locking aspect ratio in \"free mode\" by holding shift key\n\n      if (!aspectRatio && event.shiftKey) {\n        aspectRatio = width && height ? width / height : 1;\n      }\n\n      if (this.limited) {\n        minLeft = cropBoxData.minLeft;\n        minTop = cropBoxData.minTop;\n        maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width);\n        maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height);\n      }\n\n      var pointer = pointers[Object.keys(pointers)[0]];\n      var range = {\n        x: pointer.endX - pointer.startX,\n        y: pointer.endY - pointer.startY\n      };\n\n      var check = function check(side) {\n        switch (side) {\n          case ACTION_EAST:\n            if (right + range.x > maxWidth) {\n              range.x = maxWidth - right;\n            }\n\n            break;\n\n          case ACTION_WEST:\n            if (left + range.x < minLeft) {\n              range.x = minLeft - left;\n            }\n\n            break;\n\n          case ACTION_NORTH:\n            if (top + range.y < minTop) {\n              range.y = minTop - top;\n            }\n\n            break;\n\n          case ACTION_SOUTH:\n            if (bottom + range.y > maxHeight) {\n              range.y = maxHeight - bottom;\n            }\n\n            break;\n        }\n      };\n\n      switch (action) {\n        // Move crop box\n        case ACTION_ALL:\n          left += range.x;\n          top += range.y;\n          break;\n        // Resize crop box\n\n        case ACTION_EAST:\n          if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) {\n            renderable = false;\n            break;\n          }\n\n          check(ACTION_EAST);\n          width += range.x;\n\n          if (width < 0) {\n            action = ACTION_WEST;\n            width = -width;\n            left -= width;\n          }\n\n          if (aspectRatio) {\n            height = width / aspectRatio;\n            top += (cropBoxData.height - height) / 2;\n          }\n\n          break;\n\n        case ACTION_NORTH:\n          if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) {\n            renderable = false;\n            break;\n          }\n\n          check(ACTION_NORTH);\n          height -= range.y;\n          top += range.y;\n\n          if (height < 0) {\n            action = ACTION_SOUTH;\n            height = -height;\n            top -= height;\n          }\n\n          if (aspectRatio) {\n            width = height * aspectRatio;\n            left += (cropBoxData.width - width) / 2;\n          }\n\n          break;\n\n        case ACTION_WEST:\n          if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) {\n            renderable = false;\n            break;\n          }\n\n          check(ACTION_WEST);\n          width -= range.x;\n          left += range.x;\n\n          if (width < 0) {\n            action = ACTION_EAST;\n            width = -width;\n            left -= width;\n          }\n\n          if (aspectRatio) {\n            height = width / aspectRatio;\n            top += (cropBoxData.height - height) / 2;\n          }\n\n          break;\n\n        case ACTION_SOUTH:\n          if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) {\n            renderable = false;\n            break;\n          }\n\n          check(ACTION_SOUTH);\n          height += range.y;\n\n          if (height < 0) {\n            action = ACTION_NORTH;\n            height = -height;\n            top -= height;\n          }\n\n          if (aspectRatio) {\n            width = height * aspectRatio;\n            left += (cropBoxData.width - width) / 2;\n          }\n\n          break;\n\n        case ACTION_NORTH_EAST:\n          if (aspectRatio) {\n            if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {\n              renderable = false;\n              break;\n            }\n\n            check(ACTION_NORTH);\n            height -= range.y;\n            top += range.y;\n            width = height * aspectRatio;\n          } else {\n            check(ACTION_NORTH);\n            check(ACTION_EAST);\n\n            if (range.x >= 0) {\n              if (right < maxWidth) {\n                width += range.x;\n              } else if (range.y <= 0 && top <= minTop) {\n                renderable = false;\n              }\n            } else {\n              width += range.x;\n            }\n\n            if (range.y <= 0) {\n              if (top > minTop) {\n                height -= range.y;\n                top += range.y;\n              }\n            } else {\n              height -= range.y;\n              top += range.y;\n            }\n          }\n\n          if (width < 0 && height < 0) {\n            action = ACTION_SOUTH_WEST;\n            height = -height;\n            width = -width;\n            top -= height;\n            left -= width;\n          } else if (width < 0) {\n            action = ACTION_NORTH_WEST;\n            width = -width;\n            left -= width;\n          } else if (height < 0) {\n            action = ACTION_SOUTH_EAST;\n            height = -height;\n            top -= height;\n          }\n\n          break;\n\n        case ACTION_NORTH_WEST:\n          if (aspectRatio) {\n            if (range.y <= 0 && (top <= minTop || left <= minLeft)) {\n              renderable = false;\n              break;\n            }\n\n            check(ACTION_NORTH);\n            height -= range.y;\n            top += range.y;\n            width = height * aspectRatio;\n            left += cropBoxData.width - width;\n          } else {\n            check(ACTION_NORTH);\n            check(ACTION_WEST);\n\n            if (range.x <= 0) {\n              if (left > minLeft) {\n                width -= range.x;\n                left += range.x;\n              } else if (range.y <= 0 && top <= minTop) {\n                renderable = false;\n              }\n            } else {\n              width -= range.x;\n              left += range.x;\n            }\n\n            if (range.y <= 0) {\n              if (top > minTop) {\n                height -= range.y;\n                top += range.y;\n              }\n            } else {\n              height -= range.y;\n              top += range.y;\n            }\n          }\n\n          if (width < 0 && height < 0) {\n            action = ACTION_SOUTH_EAST;\n            height = -height;\n            width = -width;\n            top -= height;\n            left -= width;\n          } else if (width < 0) {\n            action = ACTION_NORTH_EAST;\n            width = -width;\n            left -= width;\n          } else if (height < 0) {\n            action = ACTION_SOUTH_WEST;\n            height = -height;\n            top -= height;\n          }\n\n          break;\n\n        case ACTION_SOUTH_WEST:\n          if (aspectRatio) {\n            if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {\n              renderable = false;\n              break;\n            }\n\n            check(ACTION_WEST);\n            width -= range.x;\n            left += range.x;\n            height = width / aspectRatio;\n          } else {\n            check(ACTION_SOUTH);\n            check(ACTION_WEST);\n\n            if (range.x <= 0) {\n              if (left > minLeft) {\n                width -= range.x;\n                left += range.x;\n              } else if (range.y >= 0 && bottom >= maxHeight) {\n                renderable = false;\n              }\n            } else {\n              width -= range.x;\n              left += range.x;\n            }\n\n            if (range.y >= 0) {\n              if (bottom < maxHeight) {\n                height += range.y;\n              }\n            } else {\n              height += range.y;\n            }\n          }\n\n          if (width < 0 && height < 0) {\n            action = ACTION_NORTH_EAST;\n            height = -height;\n            width = -width;\n            top -= height;\n            left -= width;\n          } else if (width < 0) {\n            action = ACTION_SOUTH_EAST;\n            width = -width;\n            left -= width;\n          } else if (height < 0) {\n            action = ACTION_NORTH_WEST;\n            height = -height;\n            top -= height;\n          }\n\n          break;\n\n        case ACTION_SOUTH_EAST:\n          if (aspectRatio) {\n            if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {\n              renderable = false;\n              break;\n            }\n\n            check(ACTION_EAST);\n            width += range.x;\n            height = width / aspectRatio;\n          } else {\n            check(ACTION_SOUTH);\n            check(ACTION_EAST);\n\n            if (range.x >= 0) {\n              if (right < maxWidth) {\n                width += range.x;\n              } else if (range.y >= 0 && bottom >= maxHeight) {\n                renderable = false;\n              }\n            } else {\n              width += range.x;\n            }\n\n            if (range.y >= 0) {\n              if (bottom < maxHeight) {\n                height += range.y;\n              }\n            } else {\n              height += range.y;\n            }\n          }\n\n          if (width < 0 && height < 0) {\n            action = ACTION_NORTH_WEST;\n            height = -height;\n            width = -width;\n            top -= height;\n            left -= width;\n          } else if (width < 0) {\n            action = ACTION_SOUTH_WEST;\n            width = -width;\n            left -= width;\n          } else if (height < 0) {\n            action = ACTION_NORTH_EAST;\n            height = -height;\n            top -= height;\n          }\n\n          break;\n        // Move canvas\n\n        case ACTION_MOVE:\n          this.move(range.x, range.y);\n          renderable = false;\n          break;\n        // Zoom canvas\n\n        case ACTION_ZOOM:\n          this.zoom(getMaxZoomRatio(pointers), event);\n          renderable = false;\n          break;\n        // Create crop box\n\n        case ACTION_CROP:\n          if (!range.x || !range.y) {\n            renderable = false;\n            break;\n          }\n\n          offset = getOffset(this.cropper);\n          left = pointer.startX - offset.left;\n          top = pointer.startY - offset.top;\n          width = cropBoxData.minWidth;\n          height = cropBoxData.minHeight;\n\n          if (range.x > 0) {\n            action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST;\n          } else if (range.x < 0) {\n            left -= width;\n            action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST;\n          }\n\n          if (range.y < 0) {\n            top -= height;\n          } // Show the crop box if is hidden\n\n\n          if (!this.cropped) {\n            removeClass(this.cropBox, CLASS_HIDDEN);\n            this.cropped = true;\n\n            if (this.limited) {\n              this.limitCropBox(true, true);\n            }\n          }\n\n          break;\n      }\n\n      if (renderable) {\n        cropBoxData.width = width;\n        cropBoxData.height = height;\n        cropBoxData.left = left;\n        cropBoxData.top = top;\n        this.action = action;\n        this.renderCropBox();\n      } // Override\n\n\n      forEach(pointers, function (p) {\n        p.startX = p.endX;\n        p.startY = p.endY;\n      });\n    }\n  };\n\n  var methods = {\n    // Show the crop box manually\n    crop: function crop() {\n      if (this.ready && !this.cropped && !this.disabled) {\n        this.cropped = true;\n        this.limitCropBox(true, true);\n\n        if (this.options.modal) {\n          addClass(this.dragBox, CLASS_MODAL);\n        }\n\n        removeClass(this.cropBox, CLASS_HIDDEN);\n        this.setCropBoxData(this.initialCropBoxData);\n      }\n\n      return this;\n    },\n    // Reset the image and crop box to their initial states\n    reset: function reset() {\n      if (this.ready && !this.disabled) {\n        this.imageData = assign({}, this.initialImageData);\n        this.canvasData = assign({}, this.initialCanvasData);\n        this.cropBoxData = assign({}, this.initialCropBoxData);\n        this.renderCanvas();\n\n        if (this.cropped) {\n          this.renderCropBox();\n        }\n      }\n\n      return this;\n    },\n    // Clear the crop box\n    clear: function clear() {\n      if (this.cropped && !this.disabled) {\n        assign(this.cropBoxData, {\n          left: 0,\n          top: 0,\n          width: 0,\n          height: 0\n        });\n        this.cropped = false;\n        this.renderCropBox();\n        this.limitCanvas(true, true); // Render canvas after crop box rendered\n\n        this.renderCanvas();\n        removeClass(this.dragBox, CLASS_MODAL);\n        addClass(this.cropBox, CLASS_HIDDEN);\n      }\n\n      return this;\n    },\n\n    /**\n     * Replace the image's src and rebuild the cropper\n     * @param {string} url - The new URL.\n     * @param {boolean} [hasSameSize] - Indicate if the new image has the same size as the old one.\n     * @returns {Cropper} this\n     */\n    replace: function replace(url) {\n      var hasSameSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n      if (!this.disabled && url) {\n        if (this.isImg) {\n          this.element.src = url;\n        }\n\n        if (hasSameSize) {\n          this.url = url;\n          this.image.src = url;\n\n          if (this.ready) {\n            this.viewBoxImage.src = url;\n            forEach(this.previews, function (element) {\n              element.getElementsByTagName('img')[0].src = url;\n            });\n          }\n        } else {\n          if (this.isImg) {\n            this.replaced = true;\n          }\n\n          this.options.data = null;\n          this.uncreate();\n          this.load(url);\n        }\n      }\n\n      return this;\n    },\n    // Enable (unfreeze) the cropper\n    enable: function enable() {\n      if (this.ready && this.disabled) {\n        this.disabled = false;\n        removeClass(this.cropper, CLASS_DISABLED);\n      }\n\n      return this;\n    },\n    // Disable (freeze) the cropper\n    disable: function disable() {\n      if (this.ready && !this.disabled) {\n        this.disabled = true;\n        addClass(this.cropper, CLASS_DISABLED);\n      }\n\n      return this;\n    },\n\n    /**\n     * Destroy the cropper and remove the instance from the image\n     * @returns {Cropper} this\n     */\n    destroy: function destroy() {\n      var element = this.element;\n\n      if (!element[NAMESPACE]) {\n        return this;\n      }\n\n      element[NAMESPACE] = undefined;\n\n      if (this.isImg && this.replaced) {\n        element.src = this.originalUrl;\n      }\n\n      this.uncreate();\n      return this;\n    },\n\n    /**\n     * Move the canvas with relative offsets\n     * @param {number} offsetX - The relative offset distance on the x-axis.\n     * @param {number} [offsetY=offsetX] - The relative offset distance on the y-axis.\n     * @returns {Cropper} this\n     */\n    move: function move(offsetX) {\n      var offsetY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : offsetX;\n      var _this$canvasData = this.canvasData,\n          left = _this$canvasData.left,\n          top = _this$canvasData.top;\n      return this.moveTo(isUndefined(offsetX) ? offsetX : left + Number(offsetX), isUndefined(offsetY) ? offsetY : top + Number(offsetY));\n    },\n\n    /**\n     * Move the canvas to an absolute point\n     * @param {number} x - The x-axis coordinate.\n     * @param {number} [y=x] - The y-axis coordinate.\n     * @returns {Cropper} this\n     */\n    moveTo: function moveTo(x) {\n      var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;\n      var canvasData = this.canvasData;\n      var changed = false;\n      x = Number(x);\n      y = Number(y);\n\n      if (this.ready && !this.disabled && this.options.movable) {\n        if (isNumber(x)) {\n          canvasData.left = x;\n          changed = true;\n        }\n\n        if (isNumber(y)) {\n          canvasData.top = y;\n          changed = true;\n        }\n\n        if (changed) {\n          this.renderCanvas(true);\n        }\n      }\n\n      return this;\n    },\n\n    /**\n     * Zoom the canvas with a relative ratio\n     * @param {number} ratio - The target ratio.\n     * @param {Event} _originalEvent - The original event if any.\n     * @returns {Cropper} this\n     */\n    zoom: function zoom(ratio, _originalEvent) {\n      var canvasData = this.canvasData;\n      ratio = Number(ratio);\n\n      if (ratio < 0) {\n        ratio = 1 / (1 - ratio);\n      } else {\n        ratio = 1 + ratio;\n      }\n\n      return this.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, null, _originalEvent);\n    },\n\n    /**\n     * Zoom the canvas to an absolute ratio\n     * @param {number} ratio - The target ratio.\n     * @param {Object} pivot - The zoom pivot point coordinate.\n     * @param {Event} _originalEvent - The original event if any.\n     * @returns {Cropper} this\n     */\n    zoomTo: function zoomTo(ratio, pivot, _originalEvent) {\n      var options = this.options,\n          canvasData = this.canvasData;\n      var width = canvasData.width,\n          height = canvasData.height,\n          naturalWidth = canvasData.naturalWidth,\n          naturalHeight = canvasData.naturalHeight;\n      ratio = Number(ratio);\n\n      if (ratio >= 0 && this.ready && !this.disabled && options.zoomable) {\n        var newWidth = naturalWidth * ratio;\n        var newHeight = naturalHeight * ratio;\n\n        if (dispatchEvent(this.element, EVENT_ZOOM, {\n          ratio: ratio,\n          oldRatio: width / naturalWidth,\n          originalEvent: _originalEvent\n        }) === false) {\n          return this;\n        }\n\n        if (_originalEvent) {\n          var pointers = this.pointers;\n          var offset = getOffset(this.cropper);\n          var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : {\n            pageX: _originalEvent.pageX,\n            pageY: _originalEvent.pageY\n          }; // Zoom from the triggering point of the event\n\n          canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width);\n          canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height);\n        } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) {\n          canvasData.left -= (newWidth - width) * ((pivot.x - canvasData.left) / width);\n          canvasData.top -= (newHeight - height) * ((pivot.y - canvasData.top) / height);\n        } else {\n          // Zoom from the center of the canvas\n          canvasData.left -= (newWidth - width) / 2;\n          canvasData.top -= (newHeight - height) / 2;\n        }\n\n        canvasData.width = newWidth;\n        canvasData.height = newHeight;\n        this.renderCanvas(true);\n      }\n\n      return this;\n    },\n\n    /**\n     * Rotate the canvas with a relative degree\n     * @param {number} degree - The rotate degree.\n     * @returns {Cropper} this\n     */\n    rotate: function rotate(degree) {\n      return this.rotateTo((this.imageData.rotate || 0) + Number(degree));\n    },\n\n    /**\n     * Rotate the canvas to an absolute degree\n     * @param {number} degree - The rotate degree.\n     * @returns {Cropper} this\n     */\n    rotateTo: function rotateTo(degree) {\n      degree = Number(degree);\n\n      if (isNumber(degree) && this.ready && !this.disabled && this.options.rotatable) {\n        this.imageData.rotate = degree % 360;\n        this.renderCanvas(true, true);\n      }\n\n      return this;\n    },\n\n    /**\n     * Scale the image on the x-axis.\n     * @param {number} scaleX - The scale ratio on the x-axis.\n     * @returns {Cropper} this\n     */\n    scaleX: function scaleX(_scaleX) {\n      var scaleY = this.imageData.scaleY;\n      return this.scale(_scaleX, isNumber(scaleY) ? scaleY : 1);\n    },\n\n    /**\n     * Scale the image on the y-axis.\n     * @param {number} scaleY - The scale ratio on the y-axis.\n     * @returns {Cropper} this\n     */\n    scaleY: function scaleY(_scaleY) {\n      var scaleX = this.imageData.scaleX;\n      return this.scale(isNumber(scaleX) ? scaleX : 1, _scaleY);\n    },\n\n    /**\n     * Scale the image\n     * @param {number} scaleX - The scale ratio on the x-axis.\n     * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis.\n     * @returns {Cropper} this\n     */\n    scale: function scale(scaleX) {\n      var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX;\n      var imageData = this.imageData;\n      var transformed = false;\n      scaleX = Number(scaleX);\n      scaleY = Number(scaleY);\n\n      if (this.ready && !this.disabled && this.options.scalable) {\n        if (isNumber(scaleX)) {\n          imageData.scaleX = scaleX;\n          transformed = true;\n        }\n\n        if (isNumber(scaleY)) {\n          imageData.scaleY = scaleY;\n          transformed = true;\n        }\n\n        if (transformed) {\n          this.renderCanvas(true, true);\n        }\n      }\n\n      return this;\n    },\n\n    /**\n     * Get the cropped area position and size data (base on the original image)\n     * @param {boolean} [rounded=false] - Indicate if round the data values or not.\n     * @returns {Object} The result cropped data.\n     */\n    getData: function getData() {\n      var rounded = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n      var options = this.options,\n          imageData = this.imageData,\n          canvasData = this.canvasData,\n          cropBoxData = this.cropBoxData;\n      var data;\n\n      if (this.ready && this.cropped) {\n        data = {\n          x: cropBoxData.left - canvasData.left,\n          y: cropBoxData.top - canvasData.top,\n          width: cropBoxData.width,\n          height: cropBoxData.height\n        };\n        var ratio = imageData.width / imageData.naturalWidth;\n        forEach(data, function (n, i) {\n          data[i] = n / ratio;\n        });\n\n        if (rounded) {\n          // In case rounding off leads to extra 1px in right or bottom border\n          // we should round the top-left corner and the dimension (#343).\n          var bottom = Math.round(data.y + data.height);\n          var right = Math.round(data.x + data.width);\n          data.x = Math.round(data.x);\n          data.y = Math.round(data.y);\n          data.width = right - data.x;\n          data.height = bottom - data.y;\n        }\n      } else {\n        data = {\n          x: 0,\n          y: 0,\n          width: 0,\n          height: 0\n        };\n      }\n\n      if (options.rotatable) {\n        data.rotate = imageData.rotate || 0;\n      }\n\n      if (options.scalable) {\n        data.scaleX = imageData.scaleX || 1;\n        data.scaleY = imageData.scaleY || 1;\n      }\n\n      return data;\n    },\n\n    /**\n     * Set the cropped area position and size with new data\n     * @param {Object} data - The new data.\n     * @returns {Cropper} this\n     */\n    setData: function setData(data) {\n      var options = this.options,\n          imageData = this.imageData,\n          canvasData = this.canvasData;\n      var cropBoxData = {};\n\n      if (this.ready && !this.disabled && isPlainObject(data)) {\n        var transformed = false;\n\n        if (options.rotatable) {\n          if (isNumber(data.rotate) && data.rotate !== imageData.rotate) {\n            imageData.rotate = data.rotate;\n            transformed = true;\n          }\n        }\n\n        if (options.scalable) {\n          if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) {\n            imageData.scaleX = data.scaleX;\n            transformed = true;\n          }\n\n          if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) {\n            imageData.scaleY = data.scaleY;\n            transformed = true;\n          }\n        }\n\n        if (transformed) {\n          this.renderCanvas(true, true);\n        }\n\n        var ratio = imageData.width / imageData.naturalWidth;\n\n        if (isNumber(data.x)) {\n          cropBoxData.left = data.x * ratio + canvasData.left;\n        }\n\n        if (isNumber(data.y)) {\n          cropBoxData.top = data.y * ratio + canvasData.top;\n        }\n\n        if (isNumber(data.width)) {\n          cropBoxData.width = data.width * ratio;\n        }\n\n        if (isNumber(data.height)) {\n          cropBoxData.height = data.height * ratio;\n        }\n\n        this.setCropBoxData(cropBoxData);\n      }\n\n      return this;\n    },\n\n    /**\n     * Get the container size data.\n     * @returns {Object} The result container data.\n     */\n    getContainerData: function getContainerData() {\n      return this.ready ? assign({}, this.containerData) : {};\n    },\n\n    /**\n     * Get the image position and size data.\n     * @returns {Object} The result image data.\n     */\n    getImageData: function getImageData() {\n      return this.sized ? assign({}, this.imageData) : {};\n    },\n\n    /**\n     * Get the canvas position and size data.\n     * @returns {Object} The result canvas data.\n     */\n    getCanvasData: function getCanvasData() {\n      var canvasData = this.canvasData;\n      var data = {};\n\n      if (this.ready) {\n        forEach(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) {\n          data[n] = canvasData[n];\n        });\n      }\n\n      return data;\n    },\n\n    /**\n     * Set the canvas position and size with new data.\n     * @param {Object} data - The new canvas data.\n     * @returns {Cropper} this\n     */\n    setCanvasData: function setCanvasData(data) {\n      var canvasData = this.canvasData;\n      var aspectRatio = canvasData.aspectRatio;\n\n      if (this.ready && !this.disabled && isPlainObject(data)) {\n        if (isNumber(data.left)) {\n          canvasData.left = data.left;\n        }\n\n        if (isNumber(data.top)) {\n          canvasData.top = data.top;\n        }\n\n        if (isNumber(data.width)) {\n          canvasData.width = data.width;\n          canvasData.height = data.width / aspectRatio;\n        } else if (isNumber(data.height)) {\n          canvasData.height = data.height;\n          canvasData.width = data.height * aspectRatio;\n        }\n\n        this.renderCanvas(true);\n      }\n\n      return this;\n    },\n\n    /**\n     * Get the crop box position and size data.\n     * @returns {Object} The result crop box data.\n     */\n    getCropBoxData: function getCropBoxData() {\n      var cropBoxData = this.cropBoxData;\n      var data;\n\n      if (this.ready && this.cropped) {\n        data = {\n          left: cropBoxData.left,\n          top: cropBoxData.top,\n          width: cropBoxData.width,\n          height: cropBoxData.height\n        };\n      }\n\n      return data || {};\n    },\n\n    /**\n     * Set the crop box position and size with new data.\n     * @param {Object} data - The new crop box data.\n     * @returns {Cropper} this\n     */\n    setCropBoxData: function setCropBoxData(data) {\n      var cropBoxData = this.cropBoxData;\n      var aspectRatio = this.options.aspectRatio;\n      var widthChanged;\n      var heightChanged;\n\n      if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) {\n        if (isNumber(data.left)) {\n          cropBoxData.left = data.left;\n        }\n\n        if (isNumber(data.top)) {\n          cropBoxData.top = data.top;\n        }\n\n        if (isNumber(data.width) && data.width !== cropBoxData.width) {\n          widthChanged = true;\n          cropBoxData.width = data.width;\n        }\n\n        if (isNumber(data.height) && data.height !== cropBoxData.height) {\n          heightChanged = true;\n          cropBoxData.height = data.height;\n        }\n\n        if (aspectRatio) {\n          if (widthChanged) {\n            cropBoxData.height = cropBoxData.width / aspectRatio;\n          } else if (heightChanged) {\n            cropBoxData.width = cropBoxData.height * aspectRatio;\n          }\n        }\n\n        this.renderCropBox();\n      }\n\n      return this;\n    },\n\n    /**\n     * Get a canvas drawn the cropped image.\n     * @param {Object} [options={}] - The config options.\n     * @returns {HTMLCanvasElement} - The result canvas.\n     */\n    getCroppedCanvas: function getCroppedCanvas() {\n      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n      if (!this.ready || !window.HTMLCanvasElement) {\n        return null;\n      }\n\n      var canvasData = this.canvasData;\n      var source = getSourceCanvas(this.image, this.imageData, canvasData, options); // Returns the source canvas if it is not cropped.\n\n      if (!this.cropped) {\n        return source;\n      }\n\n      var _this$getData = this.getData(),\n          initialX = _this$getData.x,\n          initialY = _this$getData.y,\n          initialWidth = _this$getData.width,\n          initialHeight = _this$getData.height;\n\n      var ratio = source.width / Math.floor(canvasData.naturalWidth);\n\n      if (ratio !== 1) {\n        initialX *= ratio;\n        initialY *= ratio;\n        initialWidth *= ratio;\n        initialHeight *= ratio;\n      }\n\n      var aspectRatio = initialWidth / initialHeight;\n      var maxSizes = getAdjustedSizes({\n        aspectRatio: aspectRatio,\n        width: options.maxWidth || Infinity,\n        height: options.maxHeight || Infinity\n      });\n      var minSizes = getAdjustedSizes({\n        aspectRatio: aspectRatio,\n        width: options.minWidth || 0,\n        height: options.minHeight || 0\n      }, 'cover');\n\n      var _getAdjustedSizes = getAdjustedSizes({\n        aspectRatio: aspectRatio,\n        width: options.width || (ratio !== 1 ? source.width : initialWidth),\n        height: options.height || (ratio !== 1 ? source.height : initialHeight)\n      }),\n          width = _getAdjustedSizes.width,\n          height = _getAdjustedSizes.height;\n\n      width = Math.min(maxSizes.width, Math.max(minSizes.width, width));\n      height = Math.min(maxSizes.height, Math.max(minSizes.height, height));\n      var canvas = document.createElement('canvas');\n      var context = canvas.getContext('2d');\n      canvas.width = normalizeDecimalNumber(width);\n      canvas.height = normalizeDecimalNumber(height);\n      context.fillStyle = options.fillColor || 'transparent';\n      context.fillRect(0, 0, width, height);\n      var _options$imageSmoothi = options.imageSmoothingEnabled,\n          imageSmoothingEnabled = _options$imageSmoothi === void 0 ? true : _options$imageSmoothi,\n          imageSmoothingQuality = options.imageSmoothingQuality;\n      context.imageSmoothingEnabled = imageSmoothingEnabled;\n\n      if (imageSmoothingQuality) {\n        context.imageSmoothingQuality = imageSmoothingQuality;\n      } // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage\n\n\n      var sourceWidth = source.width;\n      var sourceHeight = source.height; // Source canvas parameters\n\n      var srcX = initialX;\n      var srcY = initialY;\n      var srcWidth;\n      var srcHeight; // Destination canvas parameters\n\n      var dstX;\n      var dstY;\n      var dstWidth;\n      var dstHeight;\n\n      if (srcX <= -initialWidth || srcX > sourceWidth) {\n        srcX = 0;\n        srcWidth = 0;\n        dstX = 0;\n        dstWidth = 0;\n      } else if (srcX <= 0) {\n        dstX = -srcX;\n        srcX = 0;\n        srcWidth = Math.min(sourceWidth, initialWidth + srcX);\n        dstWidth = srcWidth;\n      } else if (srcX <= sourceWidth) {\n        dstX = 0;\n        srcWidth = Math.min(initialWidth, sourceWidth - srcX);\n        dstWidth = srcWidth;\n      }\n\n      if (srcWidth <= 0 || srcY <= -initialHeight || srcY > sourceHeight) {\n        srcY = 0;\n        srcHeight = 0;\n        dstY = 0;\n        dstHeight = 0;\n      } else if (srcY <= 0) {\n        dstY = -srcY;\n        srcY = 0;\n        srcHeight = Math.min(sourceHeight, initialHeight + srcY);\n        dstHeight = srcHeight;\n      } else if (srcY <= sourceHeight) {\n        dstY = 0;\n        srcHeight = Math.min(initialHeight, sourceHeight - srcY);\n        dstHeight = srcHeight;\n      }\n\n      var params = [srcX, srcY, srcWidth, srcHeight]; // Avoid \"IndexSizeError\"\n\n      if (dstWidth > 0 && dstHeight > 0) {\n        var scale = width / initialWidth;\n        params.push(dstX * scale, dstY * scale, dstWidth * scale, dstHeight * scale);\n      } // All the numerical parameters should be integer for `drawImage`\n      // https://github.com/fengyuanchen/cropper/issues/476\n\n\n      context.drawImage.apply(context, [source].concat(_toConsumableArray(params.map(function (param) {\n        return Math.floor(normalizeDecimalNumber(param));\n      }))));\n      return canvas;\n    },\n\n    /**\n     * Change the aspect ratio of the crop box.\n     * @param {number} aspectRatio - The new aspect ratio.\n     * @returns {Cropper} this\n     */\n    setAspectRatio: function setAspectRatio(aspectRatio) {\n      var options = this.options;\n\n      if (!this.disabled && !isUndefined(aspectRatio)) {\n        // 0 -> NaN\n        options.aspectRatio = Math.max(0, aspectRatio) || NaN;\n\n        if (this.ready) {\n          this.initCropBox();\n\n          if (this.cropped) {\n            this.renderCropBox();\n          }\n        }\n      }\n\n      return this;\n    },\n\n    /**\n     * Change the drag mode.\n     * @param {string} mode - The new drag mode.\n     * @returns {Cropper} this\n     */\n    setDragMode: function setDragMode(mode) {\n      var options = this.options,\n          dragBox = this.dragBox,\n          face = this.face;\n\n      if (this.ready && !this.disabled) {\n        var croppable = mode === DRAG_MODE_CROP;\n        var movable = options.movable && mode === DRAG_MODE_MOVE;\n        mode = croppable || movable ? mode : DRAG_MODE_NONE;\n        options.dragMode = mode;\n        setData(dragBox, DATA_ACTION, mode);\n        toggleClass(dragBox, CLASS_CROP, croppable);\n        toggleClass(dragBox, CLASS_MOVE, movable);\n\n        if (!options.cropBoxMovable) {\n          // Sync drag mode to crop box when it is not movable\n          setData(face, DATA_ACTION, mode);\n          toggleClass(face, CLASS_CROP, croppable);\n          toggleClass(face, CLASS_MOVE, movable);\n        }\n      }\n\n      return this;\n    }\n  };\n\n  var AnotherCropper = WINDOW.Cropper;\n\n  var Cropper = /*#__PURE__*/function () {\n    /**\n     * Create a new Cropper.\n     * @param {Element} element - The target element for cropping.\n     * @param {Object} [options={}] - The configuration options.\n     */\n    function Cropper(element) {\n      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n      _classCallCheck(this, Cropper);\n\n      if (!element || !REGEXP_TAG_NAME.test(element.tagName)) {\n        throw new Error('The first argument is required and must be an <img> or <canvas> element.');\n      }\n\n      this.element = element;\n      this.options = assign({}, DEFAULTS, isPlainObject(options) && options);\n      this.cropped = false;\n      this.disabled = false;\n      this.pointers = {};\n      this.ready = false;\n      this.reloading = false;\n      this.replaced = false;\n      this.sized = false;\n      this.sizing = false;\n      this.init();\n    }\n\n    _createClass(Cropper, [{\n      key: \"init\",\n      value: function init() {\n        var element = this.element;\n        var tagName = element.tagName.toLowerCase();\n        var url;\n\n        if (element[NAMESPACE]) {\n          return;\n        }\n\n        element[NAMESPACE] = this;\n\n        if (tagName === 'img') {\n          this.isImg = true; // e.g.: \"img/picture.jpg\"\n\n          url = element.getAttribute('src') || '';\n          this.originalUrl = url; // Stop when it's a blank image\n\n          if (!url) {\n            return;\n          } // e.g.: \"https://example.com/img/picture.jpg\"\n\n\n          url = element.src;\n        } else if (tagName === 'canvas' && window.HTMLCanvasElement) {\n          url = element.toDataURL();\n        }\n\n        this.load(url);\n      }\n    }, {\n      key: \"load\",\n      value: function load(url) {\n        var _this = this;\n\n        if (!url) {\n          return;\n        }\n\n        this.url = url;\n        this.imageData = {};\n        var element = this.element,\n            options = this.options;\n\n        if (!options.rotatable && !options.scalable) {\n          options.checkOrientation = false;\n        } // Only IE10+ supports Typed Arrays\n\n\n        if (!options.checkOrientation || !window.ArrayBuffer) {\n          this.clone();\n          return;\n        } // Detect the mime type of the image directly if it is a Data URL\n\n\n        if (REGEXP_DATA_URL.test(url)) {\n          // Read ArrayBuffer from Data URL of JPEG images directly for better performance\n          if (REGEXP_DATA_URL_JPEG.test(url)) {\n            this.read(dataURLToArrayBuffer(url));\n          } else {\n            // Only a JPEG image may contains Exif Orientation information,\n            // the rest types of Data URLs are not necessary to check orientation at all.\n            this.clone();\n          }\n\n          return;\n        } // 1. Detect the mime type of the image by a XMLHttpRequest.\n        // 2. Load the image as ArrayBuffer for reading orientation if its a JPEG image.\n\n\n        var xhr = new XMLHttpRequest();\n        var clone = this.clone.bind(this);\n        this.reloading = true;\n        this.xhr = xhr; // 1. Cross origin requests are only supported for protocol schemes:\n        // http, https, data, chrome, chrome-extension.\n        // 2. Access to XMLHttpRequest from a Data URL will be blocked by CORS policy\n        // in some browsers as IE11 and Safari.\n\n        xhr.onabort = clone;\n        xhr.onerror = clone;\n        xhr.ontimeout = clone;\n\n        xhr.onprogress = function () {\n          // Abort the request directly if it not a JPEG image for better performance\n          if (xhr.getResponseHeader('content-type') !== MIME_TYPE_JPEG) {\n            xhr.abort();\n          }\n        };\n\n        xhr.onload = function () {\n          _this.read(xhr.response);\n        };\n\n        xhr.onloadend = function () {\n          _this.reloading = false;\n          _this.xhr = null;\n        }; // Bust cache when there is a \"crossOrigin\" property to avoid browser cache error\n\n\n        if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) {\n          url = addTimestamp(url);\n        } // The third parameter is required for avoiding side-effect (#682)\n\n\n        xhr.open('GET', url, true);\n        xhr.responseType = 'arraybuffer';\n        xhr.withCredentials = element.crossOrigin === 'use-credentials';\n        xhr.send();\n      }\n    }, {\n      key: \"read\",\n      value: function read(arrayBuffer) {\n        var options = this.options,\n            imageData = this.imageData; // Reset the orientation value to its default value 1\n        // as some iOS browsers will render image with its orientation\n\n        var orientation = resetAndGetOrientation(arrayBuffer);\n        var rotate = 0;\n        var scaleX = 1;\n        var scaleY = 1;\n\n        if (orientation > 1) {\n          // Generate a new URL which has the default orientation value\n          this.url = arrayBufferToDataURL(arrayBuffer, MIME_TYPE_JPEG);\n\n          var _parseOrientation = parseOrientation(orientation);\n\n          rotate = _parseOrientation.rotate;\n          scaleX = _parseOrientation.scaleX;\n          scaleY = _parseOrientation.scaleY;\n        }\n\n        if (options.rotatable) {\n          imageData.rotate = rotate;\n        }\n\n        if (options.scalable) {\n          imageData.scaleX = scaleX;\n          imageData.scaleY = scaleY;\n        }\n\n        this.clone();\n      }\n    }, {\n      key: \"clone\",\n      value: function clone() {\n        var element = this.element,\n            url = this.url;\n        var crossOrigin = element.crossOrigin;\n        var crossOriginUrl = url;\n\n        if (this.options.checkCrossOrigin && isCrossOriginURL(url)) {\n          if (!crossOrigin) {\n            crossOrigin = 'anonymous';\n          } // Bust cache when there is not a \"crossOrigin\" property (#519)\n\n\n          crossOriginUrl = addTimestamp(url);\n        }\n\n        this.crossOrigin = crossOrigin;\n        this.crossOriginUrl = crossOriginUrl;\n        var image = document.createElement('img');\n\n        if (crossOrigin) {\n          image.crossOrigin = crossOrigin;\n        }\n\n        image.src = crossOriginUrl || url;\n        image.alt = element.alt || 'The image to crop';\n        this.image = image;\n        image.onload = this.start.bind(this);\n        image.onerror = this.stop.bind(this);\n        addClass(image, CLASS_HIDE);\n        element.parentNode.insertBefore(image, element.nextSibling);\n      }\n    }, {\n      key: \"start\",\n      value: function start() {\n        var _this2 = this;\n\n        var image = this.image;\n        image.onload = null;\n        image.onerror = null;\n        this.sizing = true; // Match all browsers that use WebKit as the layout engine in iOS devices,\n        // such as Safari for iOS, Chrome for iOS, and in-app browsers.\n\n        var isIOSWebKit = WINDOW.navigator && /(?:iPad|iPhone|iPod).*?AppleWebKit/i.test(WINDOW.navigator.userAgent);\n\n        var done = function done(naturalWidth, naturalHeight) {\n          assign(_this2.imageData, {\n            naturalWidth: naturalWidth,\n            naturalHeight: naturalHeight,\n            aspectRatio: naturalWidth / naturalHeight\n          });\n          _this2.initialImageData = assign({}, _this2.imageData);\n          _this2.sizing = false;\n          _this2.sized = true;\n\n          _this2.build();\n        }; // Most modern browsers (excepts iOS WebKit)\n\n\n        if (image.naturalWidth && !isIOSWebKit) {\n          done(image.naturalWidth, image.naturalHeight);\n          return;\n        }\n\n        var sizingImage = document.createElement('img');\n        var body = document.body || document.documentElement;\n        this.sizingImage = sizingImage;\n\n        sizingImage.onload = function () {\n          done(sizingImage.width, sizingImage.height);\n\n          if (!isIOSWebKit) {\n            body.removeChild(sizingImage);\n          }\n        };\n\n        sizingImage.src = image.src; // iOS WebKit will convert the image automatically\n        // with its orientation once append it into DOM (#279)\n\n        if (!isIOSWebKit) {\n          sizingImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;';\n          body.appendChild(sizingImage);\n        }\n      }\n    }, {\n      key: \"stop\",\n      value: function stop() {\n        var image = this.image;\n        image.onload = null;\n        image.onerror = null;\n        image.parentNode.removeChild(image);\n        this.image = null;\n      }\n    }, {\n      key: \"build\",\n      value: function build() {\n        if (!this.sized || this.ready) {\n          return;\n        }\n\n        var element = this.element,\n            options = this.options,\n            image = this.image; // Create cropper elements\n\n        var container = element.parentNode;\n        var template = document.createElement('div');\n        template.innerHTML = TEMPLATE;\n        var cropper = template.querySelector(\".\".concat(NAMESPACE, \"-container\"));\n        var canvas = cropper.querySelector(\".\".concat(NAMESPACE, \"-canvas\"));\n        var dragBox = cropper.querySelector(\".\".concat(NAMESPACE, \"-drag-box\"));\n        var cropBox = cropper.querySelector(\".\".concat(NAMESPACE, \"-crop-box\"));\n        var face = cropBox.querySelector(\".\".concat(NAMESPACE, \"-face\"));\n        this.container = container;\n        this.cropper = cropper;\n        this.canvas = canvas;\n        this.dragBox = dragBox;\n        this.cropBox = cropBox;\n        this.viewBox = cropper.querySelector(\".\".concat(NAMESPACE, \"-view-box\"));\n        this.face = face;\n        canvas.appendChild(image); // Hide the original image\n\n        addClass(element, CLASS_HIDDEN); // Inserts the cropper after to the current image\n\n        container.insertBefore(cropper, element.nextSibling); // Show the image if is hidden\n\n        if (!this.isImg) {\n          removeClass(image, CLASS_HIDE);\n        }\n\n        this.initPreview();\n        this.bind();\n        options.initialAspectRatio = Math.max(0, options.initialAspectRatio) || NaN;\n        options.aspectRatio = Math.max(0, options.aspectRatio) || NaN;\n        options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0;\n        addClass(cropBox, CLASS_HIDDEN);\n\n        if (!options.guides) {\n          addClass(cropBox.getElementsByClassName(\"\".concat(NAMESPACE, \"-dashed\")), CLASS_HIDDEN);\n        }\n\n        if (!options.center) {\n          addClass(cropBox.getElementsByClassName(\"\".concat(NAMESPACE, \"-center\")), CLASS_HIDDEN);\n        }\n\n        if (options.background) {\n          addClass(cropper, \"\".concat(NAMESPACE, \"-bg\"));\n        }\n\n        if (!options.highlight) {\n          addClass(face, CLASS_INVISIBLE);\n        }\n\n        if (options.cropBoxMovable) {\n          addClass(face, CLASS_MOVE);\n          setData(face, DATA_ACTION, ACTION_ALL);\n        }\n\n        if (!options.cropBoxResizable) {\n          addClass(cropBox.getElementsByClassName(\"\".concat(NAMESPACE, \"-line\")), CLASS_HIDDEN);\n          addClass(cropBox.getElementsByClassName(\"\".concat(NAMESPACE, \"-point\")), CLASS_HIDDEN);\n        }\n\n        this.render();\n        this.ready = true;\n        this.setDragMode(options.dragMode);\n\n        if (options.autoCrop) {\n          this.crop();\n        }\n\n        this.setData(options.data);\n\n        if (isFunction(options.ready)) {\n          addListener(element, EVENT_READY, options.ready, {\n            once: true\n          });\n        }\n\n        dispatchEvent(element, EVENT_READY);\n      }\n    }, {\n      key: \"unbuild\",\n      value: function unbuild() {\n        if (!this.ready) {\n          return;\n        }\n\n        this.ready = false;\n        this.unbind();\n        this.resetPreview();\n        this.cropper.parentNode.removeChild(this.cropper);\n        removeClass(this.element, CLASS_HIDDEN);\n      }\n    }, {\n      key: \"uncreate\",\n      value: function uncreate() {\n        if (this.ready) {\n          this.unbuild();\n          this.ready = false;\n          this.cropped = false;\n        } else if (this.sizing) {\n          this.sizingImage.onload = null;\n          this.sizing = false;\n          this.sized = false;\n        } else if (this.reloading) {\n          this.xhr.onabort = null;\n          this.xhr.abort();\n        } else if (this.image) {\n          this.stop();\n        }\n      }\n      /**\n       * Get the no conflict cropper class.\n       * @returns {Cropper} The cropper class.\n       */\n\n    }], [{\n      key: \"noConflict\",\n      value: function noConflict() {\n        window.Cropper = AnotherCropper;\n        return Cropper;\n      }\n      /**\n       * Change the default options.\n       * @param {Object} options - The new default options.\n       */\n\n    }, {\n      key: \"setDefaults\",\n      value: function setDefaults(options) {\n        assign(DEFAULTS, isPlainObject(options) && options);\n      }\n    }]);\n\n    return Cropper;\n  }();\n\n  assign(Cropper.prototype, render, preview, events, handlers, change, methods);\n\n  return Cropper;\n\n})));\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/cxselect/jquery.cxselect.js",
    "content": "/*!\r\n * jQuery cxSelect\r\n * @name jquery.cxselect.js\r\n * @version 1.4.2\r\n * @date 2017-09-26\r\n * @author ciaoca\r\n * @email ciaoca@gmail.com\r\n * @site https://github.com/ciaoca/cxSelect\r\n * @license Released under the MIT license\r\n */\r\n(function(factory) {\r\n  if (typeof define === 'function' && define.amd) {\r\n    define(['jquery'], factory);\r\n  } else {\r\n    factory(window.jQuery || window.Zepto || window.$);\r\n  };\r\n}(function($) {\r\n  var cxSelect = function() {\r\n    var self = this;\r\n    var dom, settings, callback;\r\n\r\n    // 分配参数\r\n    for (var i = 0, l = arguments.length; i < l; i++) {\r\n      if (cxSelect.isJquery(arguments[i]) || cxSelect.isZepto(arguments[i])) {\r\n        dom = arguments[i];\r\n      } else if (cxSelect.isElement(arguments[i])) {\r\n        dom = $(arguments[i]);\r\n      } else if (typeof arguments[i] === 'function') {\r\n        callback = arguments[i];\r\n      } else if (typeof arguments[i] === 'object') {\r\n        settings = arguments[i];\r\n      };\r\n    };\r\n\r\n    var api = new cxSelect.init(dom, settings);\r\n\r\n    if (typeof callback === 'function') {\r\n      callback(api);\r\n    };\r\n\r\n    return api;\r\n  };\r\n\r\n  cxSelect.isElement = function(o){\r\n    if (o && (typeof HTMLElement === 'function' || typeof HTMLElement === 'object') && o instanceof HTMLElement) {\r\n      return true;\r\n    } else {\r\n      return (o && o.nodeType && o.nodeType === 1) ? true : false;\r\n    };\r\n  };\r\n\r\n  cxSelect.isJquery = function(o){\r\n    return (o && o.length && (typeof jQuery === 'function' || typeof jQuery === 'object') && o instanceof jQuery) ? true : false;\r\n  };\r\n\r\n  cxSelect.isZepto = function(o){\r\n    return (o && o.length && (typeof Zepto === 'function' || typeof Zepto === 'object') && Zepto.zepto.isZ(o)) ? true : false;\r\n  };\r\n\r\n  cxSelect.getIndex = function(n, required) {\r\n    return required ? n : n - 1;\r\n  };\r\n\r\n  cxSelect.getData = function(data, space) {\r\n    if (typeof space === 'string' && space.length) {\r\n      space = space.split('.');\r\n      for (var i = 0, l = space.length; i < l; i++) {\r\n        data = data[space[i]];\r\n      };\r\n    };\r\n    return data;\r\n  };\r\n\r\n  cxSelect.init = function(dom, settings) {\r\n    var self = this;\r\n\r\n    if (!cxSelect.isJquery(dom) && !cxSelect.isZepto(dom)) {return};\r\n\r\n    var theSelect = {\r\n      dom: {\r\n        box: dom\r\n      }\r\n    };\r\n\r\n    self.attach = cxSelect.attach.bind(theSelect);\r\n    self.detach = cxSelect.detach.bind(theSelect);\r\n    self.setOptions = cxSelect.setOptions.bind(theSelect);\r\n    self.clear = cxSelect.clear.bind(theSelect);\r\n\r\n    theSelect.changeEvent = function() {\r\n      cxSelect.selectChange.call(theSelect, this.className);\r\n    };\r\n\r\n    theSelect.settings = $.extend({}, $.cxSelect.defaults, settings, {\r\n      url: theSelect.dom.box.data('url'),\r\n      emptyStyle: theSelect.dom.box.data('emptyStyle'),\r\n      required: theSelect.dom.box.data('required'),\r\n      firstTitle: theSelect.dom.box.data('firstTitle'),\r\n      firstValue: theSelect.dom.box.data('firstValue'),\r\n      jsonSpace: theSelect.dom.box.data('jsonSpace'),\r\n      jsonName: theSelect.dom.box.data('jsonName'),\r\n      jsonValue: theSelect.dom.box.data('jsonValue'),\r\n      jsonSub: theSelect.dom.box.data('jsonSub')\r\n    });\r\n\r\n    var _dataSelects = theSelect.dom.box.data('selects');\r\n\r\n    if (typeof _dataSelects === 'string' && _dataSelects.length) {\r\n      theSelect.settings.selects = _dataSelects.split(',');\r\n    };\r\n\r\n    self.setOptions();\r\n    self.attach();\r\n\r\n    // 使用独立接口获取数据\r\n    if (!theSelect.settings.url && !theSelect.settings.data) {\r\n      cxSelect.start.apply(theSelect);\r\n\r\n    // 设置自定义数据\r\n    } else if ($.isArray(theSelect.settings.data)) {\r\n      cxSelect.start.call(theSelect, theSelect.settings.data);\r\n\r\n    // 设置 URL，通过 Ajax 获取数据\r\n    } else if (typeof theSelect.settings.url === 'string' && theSelect.settings.url.length) {\r\n      $.getJSON(theSelect.settings.url, function(json) {\r\n        cxSelect.start.call(theSelect, json);\r\n      });\r\n    };\r\n  };\r\n\r\n  // 设置参数\r\n  cxSelect.setOptions = function(opts) {\r\n    var self = this;\r\n\r\n    if (opts) {\r\n      $.extend(self.settings, opts);\r\n    };\r\n\r\n    // 初次或重设选择器组\r\n    if (!$.isArray(self.selectArray) || !self.selectArray.length || (opts && opts.selects)) {\r\n      self.selectArray = [];\r\n\r\n      if ($.isArray(self.settings.selects) && self.settings.selects.length) {\r\n        var _tempSelect;\r\n\r\n        for (var i = 0, l = self.settings.selects.length; i < l; i++) {\r\n          _tempSelect = self.dom.box.find('select.' + self.settings.selects[i]);\r\n\r\n          if (!_tempSelect || !_tempSelect.length) {break};\r\n\r\n          self.selectArray.push(_tempSelect);\r\n        };\r\n      };\r\n    };\r\n\r\n    if (opts) {\r\n      if (!$.isArray(opts.data) && typeof opts.url === 'string' && opts.url.length) {\r\n        $.getJSON(self.settings.url, function(json) {\r\n          cxSelect.start.call(self, json);\r\n        });\r\n\r\n      } else {\r\n        cxSelect.start.call(self, opts.data);\r\n      };\r\n    };\r\n  };\r\n\r\n  // 绑定\r\n  cxSelect.attach = function() {\r\n    var self = this;\r\n\r\n    if (!self.attachStatus) {\r\n      self.dom.box.on('change', 'select', self.changeEvent);\r\n    };\r\n\r\n    if (typeof self.attachStatus === 'boolean') {\r\n      cxSelect.start.call(self);\r\n    };\r\n\r\n    self.attachStatus = true;\r\n  };\r\n\r\n  // 移除绑定\r\n  cxSelect.detach = function() {\r\n    var self = this;\r\n    self.dom.box.off('change', 'select', self.changeEvent);\r\n    self.attachStatus = false;\r\n  };\r\n\r\n  // 清空选项\r\n  cxSelect.clear = function(index) {\r\n    var self = this;\r\n    var _style = {\r\n      display: '',\r\n      visibility: ''\r\n    };\r\n\r\n    index = isNaN(index) ? 0 : index;\r\n\r\n    // 清空后面的 select\r\n    for (var i = index, l = self.selectArray.length; i < l; i++) {\r\n      self.selectArray[i].empty().prop('disabled', true);\r\n\r\n      if (self.settings.emptyStyle === 'none') {\r\n        _style.display = 'none';\r\n      } else if (self.settings.emptyStyle === 'hidden') {\r\n        _style.visibility = 'hidden';\r\n      };\r\n\r\n      self.selectArray[i].css(_style);\r\n    };\r\n  };\r\n\r\n  cxSelect.start = function(data) {\r\n    var self = this;\r\n\r\n    if ($.isArray(data)) {\r\n      self.settings.data = cxSelect.getData(data, self.settings.jsonSpace);\r\n    };\r\n\r\n    if (!self.selectArray.length) {return};\r\n\r\n    // 保存默认值\r\n    for (var i = 0, l = self.selectArray.length; i < l; i++) {\r\n      if (typeof self.selectArray[i].attr('data-value') !== 'string' && self.selectArray[i][0].options.length) {\r\n        self.selectArray[i].attr('data-value', self.selectArray[i].val());\r\n      };\r\n    };\r\n\r\n    if (self.settings.data || (typeof self.selectArray[0].data('url') === 'string' && self.selectArray[0].data('url').length)) {\r\n      cxSelect.getOptionData.call(self, 0);\r\n    } else if (self.selectArray[0][0].options.length && typeof self.selectArray[0].attr('data-value') === 'string' && self.selectArray[0].attr('data-value').length) {\r\n      self.selectArray[0].val(self.selectArray[0].attr('data-value'));\r\n      cxSelect.getOptionData.call(self, 1);\r\n    } else {\r\n      self.selectArray[0].prop('disabled', false).css({\r\n        'display': '',\r\n        'visibility': ''\r\n      });\r\n    };\r\n  };\r\n\r\n  // 获取选项数据\r\n  cxSelect.getOptionData = function(index) {\r\n    var self = this;\r\n\r\n    if (typeof index !== 'number' || isNaN(index) || index < 0 || index >= self.selectArray.length) {return};\r\n\r\n    var _indexPrev = index - 1;\r\n    var _select = self.selectArray[index];\r\n    var _selectData;\r\n    var _valueIndex;\r\n    var _dataUrl = _select.data('url');\r\n    var _jsonSpace = typeof _select.data('jsonSpace') === 'undefined' ? self.settings.jsonSpace : _select.data('jsonSpace');\r\n    var _query = {};\r\n    var _queryName;\r\n    var _selectName;\r\n    var _selectValue;\r\n\r\n    cxSelect.clear.call(self, index);\r\n\r\n    // 使用独立接口\r\n    if (typeof _dataUrl === 'string' && _dataUrl.length) {\r\n      if (index > 0) {\r\n        for (var i = 0, j = 1; i < index; i++, j++) {\r\n          _queryName = self.selectArray[j].data('queryName');\r\n          _selectName = self.selectArray[i].attr('name');\r\n          _selectValue = self.selectArray[i].val();\r\n\r\n          if (typeof _queryName === 'string' && _queryName.length) {\r\n            _query[_queryName] = _selectValue;\r\n          } else if (typeof _selectName === 'string' && _selectName.length) {\r\n            _query[_selectName] = _selectValue;\r\n          };\r\n        };\r\n      };\r\n\r\n      $.getJSON(_dataUrl, _query, function(json) {\r\n        _selectData = cxSelect.getData(json, _jsonSpace);\r\n\r\n        cxSelect.buildOption.call(self, index, _selectData);\r\n      });\r\n\r\n    // 使用整合数据\r\n    } else if (self.settings.data && typeof self.settings.data === 'object') {\r\n      _selectData = self.settings.data;\r\n\r\n      for (var i = 0; i < index; i++) {\r\n        _valueIndex = cxSelect.getIndex(self.selectArray[i][0].selectedIndex, typeof self.selectArray[i].data('required') === 'boolean' ? self.selectArray[i].data('required') : self.settings.required);\r\n\r\n        if (typeof _selectData[_valueIndex] === 'object' && $.isArray(_selectData[_valueIndex][self.settings.jsonSub]) && _selectData[_valueIndex][self.settings.jsonSub].length) {\r\n          _selectData = _selectData[_valueIndex][self.settings.jsonSub];\r\n        } else {\r\n          _selectData = null;\r\n          break;\r\n        };\r\n      };\r\n\r\n      cxSelect.buildOption.call(self, index, _selectData);\r\n    };\r\n  };\r\n\r\n  // 构建选项列表\r\n  cxSelect.buildOption = function(index, data) {\r\n    var self = this;\r\n\r\n    var _select = self.selectArray[index];\r\n    var _required = typeof _select.data('required') === 'boolean' ? _select.data('required') : self.settings.required;\r\n    var _firstTitle = typeof _select.data('firstTitle') === 'undefined' ? self.settings.firstTitle : _select.data('firstTitle');\r\n    var _firstValue = typeof _select.data('firstValue') === 'undefined' ? self.settings.firstValue : _select.data('firstValue');\r\n    var _jsonName = typeof _select.data('jsonName') === 'undefined' ? self.settings.jsonName : _select.data('jsonName');\r\n    var _jsonValue = typeof _select.data('jsonValue') === 'undefined' ? self.settings.jsonValue : _select.data('jsonValue');\r\n\r\n    if (!$.isArray(data)) {return};\r\n\r\n    var _html = !_required ? '<option value=\"' + String(_firstValue) + '\">' + String(_firstTitle) + '</option>' : '';\r\n\r\n    // 区分标题、值的数据\r\n    if (typeof _jsonName === 'string' && _jsonName.length) {\r\n      // 无值字段时使用标题作为值\r\n      if (typeof _jsonValue !== 'string' || !_jsonValue.length) {\r\n        _jsonValue = _jsonName;\r\n      };\r\n\r\n      for (var i = 0, l = data.length; i < l; i++) {\r\n        _html += '<option value=\"' + String(data[i][_jsonValue]) + '\">' + String(data[i][_jsonName]) + '</option>';\r\n      };\r\n\r\n    // 数组即为值的数据\r\n    } else {\r\n      for (var i = 0, l = data.length; i < l; i++) {\r\n        _html += '<option value=\"' + String(data[i]) + '\">' + String(data[i]) + '</option>';\r\n      };\r\n    };\r\n\r\n    _select.html(_html).prop('disabled', false).css({\r\n      'display': '',\r\n      'visibility': ''\r\n    });\r\n\r\n    // 初次加载设置默认值\r\n    if (typeof _select.attr('data-value') === 'string') {\r\n      _select.val(String(_select.attr('data-value'))).removeAttr('data-value');\r\n\r\n      if (_select[0].selectedIndex < 0) {\r\n        _select[0].options[0].selected = true;\r\n      };\r\n    };\r\n\r\n    if (_required || _select[0].selectedIndex > 0) {\r\n      _select.trigger('change');\r\n    };\r\n\r\n  };\r\n\r\n  // 改变选择时的处理\r\n  cxSelect.selectChange = function(name) {\r\n    var self = this;\r\n\r\n    if (typeof name !== 'string' || !name.length) {return};\r\n\r\n    var index;\r\n\r\n    name = name.replace(/\\s+/g, ',');\r\n    name = ',' + name + ',';\r\n\r\n    // 获取当前 select 位置\r\n    for (var i = 0, l = self.selectArray.length; i < l; i++) {\r\n      if (name.indexOf(',' + self.settings.selects[i] + ',') > -1) {\r\n        index = i;\r\n        break;\r\n      };\r\n    };\r\n\r\n    if (typeof index === 'number' && index > -1) {\r\n      index += 1;\r\n      cxSelect.getOptionData.call(self, index);\r\n    };\r\n  };\r\n\r\n  $.cxSelect = function() {\r\n    return cxSelect.apply(this, arguments);\r\n  };\r\n\r\n  // 默认值\r\n  $.cxSelect.defaults = {\r\n    selects: [],            // 下拉选框组\r\n    url: null,              // 列表数据文件路径（URL）或数组数据\r\n    data: null,             // 自定义数据\r\n    emptyStyle: null,       // 无数据状态显示方式\r\n    required: false,        // 是否为必选\r\n    firstTitle: '请选择',    // 第一个选项的标题\r\n    firstValue: '',         // 第一个选项的值\r\n    jsonSpace: '',          // 数据命名空间\r\n    jsonName: 'n',          // 数据标题字段名称\r\n    jsonValue: '',          // 数据值字段名称\r\n    jsonSub: 's'            // 子集数据字段名称\r\n  };\r\n\r\n  $.fn.cxSelect = function(settings, callback) {\r\n    this.each(function(i) {\r\n      $.cxSelect(this, settings, callback);\r\n    });\r\n    return this;\r\n  };\r\n}));\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/datapicker/bootstrap-datetimepicker.css",
    "content": "/*!\n * Datetimepicker for Bootstrap\n *\n * Copyright 2012 Stefan Petre\n * Improvements by Andrew Rowls\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n */\n.datetimepicker {\n\tpadding: 4px;\n\tmargin-top: 1px;\n\t-webkit-border-radius: 4px;\n\t-moz-border-radius: 4px;\n\tborder-radius: 4px;\n\tdirection: ltr;\n}\n\n.datetimepicker-inline {\n\twidth: 220px;\n}\n\n.datetimepicker.datetimepicker-rtl {\n\tdirection: rtl;\n}\n\n.datetimepicker.datetimepicker-rtl table tr td span {\n\tfloat: right;\n}\n\n.datetimepicker-dropdown, .datetimepicker-dropdown-left {\n\ttop: 0;\n\tleft: 0;\n}\n\n[class*=\" datetimepicker-dropdown\"]:before {\n\tcontent: '';\n\tdisplay: inline-block;\n\tborder-left: 7px solid transparent;\n\tborder-right: 7px solid transparent;\n\tborder-bottom: 7px solid #cccccc;\n\tborder-bottom-color: rgba(0, 0, 0, 0.2);\n\tposition: absolute;\n}\n\n[class*=\" datetimepicker-dropdown\"]:after {\n\tcontent: '';\n\tdisplay: inline-block;\n\tborder-left: 6px solid transparent;\n\tborder-right: 6px solid transparent;\n\tborder-bottom: 6px solid #ffffff;\n\tposition: absolute;\n}\n\n[class*=\" datetimepicker-dropdown-top\"]:before {\n\tcontent: '';\n\tdisplay: inline-block;\n\tborder-left: 7px solid transparent;\n\tborder-right: 7px solid transparent;\n\tborder-top: 7px solid #cccccc;\n\tborder-top-color: rgba(0, 0, 0, 0.2);\n\tborder-bottom: 0;\n}\n\n[class*=\" datetimepicker-dropdown-top\"]:after {\n\tcontent: '';\n\tdisplay: inline-block;\n\tborder-left: 6px solid transparent;\n\tborder-right: 6px solid transparent;\n\tborder-top: 6px solid #ffffff;\n\tborder-bottom: 0;\n}\n\n.datetimepicker-dropdown-bottom-left:before {\n\ttop: -7px;\n\tright: 6px;\n}\n\n.datetimepicker-dropdown-bottom-left:after {\n\ttop: -6px;\n\tright: 7px;\n}\n\n.datetimepicker-dropdown-bottom-right:before {\n\ttop: -7px;\n\tleft: 6px;\n}\n\n.datetimepicker-dropdown-bottom-right:after {\n\ttop: -6px;\n\tleft: 7px;\n}\n\n.datetimepicker-dropdown-top-left:before {\n\tbottom: -7px;\n\tright: 6px;\n}\n\n.datetimepicker-dropdown-top-left:after {\n\tbottom: -6px;\n\tright: 7px;\n}\n\n.datetimepicker-dropdown-top-right:before {\n\tbottom: -7px;\n\tleft: 6px;\n}\n\n.datetimepicker-dropdown-top-right:after {\n\tbottom: -6px;\n\tleft: 7px;\n}\n\n.datetimepicker > div {\n\tdisplay: none;\n}\n\n.datetimepicker.minutes div.datetimepicker-minutes {\n\tdisplay: block;\n}\n\n.datetimepicker.hours div.datetimepicker-hours {\n\tdisplay: block;\n}\n\n.datetimepicker.days div.datetimepicker-days {\n\tdisplay: block;\n}\n\n.datetimepicker.months div.datetimepicker-months {\n\tdisplay: block;\n}\n\n.datetimepicker.years div.datetimepicker-years {\n\tdisplay: block;\n}\n\n.datetimepicker table {\n\tmargin: 0;\n}\n\n.datetimepicker  td,\n.datetimepicker th {\n\ttext-align: center;\n\twidth: 20px;\n\theight: 20px;\n\t-webkit-border-radius: 4px;\n\t-moz-border-radius: 4px;\n\tborder-radius: 4px;\n\tborder: none;\n}\n\n.table-striped .datetimepicker table tr td,\n.table-striped .datetimepicker table tr th {\n\tbackground-color: transparent;\n}\n\n.datetimepicker table tr td.minute:hover {\n\tbackground: #eeeeee;\n\tcursor: pointer;\n}\n\n.datetimepicker table tr td.hour:hover {\n\tbackground: #eeeeee;\n\tcursor: pointer;\n}\n\n.datetimepicker table tr td.day:hover {\n\tbackground: #eeeeee;\n\tcursor: pointer;\n}\n\n.datetimepicker table tr td.old,\n.datetimepicker table tr td.new {\n\tcolor: #999999;\n}\n\n.datetimepicker table tr td.disabled,\n.datetimepicker table tr td.disabled:hover {\n\tbackground: none;\n\tcolor: #999999;\n\tcursor: default;\n}\n\n.datetimepicker table tr td.today,\n.datetimepicker table tr td.today:hover,\n.datetimepicker table tr td.today.disabled,\n.datetimepicker table tr td.today.disabled:hover {\n\tbackground-color: #fde19a;\n\tbackground-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));\n\tbackground-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: -o-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: linear-gradient(to bottom, #fdd49a, #fdf59a);\n\tbackground-repeat: repeat-x;\n\tfilter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);\n\tborder-color: #fdf59a #fdf59a #fbed50;\n\tborder-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n\tfilter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.datetimepicker table tr td.today:hover,\n.datetimepicker table tr td.today:hover:hover,\n.datetimepicker table tr td.today.disabled:hover,\n.datetimepicker table tr td.today.disabled:hover:hover,\n.datetimepicker table tr td.today:active,\n.datetimepicker table tr td.today:hover:active,\n.datetimepicker table tr td.today.disabled:active,\n.datetimepicker table tr td.today.disabled:hover:active,\n.datetimepicker table tr td.today.active,\n.datetimepicker table tr td.today:hover.active,\n.datetimepicker table tr td.today.disabled.active,\n.datetimepicker table tr td.today.disabled:hover.active,\n.datetimepicker table tr td.today.disabled,\n.datetimepicker table tr td.today:hover.disabled,\n.datetimepicker table tr td.today.disabled.disabled,\n.datetimepicker table tr td.today.disabled:hover.disabled,\n.datetimepicker table tr td.today[disabled],\n.datetimepicker table tr td.today:hover[disabled],\n.datetimepicker table tr td.today.disabled[disabled],\n.datetimepicker table tr td.today.disabled:hover[disabled] {\n\tbackground-color: #fdf59a;\n}\n\n.datetimepicker table tr td.today:active,\n.datetimepicker table tr td.today:hover:active,\n.datetimepicker table tr td.today.disabled:active,\n.datetimepicker table tr td.today.disabled:hover:active,\n.datetimepicker table tr td.today.active,\n.datetimepicker table tr td.today:hover.active,\n.datetimepicker table tr td.today.disabled.active,\n.datetimepicker table tr td.today.disabled:hover.active {\n\tbackground-color: #fbf069;\n}\n\n.datetimepicker table tr td.active,\n.datetimepicker table tr td.active:hover,\n.datetimepicker table tr td.active.disabled,\n.datetimepicker table tr td.active.disabled:hover {\n\tbackground-color: #006dcc;\n\tbackground-image: -moz-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -ms-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));\n\tbackground-image: -webkit-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -o-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: linear-gradient(to bottom, #0088cc, #0044cc);\n\tbackground-repeat: repeat-x;\n\tfilter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);\n\tborder-color: #0044cc #0044cc #002a80;\n\tborder-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n\tfilter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n\tcolor: #ffffff;\n\ttext-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.datetimepicker table tr td.active:hover,\n.datetimepicker table tr td.active:hover:hover,\n.datetimepicker table tr td.active.disabled:hover,\n.datetimepicker table tr td.active.disabled:hover:hover,\n.datetimepicker table tr td.active:active,\n.datetimepicker table tr td.active:hover:active,\n.datetimepicker table tr td.active.disabled:active,\n.datetimepicker table tr td.active.disabled:hover:active,\n.datetimepicker table tr td.active.active,\n.datetimepicker table tr td.active:hover.active,\n.datetimepicker table tr td.active.disabled.active,\n.datetimepicker table tr td.active.disabled:hover.active,\n.datetimepicker table tr td.active.disabled,\n.datetimepicker table tr td.active:hover.disabled,\n.datetimepicker table tr td.active.disabled.disabled,\n.datetimepicker table tr td.active.disabled:hover.disabled,\n.datetimepicker table tr td.active[disabled],\n.datetimepicker table tr td.active:hover[disabled],\n.datetimepicker table tr td.active.disabled[disabled],\n.datetimepicker table tr td.active.disabled:hover[disabled] {\n\tbackground-color: #0044cc;\n}\n\n.datetimepicker table tr td.active:active,\n.datetimepicker table tr td.active:hover:active,\n.datetimepicker table tr td.active.disabled:active,\n.datetimepicker table tr td.active.disabled:hover:active,\n.datetimepicker table tr td.active.active,\n.datetimepicker table tr td.active:hover.active,\n.datetimepicker table tr td.active.disabled.active,\n.datetimepicker table tr td.active.disabled:hover.active {\n\tbackground-color: #003399;\n}\n\n.datetimepicker table tr td span {\n\tdisplay: block;\n\twidth: 23%;\n\theight: 54px;\n\tline-height: 54px;\n\tfloat: left;\n\tmargin: 1%;\n\tcursor: pointer;\n\t-webkit-border-radius: 4px;\n\t-moz-border-radius: 4px;\n\tborder-radius: 4px;\n}\n\n.datetimepicker .datetimepicker-hours span {\n\theight: 26px;\n\tline-height: 26px;\n}\n\n.datetimepicker .datetimepicker-hours table tr td span.hour_am,\n.datetimepicker .datetimepicker-hours table tr td span.hour_pm {\n\twidth: 14.6%;\n}\n\n.datetimepicker .datetimepicker-hours fieldset legend,\n.datetimepicker .datetimepicker-minutes fieldset legend {\n\tmargin-bottom: inherit;\n\tline-height: 30px;\n}\n\n.datetimepicker .datetimepicker-minutes span {\n\theight: 26px;\n\tline-height: 26px;\n}\n\n.datetimepicker table tr td span:hover {\n\tbackground: #eeeeee;\n}\n\n.datetimepicker table tr td span.disabled,\n.datetimepicker table tr td span.disabled:hover {\n\tbackground: none;\n\tcolor: #999999;\n\tcursor: default;\n}\n\n.datetimepicker table tr td span.active,\n.datetimepicker table tr td span.active:hover,\n.datetimepicker table tr td span.active.disabled,\n.datetimepicker table tr td span.active.disabled:hover {\n\tbackground-color: #006dcc;\n\tbackground-image: -moz-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -ms-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));\n\tbackground-image: -webkit-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -o-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: linear-gradient(to bottom, #0088cc, #0044cc);\n\tbackground-repeat: repeat-x;\n\tfilter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);\n\tborder-color: #0044cc #0044cc #002a80;\n\tborder-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n\tfilter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n\tcolor: #ffffff;\n\ttext-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.datetimepicker table tr td span.active:hover,\n.datetimepicker table tr td span.active:hover:hover,\n.datetimepicker table tr td span.active.disabled:hover,\n.datetimepicker table tr td span.active.disabled:hover:hover,\n.datetimepicker table tr td span.active:active,\n.datetimepicker table tr td span.active:hover:active,\n.datetimepicker table tr td span.active.disabled:active,\n.datetimepicker table tr td span.active.disabled:hover:active,\n.datetimepicker table tr td span.active.active,\n.datetimepicker table tr td span.active:hover.active,\n.datetimepicker table tr td span.active.disabled.active,\n.datetimepicker table tr td span.active.disabled:hover.active,\n.datetimepicker table tr td span.active.disabled,\n.datetimepicker table tr td span.active:hover.disabled,\n.datetimepicker table tr td span.active.disabled.disabled,\n.datetimepicker table tr td span.active.disabled:hover.disabled,\n.datetimepicker table tr td span.active[disabled],\n.datetimepicker table tr td span.active:hover[disabled],\n.datetimepicker table tr td span.active.disabled[disabled],\n.datetimepicker table tr td span.active.disabled:hover[disabled] {\n\tbackground-color: #0044cc;\n}\n\n.datetimepicker table tr td span.active:active,\n.datetimepicker table tr td span.active:hover:active,\n.datetimepicker table tr td span.active.disabled:active,\n.datetimepicker table tr td span.active.disabled:hover:active,\n.datetimepicker table tr td span.active.active,\n.datetimepicker table tr td span.active:hover.active,\n.datetimepicker table tr td span.active.disabled.active,\n.datetimepicker table tr td span.active.disabled:hover.active {\n\tbackground-color: #003399;\n}\n\n.datetimepicker table tr td span.old {\n\tcolor: #999999;\n}\n\n.datetimepicker th.switch {\n\twidth: 145px;\n}\n\n.datetimepicker th span.glyphicon {\n\tpointer-events: none;\n}\n\n.datetimepicker thead tr:first-child th,\n.datetimepicker tfoot th {\n\tcursor: pointer;\n}\n\n.datetimepicker thead tr:first-child th:hover,\n.datetimepicker tfoot th:hover {\n\tbackground: #eeeeee;\n}\n\n.input-append.date .add-on i,\n.input-prepend.date .add-on i,\n.input-group.date .input-group-addon span {\n\tcursor: pointer;\n\twidth: 14px;\n\theight: 14px;\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/datapicker/bootstrap-datetimepicker.js",
    "content": "﻿/* =========================================================\n * bootstrap-datetimepicker.js\n * =========================================================\n * Copyright 2012 Stefan Petre\n *\n * Improvements by Andrew Rowls\n * Improvements by Sébastien Malot\n * Improvements by Yun Lai\n * Improvements by Kenneth Henderick\n * Improvements by CuGBabyBeaR\n * Improvements by Christian Vaas <auspex@auspex.eu>\n *\n * Project URL : http://www.malot.fr/bootstrap-datetimepicker\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================= */\n\n(function(factory){\n    if (typeof define === 'function' && define.amd)\n      define(['jquery'], factory);\n    else if (typeof exports === 'object')\n      factory(require('jquery'));\n    else\n      factory(jQuery);\n\n}(function($, undefined){\n\n  // Add ECMA262-5 Array methods if not supported natively (IE8)\n  if (!('indexOf' in Array.prototype)) {\n    Array.prototype.indexOf = function (find, i) {\n      if (i === undefined) i = 0;\n      if (i < 0) i += this.length;\n      if (i < 0) i = 0;\n      for (var n = this.length; i < n; i++) {\n        if (i in this && this[i] === find) {\n          return i;\n        }\n      }\n      return -1;\n    }\n  }\n\n  // Add timezone abbreviation support for ie6+, Chrome, Firefox\n  function timeZoneAbbreviation() {\n    var abbreviation, date, formattedStr, i, len, matchedStrings, ref, str;\n    date = (new Date()).toString();\n    formattedStr = ((ref = date.split('(')[1]) != null ? ref.slice(0, -1) : 0) || date.split(' ');\n    if (formattedStr instanceof Array) {\n      matchedStrings = [];\n      for (var i = 0, len = formattedStr.length; i < len; i++) {\n        str = formattedStr[i];\n        if ((abbreviation = (ref = str.match(/\\b[A-Z]+\\b/)) !== null) ? ref[0] : 0) {\n          matchedStrings.push(abbreviation);\n        }\n      }\n      formattedStr = matchedStrings.pop();\n    }\n    return formattedStr;\n  }\n\n  function UTCDate() {\n    return new Date(Date.UTC.apply(Date, arguments));\n  }\n\n  // Picker object\n  var Datetimepicker = function (element, options) {\n    var that = this;\n\n    this.element = $(element);\n\n    // add container for single page application\n    // when page switch the datetimepicker div will be removed also.\n    this.container = options.container || 'body';\n\n    this.language = options.language || this.element.data('date-language') || 'zh-cn';\n    this.language = this.language in dates ? this.language : this.language.split('-')[0]; // fr-CA fallback to fr\n    this.language = this.language in dates ? this.language : 'en';\n    this.isRTL = dates[this.language].rtl || false;\n    this.formatType = options.formatType || this.element.data('format-type') || 'standard';\n    this.format = DPGlobal.parseFormat(options.format || this.element.data('date-format') || dates[this.language].format || DPGlobal.getDefaultFormat(this.formatType, 'input'), this.formatType);\n    this.isInline = false;\n    this.isVisible = false;\n    this.isInput = this.element.is('input');\n    this.fontAwesome = options.fontAwesome || this.element.data('font-awesome') || false;\n\n    this.bootcssVer = options.bootcssVer || (this.isInput ? (this.element.is('.form-control') ? 3 : 2) : ( this.bootcssVer = this.element.is('.input-group') ? 3 : 2 ));\n\n    this.component = this.element.is('.date') ? ( this.bootcssVer === 3 ? this.element.find('.input-group-addon .glyphicon-th, .input-group-addon .glyphicon-time, .input-group-addon .glyphicon-remove, .input-group-addon .glyphicon-calendar, .input-group-addon .fa-calendar, .input-group-addon .fa-clock-o').parent() : this.element.find('.add-on .icon-th, .add-on .icon-time, .add-on .icon-calendar, .add-on .fa-calendar, .add-on .fa-clock-o').parent()) : false;\n    this.componentReset = this.element.is('.date') ? ( this.bootcssVer === 3 ? this.element.find('.input-group-addon .glyphicon-remove, .input-group-addon .fa-times').parent():this.element.find('.add-on .icon-remove, .add-on .fa-times').parent()) : false;\n    this.hasInput = this.component && this.element.find('input').length;\n    if (this.component && this.component.length === 0) {\n      this.component = false;\n    }\n    this.linkField = options.linkField || this.element.data('link-field') || false;\n    this.linkFormat = DPGlobal.parseFormat(options.linkFormat || this.element.data('link-format') || DPGlobal.getDefaultFormat(this.formatType, 'link'), this.formatType);\n    this.minuteStep = options.minuteStep || this.element.data('minute-step') || 5;\n    this.pickerPosition = options.pickerPosition || this.element.data('picker-position') || 'bottom-right';\n    this.showMeridian = options.showMeridian || this.element.data('show-meridian') || false;\n    this.initialDate = options.initialDate || new Date();\n    this.zIndex = options.zIndex || this.element.data('z-index') || undefined;\n    this.title = typeof options.title === 'undefined' ? false : options.title;\n    this.timezone = options.timezone || timeZoneAbbreviation();\n\n    this.icons = {\n      leftArrow: this.fontAwesome ? 'fa-arrow-left' : (this.bootcssVer === 3 ? 'glyphicon-arrow-left' : 'icon-arrow-left'),\n      rightArrow: this.fontAwesome ? 'fa-arrow-right' : (this.bootcssVer === 3 ? 'glyphicon-arrow-right' : 'icon-arrow-right')\n    }\n    this.icontype = this.fontAwesome ? 'fa' : 'glyphicon';\n\n    this._attachEvents();\n\n    this.clickedOutside = function (e) {\n        // Clicked outside the datetimepicker, hide it\n        if ($(e.target).closest('.datetimepicker').length === 0) {\n            that.hide();\n        }\n    }\n\n    this.formatViewType = 'datetime';\n    if ('formatViewType' in options) {\n      this.formatViewType = options.formatViewType;\n    } else if ('formatViewType' in this.element.data()) {\n      this.formatViewType = this.element.data('formatViewType');\n    }\n\n    this.minView = 0;\n    if ('minView' in options) {\n      this.minView = options.minView;\n    } else if ('minView' in this.element.data()) {\n      this.minView = this.element.data('min-view');\n    }\n    this.minView = DPGlobal.convertViewMode(this.minView);\n\n    this.maxView = DPGlobal.modes.length - 1;\n    if ('maxView' in options) {\n      this.maxView = options.maxView;\n    } else if ('maxView' in this.element.data()) {\n      this.maxView = this.element.data('max-view');\n    }\n    this.maxView = DPGlobal.convertViewMode(this.maxView);\n\n    this.wheelViewModeNavigation = false;\n    if ('wheelViewModeNavigation' in options) {\n      this.wheelViewModeNavigation = options.wheelViewModeNavigation;\n    } else if ('wheelViewModeNavigation' in this.element.data()) {\n      this.wheelViewModeNavigation = this.element.data('view-mode-wheel-navigation');\n    }\n\n    this.wheelViewModeNavigationInverseDirection = false;\n\n    if ('wheelViewModeNavigationInverseDirection' in options) {\n      this.wheelViewModeNavigationInverseDirection = options.wheelViewModeNavigationInverseDirection;\n    } else if ('wheelViewModeNavigationInverseDirection' in this.element.data()) {\n      this.wheelViewModeNavigationInverseDirection = this.element.data('view-mode-wheel-navigation-inverse-dir');\n    }\n\n    this.wheelViewModeNavigationDelay = 100;\n    if ('wheelViewModeNavigationDelay' in options) {\n      this.wheelViewModeNavigationDelay = options.wheelViewModeNavigationDelay;\n    } else if ('wheelViewModeNavigationDelay' in this.element.data()) {\n      this.wheelViewModeNavigationDelay = this.element.data('view-mode-wheel-navigation-delay');\n    }\n\n    this.startViewMode = 2;\n    if ('startView' in options) {\n      this.startViewMode = options.startView;\n    } else if ('startView' in this.element.data()) {\n      this.startViewMode = this.element.data('start-view');\n    }\n    this.startViewMode = DPGlobal.convertViewMode(this.startViewMode);\n    this.viewMode = this.startViewMode;\n\n    this.viewSelect = this.minView;\n    if ('viewSelect' in options) {\n      this.viewSelect = options.viewSelect;\n    } else if ('viewSelect' in this.element.data()) {\n      this.viewSelect = this.element.data('view-select');\n    }\n    this.viewSelect = DPGlobal.convertViewMode(this.viewSelect);\n\n    this.forceParse = true;\n    if ('forceParse' in options) {\n      this.forceParse = options.forceParse;\n    } else if ('dateForceParse' in this.element.data()) {\n      this.forceParse = this.element.data('date-force-parse');\n    }\n    var template = this.bootcssVer === 3 ? DPGlobal.templateV3 : DPGlobal.template;\n    while (template.indexOf('{iconType}') !== -1) {\n      template = template.replace('{iconType}', this.icontype);\n    }\n    while (template.indexOf('{leftArrow}') !== -1) {\n      template = template.replace('{leftArrow}', this.icons.leftArrow);\n    }\n    while (template.indexOf('{rightArrow}') !== -1) {\n      template = template.replace('{rightArrow}', this.icons.rightArrow);\n    }\n    this.picker = $(template)\n      .appendTo(this.isInline ? this.element : this.container) // 'body')\n      .on({\n        click:     $.proxy(this.click, this),\n        mousedown: $.proxy(this.mousedown, this)\n      });\n\n    if (this.wheelViewModeNavigation) {\n      if ($.fn.mousewheel) {\n        this.picker.on({mousewheel: $.proxy(this.mousewheel, this)});\n      } else {\n        console.log('Mouse Wheel event is not supported. Please include the jQuery Mouse Wheel plugin before enabling this option');\n      }\n    }\n\n    if (this.isInline) {\n      this.picker.addClass('datetimepicker-inline');\n    } else {\n      this.picker.addClass('datetimepicker-dropdown-' + this.pickerPosition + ' dropdown-menu');\n    }\n    if (this.isRTL) {\n      this.picker.addClass('datetimepicker-rtl');\n      var selector = this.bootcssVer === 3 ? '.prev span, .next span' : '.prev i, .next i';\n      this.picker.find(selector).toggleClass(this.icons.leftArrow + ' ' + this.icons.rightArrow);\n    }\n\n    $(document).on('mousedown touchend', this.clickedOutside);\n\n    this.autoclose = false;\n    if ('autoclose' in options) {\n      this.autoclose = options.autoclose;\n    } else if ('dateAutoclose' in this.element.data()) {\n      this.autoclose = this.element.data('date-autoclose');\n    }\n\n    this.keyboardNavigation = true;\n    if ('keyboardNavigation' in options) {\n      this.keyboardNavigation = options.keyboardNavigation;\n    } else if ('dateKeyboardNavigation' in this.element.data()) {\n      this.keyboardNavigation = this.element.data('date-keyboard-navigation');\n    }\n\n    this.todayBtn = (options.todayBtn || this.element.data('date-today-btn') || false);\n    this.clearBtn = (options.clearBtn || this.element.data('date-clear-btn') || false);\n    this.todayHighlight = (options.todayHighlight || this.element.data('date-today-highlight') || false);\n\n    this.weekStart = 0;\n    if (typeof options.weekStart !== 'undefined') {\n      this.weekStart = options.weekStart;\n    } else if (typeof this.element.data('date-weekstart') !== 'undefined') {\n      this.weekStart = this.element.data('date-weekstart');\n    } else if (typeof dates[this.language].weekStart !== 'undefined') {\n      this.weekStart = dates[this.language].weekStart;\n    }\n    this.weekStart = this.weekStart % 7;\n    this.weekEnd = ((this.weekStart + 6) % 7);\n    this.onRenderDay = function (date) {\n      var render = (options.onRenderDay || function () { return []; })(date);\n      if (typeof render === 'string') {\n        render = [render];\n      }\n      var res = ['day'];\n      return res.concat((render ? render : []));\n    };\n    this.onRenderHour = function (date) {\n      var render = (options.onRenderHour || function () { return []; })(date);\n      var res = ['hour'];\n      if (typeof render === 'string') {\n        render = [render];\n      }\n      return res.concat((render ? render : []));\n    };\n    this.onRenderMinute = function (date) {\n      var render = (options.onRenderMinute || function () { return []; })(date);\n      var res = ['minute'];\n      if (typeof render === 'string') {\n        render = [render];\n      }\n      if (date < this.startDate || date > this.endDate) {\n        res.push('disabled');\n      } else if (Math.floor(this.date.getUTCMinutes() / this.minuteStep) === Math.floor(date.getUTCMinutes() / this.minuteStep)) {\n        res.push('active');\n      }\n      return res.concat((render ? render : []));\n    };\n    this.onRenderYear = function (date) {\n      var render = (options.onRenderYear || function () { return []; })(date);\n      var res = ['year'];\n      if (typeof render === 'string') {\n        render = [render];\n      }\n      if (this.date.getUTCFullYear() === date.getUTCFullYear()) {\n        res.push('active');\n      }\n      var currentYear = date.getUTCFullYear();\n      var endYear = this.endDate.getUTCFullYear();\n      if (date < this.startDate || currentYear > endYear) {\n        res.push('disabled');\n      }\n      return res.concat((render ? render : []));\n    }\n    this.onRenderMonth = function (date) {\n      var render = (options.onRenderMonth || function () { return []; })(date);\n      var res = ['month'];\n      if (typeof render === 'string') {\n        render = [render];\n      }\n      return res.concat((render ? render : []));\n    }\n    this.startDate = new Date(-8639968443048000);\n    this.endDate = new Date(8639968443048000);\n    this.datesDisabled = [];\n    this.daysOfWeekDisabled = [];\n    this.setStartDate(options.startDate || this.element.data('date-startdate'));\n    this.setEndDate(options.endDate || this.element.data('date-enddate'));\n    this.setDatesDisabled(options.datesDisabled || this.element.data('date-dates-disabled'));\n    this.setDaysOfWeekDisabled(options.daysOfWeekDisabled || this.element.data('date-days-of-week-disabled'));\n    this.setMinutesDisabled(options.minutesDisabled || this.element.data('date-minute-disabled'));\n    this.setHoursDisabled(options.hoursDisabled || this.element.data('date-hour-disabled'));\n    this.fillDow();\n    this.fillMonths();\n    this.update();\n    this.showMode();\n\n    if (this.isInline) {\n      this.show();\n    }\n  };\n\n  Datetimepicker.prototype = {\n    constructor: Datetimepicker,\n\n    _events:       [],\n    _attachEvents: function () {\n      this._detachEvents();\n      if (this.isInput) { // single input\n        this._events = [\n          [this.element, {\n            focus:   $.proxy(this.show, this),\n            keyup:   $.proxy(this.update, this),\n            keydown: $.proxy(this.keydown, this)\n          }]\n        ];\n      }\n      else if (this.component && this.hasInput) { // component: input + button\n        this._events = [\n          // For components that are not readonly, allow keyboard nav\n          [this.element.find('input'), {\n            focus:   $.proxy(this.show, this),\n            keyup:   $.proxy(this.update, this),\n            keydown: $.proxy(this.keydown, this)\n          }],\n          [this.component, {\n            click: $.proxy(this.show, this)\n          }]\n        ];\n        if (this.componentReset) {\n          this._events.push([\n            this.componentReset,\n            {click: $.proxy(this.reset, this)}\n          ]);\n        }\n      }\n      else if (this.element.is('div')) {  // inline datetimepicker\n        this.isInline = true;\n      }\n      else {\n        this._events = [\n          [this.element, {\n            click: $.proxy(this.show, this)\n          }]\n        ];\n      }\n      for (var i = 0, el, ev; i < this._events.length; i++) {\n        el = this._events[i][0];\n        ev = this._events[i][1];\n        el.on(ev);\n      }\n    },\n\n    _detachEvents: function () {\n      for (var i = 0, el, ev; i < this._events.length; i++) {\n        el = this._events[i][0];\n        ev = this._events[i][1];\n        el.off(ev);\n      }\n      this._events = [];\n    },\n\n    show: function (e) {\n      this.picker.show();\n      this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();\n      if (this.forceParse) {\n        this.update();\n      }\n      this.place();\n      $(window).on('resize', $.proxy(this.place, this));\n      if (e) {\n        e.stopPropagation();\n        e.preventDefault();\n      }\n      this.isVisible = true;\n      this.element.trigger({\n        type: 'show',\n        date: this.date\n      });\n    },\n\n    hide: function () {\n      if (!this.isVisible) return;\n      if (this.isInline) return;\n      this.picker.hide();\n      $(window).off('resize', this.place);\n      this.viewMode = this.startViewMode;\n      this.showMode();\n      if (!this.isInput) {\n        $(document).off('mousedown', this.hide);\n      }\n\n      if (\n        this.forceParse &&\n          (\n            this.isInput && this.element.val() ||\n              this.hasInput && this.element.find('input').val()\n            )\n        )\n        this.setValue();\n      this.isVisible = false;\n      this.element.trigger({\n        type: 'hide',\n        date: this.date\n      });\n    },\n\n    remove: function () {\n      this._detachEvents();\n      $(document).off('mousedown', this.clickedOutside);\n      this.picker.remove();\n      delete this.picker;\n      delete this.element.data().datetimepicker;\n    },\n\n    getDate: function () {\n      var d = this.getUTCDate();\n      if (d === null) {\n        return null;\n      }\n      return new Date(d.getTime() + (d.getTimezoneOffset() * 60000));\n    },\n\n    getUTCDate: function () {\n      return this.date;\n    },\n\n    getInitialDate: function () {\n      return this.initialDate\n    },\n\n    setInitialDate: function (initialDate) {\n      this.initialDate = initialDate;\n    },\n\n    setDate: function (d) {\n      this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset() * 60000)));\n    },\n\n    setUTCDate: function (d) {\n      if (d >= this.startDate && d <= this.endDate) {\n        this.date = d;\n        this.setValue();\n        this.viewDate = this.date;\n        this.fill();\n      } else {\n        this.element.trigger({\n          type:      'outOfRange',\n          date:      d,\n          startDate: this.startDate,\n          endDate:   this.endDate\n        });\n      }\n    },\n\n    setFormat: function (format) {\n      this.format = DPGlobal.parseFormat(format, this.formatType);\n      var element;\n      if (this.isInput) {\n        element = this.element;\n      } else if (this.component) {\n        element = this.element.find('input');\n      }\n      if (element && element.val()) {\n        this.setValue();\n      }\n    },\n\n    setValue: function () {\n      var formatted = this.getFormattedDate();\n      if (!this.isInput) {\n        if (this.component) {\n          this.element.find('input').val(formatted);\n        }\n        this.element.data('date', formatted);\n      } else {\n        this.element.val(formatted);\n      }\n      if (this.linkField) {\n        $('#' + this.linkField).val(this.getFormattedDate(this.linkFormat));\n      }\n    },\n\n    getFormattedDate: function (format) {\n      format = format || this.format;\n      return DPGlobal.formatDate(this.date, format, this.language, this.formatType, this.timezone);\n    },\n\n    setStartDate: function (startDate) {\n      this.startDate = startDate || this.startDate;\n      if (this.startDate.valueOf() !== 8639968443048000) {\n        this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language, this.formatType, this.timezone);\n      }\n      this.update();\n      this.updateNavArrows();\n    },\n\n    setEndDate: function (endDate) {\n      this.endDate = endDate || this.endDate;\n      if (this.endDate.valueOf() !== 8639968443048000) {\n        this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language, this.formatType, this.timezone);\n      }\n      this.update();\n      this.updateNavArrows();\n    },\n\n    setDatesDisabled: function (datesDisabled) {\n      this.datesDisabled = datesDisabled || [];\n      if (!$.isArray(this.datesDisabled)) {\n        this.datesDisabled = this.datesDisabled.split(/,\\s*/);\n      }\n      var mThis = this;\n      this.datesDisabled = $.map(this.datesDisabled, function (d) {\n        return DPGlobal.parseDate(d, mThis.format, mThis.language, mThis.formatType, mThis.timezone).toDateString();\n      });\n      this.update();\n      this.updateNavArrows();\n    },\n\n    setTitle: function (selector, value) {\n      return this.picker.find(selector)\n        .find('th:eq(1)')\n        .text(this.title === false ? value : this.title);\n    },\n\n    setDaysOfWeekDisabled: function (daysOfWeekDisabled) {\n      this.daysOfWeekDisabled = daysOfWeekDisabled || [];\n      if (!$.isArray(this.daysOfWeekDisabled)) {\n        this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\\s*/);\n      }\n      this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {\n        return parseInt(d, 10);\n      });\n      this.update();\n      this.updateNavArrows();\n    },\n\n    setMinutesDisabled: function (minutesDisabled) {\n      this.minutesDisabled = minutesDisabled || [];\n      if (!$.isArray(this.minutesDisabled)) {\n        this.minutesDisabled = this.minutesDisabled.split(/,\\s*/);\n      }\n      this.minutesDisabled = $.map(this.minutesDisabled, function (d) {\n        return parseInt(d, 10);\n      });\n      this.update();\n      this.updateNavArrows();\n    },\n\n    setHoursDisabled: function (hoursDisabled) {\n      this.hoursDisabled = hoursDisabled || [];\n      if (!$.isArray(this.hoursDisabled)) {\n        this.hoursDisabled = this.hoursDisabled.split(/,\\s*/);\n      }\n      this.hoursDisabled = $.map(this.hoursDisabled, function (d) {\n        return parseInt(d, 10);\n      });\n      this.update();\n      this.updateNavArrows();\n    },\n\n    place: function () {\n      if (this.isInline) return;\n\n      if (!this.zIndex) {\n        var index_highest = 0;\n        $('div').each(function () {\n          var index_current = parseInt($(this).css('zIndex'), 10);\n          if (index_current > index_highest) {\n            index_highest = index_current;\n          }\n        });\n        this.zIndex = index_highest + 10;\n      }\n\n      var offset, top, left, containerOffset;\n      if (this.container instanceof $) {\n        containerOffset = this.container.offset();\n      } else {\n        containerOffset = $(this.container).offset();\n      }\n\n      if (this.component) {\n        offset = this.component.offset();\n        left = offset.left;\n        if (this.pickerPosition === 'bottom-left' || this.pickerPosition === 'top-left') {\n          left += this.component.outerWidth() - this.picker.outerWidth();\n        }\n      } else {\n        offset = this.element.offset();\n        left = offset.left;\n        if (this.pickerPosition === 'bottom-left' || this.pickerPosition === 'top-left') {\n          left += this.element.outerWidth() - this.picker.outerWidth();\n        }\n      }\n\n      var bodyWidth = document.body.clientWidth || window.innerWidth;\n      if (left + 220 > bodyWidth) {\n        left = bodyWidth - 220;\n      }\n\n      if (this.pickerPosition === 'top-left' || this.pickerPosition === 'top-right') {\n        top = offset.top - this.picker.outerHeight();\n      } else {\n        top = offset.top + this.height;\n      }\n\n      top = top - containerOffset.top;\n      left = left - containerOffset.left;\n\n      this.picker.css({\n        top:    top,\n        left:   left,\n        zIndex: this.zIndex\n      });\n    },\n\n    hour_minute: \"^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]\",\n\n    update: function () {\n      var date, fromArgs = false;\n      if (arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {\n        date = arguments[0];\n        fromArgs = true;\n      } else {\n        date = (this.isInput ? this.element.val() : this.element.find('input').val()) || this.element.data('date') || this.initialDate;\n        if (typeof date === 'string') {\n          date = date.replace(/^\\s+|\\s+$/g,'');\n        }\n      }\n\n      if (!date) {\n        date = new Date();\n        fromArgs = false;\n      }\n\n      if (typeof date === \"string\") {\n        if (new RegExp(this.hour_minute).test(date) || new RegExp(this.hour_minute + \":[0-5][0-9]\").test(date)) {\n          date = this.getDate()\n        }\n      }\n\n      this.date = DPGlobal.parseDate(date, this.format, this.language, this.formatType, this.timezone);\n\n      if (fromArgs) this.setValue();\n\n      if (this.date < this.startDate) {\n        this.viewDate = new Date(this.startDate);\n      } else if (this.date > this.endDate) {\n        this.viewDate = new Date(this.endDate);\n      } else {\n        this.viewDate = new Date(this.date);\n      }\n      this.fill();\n    },\n\n    fillDow: function () {\n      var dowCnt = this.weekStart,\n        html = '<tr>';\n      while (dowCnt < this.weekStart + 7) {\n        html += '<th class=\"dow\">' + dates[this.language].daysMin[(dowCnt++) % 7] + '</th>';\n      }\n      html += '</tr>';\n      this.picker.find('.datetimepicker-days thead').append(html);\n    },\n\n    fillMonths: function () {\n      var html = '';\n      var d = new Date(this.viewDate);\n      for (var i = 0; i < 12; i++) {\n        d.setUTCMonth(i);\n        var classes = this.onRenderMonth(d);\n        html += '<span class=\"' + classes.join(' ') + '\">' + dates[this.language].monthsShort[i] + '</span>';\n      }\n      this.picker.find('.datetimepicker-months td').html(html);\n    },\n\n    fill: function () {\n      if (!this.date || !this.viewDate) {\n        return;\n      }\n      var d = new Date(this.viewDate),\n        year = d.getUTCFullYear(),\n        month = d.getUTCMonth(),\n        dayMonth = d.getUTCDate(),\n        hours = d.getUTCHours(),\n        startYear = this.startDate.getUTCFullYear(),\n        startMonth = this.startDate.getUTCMonth(),\n        endYear = this.endDate.getUTCFullYear(),\n        endMonth = this.endDate.getUTCMonth() + 1,\n        currentDate = (new UTCDate(this.date.getUTCFullYear(), this.date.getUTCMonth(), this.date.getUTCDate())).valueOf(),\n        today = new Date();\n      this.setTitle('.datetimepicker-days', dates[this.language].months[month] + ' ' + year)\n      if (this.formatViewType === 'time') {\n        var formatted = this.getFormattedDate();\n        this.setTitle('.datetimepicker-hours', formatted);\n        this.setTitle('.datetimepicker-minutes', formatted);\n      } else {\n        this.setTitle('.datetimepicker-hours', dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);\n        this.setTitle('.datetimepicker-minutes', dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);\n      }\n      this.picker.find('tfoot th.today')\n        .text(dates[this.language].today || dates['en'].today)\n        .toggle(this.todayBtn !== false);\n      this.picker.find('tfoot th.clear')\n        .text(dates[this.language].clear || dates['en'].clear)\n        .toggle(this.clearBtn !== false);\n      this.updateNavArrows();\n      this.fillMonths();\n      var prevMonth = UTCDate(year, month - 1, 28, 0, 0, 0, 0),\n        day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());\n      prevMonth.setUTCDate(day);\n      prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7);\n      var nextMonth = new Date(prevMonth);\n      nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);\n      nextMonth = nextMonth.valueOf();\n      var html = [];\n      var classes;\n      while (prevMonth.valueOf() < nextMonth) {\n        if (prevMonth.getUTCDay() === this.weekStart) {\n          html.push('<tr>');\n        }\n        classes = this.onRenderDay(prevMonth);\n        if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() === year && prevMonth.getUTCMonth() < month)) {\n          classes.push('old');\n        } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() === year && prevMonth.getUTCMonth() > month)) {\n          classes.push('new');\n        }\n        // Compare internal UTC date with local today, not UTC today\n        if (this.todayHighlight &&\n          prevMonth.getUTCFullYear() === today.getFullYear() &&\n          prevMonth.getUTCMonth() === today.getMonth() &&\n          prevMonth.getUTCDate() === today.getDate()) {\n          classes.push('today');\n        }\n        if (prevMonth.valueOf() === currentDate) {\n          classes.push('active');\n        }\n        if ((prevMonth.valueOf() + 86400000) <= this.startDate || prevMonth.valueOf() > this.endDate ||\n          $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1 ||\n          $.inArray(prevMonth.toDateString(), this.datesDisabled) !== -1) {\n          classes.push('disabled');\n        }\n        html.push('<td class=\"' + classes.join(' ') + '\">' + prevMonth.getUTCDate() + '</td>');\n        if (prevMonth.getUTCDay() === this.weekEnd) {\n          html.push('</tr>');\n        }\n        prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);\n      }\n      this.picker.find('.datetimepicker-days tbody').empty().append(html.join(''));\n\n      html = [];\n      var txt = '', meridian = '', meridianOld = '';\n      var hoursDisabled = this.hoursDisabled || [];\n      d = new Date(this.viewDate)\n      for (var i = 0; i < 24; i++) {\n        d.setUTCHours(i);\n        classes = this.onRenderHour(d);\n        if (hoursDisabled.indexOf(i) !== -1) {\n          classes.push('disabled');\n        }\n        var actual = UTCDate(year, month, dayMonth, i);\n        // We want the previous hour for the startDate\n        if ((actual.valueOf() + 3600000) <= this.startDate || actual.valueOf() > this.endDate) {\n          classes.push('disabled');\n        } else if (hours === i) {\n          classes.push('active');\n        }\n        if (this.showMeridian && dates[this.language].meridiem.length === 2) {\n          meridian = (i < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]);\n          if (meridian !== meridianOld) {\n            if (meridianOld !== '') {\n              html.push('</fieldset>');\n            }\n            html.push('<fieldset class=\"hour\"><legend>' + meridian.toUpperCase() + '</legend>');\n          }\n          meridianOld = meridian;\n          txt = (i % 12 ? i % 12 : 12);\n          if (i < 12) {\n            classes.push('hour_am');\n          } else {\n            classes.push('hour_pm');\n          }\n          html.push('<span class=\"' + classes.join(' ') + '\">' + txt + '</span>');\n          if (i === 23) {\n            html.push('</fieldset>');\n          }\n        } else {\n          txt = i + ':00';\n          html.push('<span class=\"' + classes.join(' ') + '\">' + txt + '</span>');\n        }\n      }\n      this.picker.find('.datetimepicker-hours td').html(html.join(''));\n\n      html = [];\n      txt = '';\n      meridian = '';\n      meridianOld = '';\n      var minutesDisabled = this.minutesDisabled || [];\n      d = new Date(this.viewDate);\n      for (var i = 0; i < 60; i += this.minuteStep) {\n        if (minutesDisabled.indexOf(i) !== -1) continue;\n        d.setUTCMinutes(i);\n        d.setUTCSeconds(0);\n        classes = this.onRenderMinute(d);\n        if (this.showMeridian && dates[this.language].meridiem.length === 2) {\n          meridian = (hours < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]);\n          if (meridian !== meridianOld) {\n            if (meridianOld !== '') {\n              html.push('</fieldset>');\n            }\n            html.push('<fieldset class=\"minute\"><legend>' + meridian.toUpperCase() + '</legend>');\n          }\n          meridianOld = meridian;\n          txt = (hours % 12 ? hours % 12 : 12);\n          html.push('<span class=\"' + classes.join(' ') + '\">' + txt + ':' + (i < 10 ? '0' + i : i) + '</span>');\n          if (i === 59) {\n            html.push('</fieldset>');\n          }\n        } else {\n          txt = i + ':00';\n          html.push('<span class=\"' + classes.join(' ') + '\">' + hours + ':' + (i < 10 ? '0' + i : i) + '</span>');\n        }\n      }\n      this.picker.find('.datetimepicker-minutes td').html(html.join(''));\n\n      var currentYear = this.date.getUTCFullYear();\n      var months = this.setTitle('.datetimepicker-months', year)\n        .end()\n        .find('.month').removeClass('active');\n      if (currentYear === year) {\n        // getUTCMonths() returns 0 based, and we need to select the next one\n        // To cater bootstrap 2 we don't need to select the next one\n        months.eq(this.date.getUTCMonth()).addClass('active');\n      }\n      if (year < startYear || year > endYear) {\n        months.addClass('disabled');\n      }\n      if (year === startYear) {\n        months.slice(0, startMonth).addClass('disabled');\n      }\n      if (year === endYear) {\n        months.slice(endMonth).addClass('disabled');\n      }\n\n      html = '';\n      year = parseInt(year / 10, 10) * 10;\n      var yearCont = this.setTitle('.datetimepicker-years', year + '-' + (year + 9))\n        .end()\n        .find('td');\n      year -= 1;\n      d = new Date(this.viewDate);\n      for (var i = -1; i < 11; i++) {\n        d.setUTCFullYear(year);\n        classes = this.onRenderYear(d);\n        if (i === -1 || i === 10) {\n          classes.push(old);\n        }\n        html += '<span class=\"' + classes.join(' ') + '\">' + year + '</span>';\n        year += 1;\n      }\n      yearCont.html(html);\n      this.place();\n    },\n\n    updateNavArrows: function () {\n      var d = new Date(this.viewDate),\n        year = d.getUTCFullYear(),\n        month = d.getUTCMonth(),\n        day = d.getUTCDate(),\n        hour = d.getUTCHours();\n      switch (this.viewMode) {\n        case 0:\n          if (year <= this.startDate.getUTCFullYear()\n            && month <= this.startDate.getUTCMonth()\n            && day <= this.startDate.getUTCDate()\n            && hour <= this.startDate.getUTCHours()) {\n            this.picker.find('.prev').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.prev').css({visibility: 'visible'});\n          }\n          if (year >= this.endDate.getUTCFullYear()\n            && month >= this.endDate.getUTCMonth()\n            && day >= this.endDate.getUTCDate()\n            && hour >= this.endDate.getUTCHours()) {\n            this.picker.find('.next').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.next').css({visibility: 'visible'});\n          }\n          break;\n        case 1:\n          if (year <= this.startDate.getUTCFullYear()\n            && month <= this.startDate.getUTCMonth()\n            && day <= this.startDate.getUTCDate()) {\n            this.picker.find('.prev').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.prev').css({visibility: 'visible'});\n          }\n          if (year >= this.endDate.getUTCFullYear()\n            && month >= this.endDate.getUTCMonth()\n            && day >= this.endDate.getUTCDate()) {\n            this.picker.find('.next').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.next').css({visibility: 'visible'});\n          }\n          break;\n        case 2:\n          if (year <= this.startDate.getUTCFullYear()\n            && month <= this.startDate.getUTCMonth()) {\n            this.picker.find('.prev').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.prev').css({visibility: 'visible'});\n          }\n          if (year >= this.endDate.getUTCFullYear()\n            && month >= this.endDate.getUTCMonth()) {\n            this.picker.find('.next').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.next').css({visibility: 'visible'});\n          }\n          break;\n        case 3:\n        case 4:\n          if (year <= this.startDate.getUTCFullYear()) {\n            this.picker.find('.prev').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.prev').css({visibility: 'visible'});\n          }\n          if (year >= this.endDate.getUTCFullYear()) {\n            this.picker.find('.next').css({visibility: 'hidden'});\n          } else {\n            this.picker.find('.next').css({visibility: 'visible'});\n          }\n          break;\n      }\n    },\n\n    mousewheel: function (e) {\n\n      e.preventDefault();\n      e.stopPropagation();\n\n      if (this.wheelPause) {\n        return;\n      }\n\n      this.wheelPause = true;\n\n      var originalEvent = e.originalEvent;\n\n      var delta = originalEvent.wheelDelta;\n\n      var mode = delta > 0 ? 1 : (delta === 0) ? 0 : -1;\n\n      if (this.wheelViewModeNavigationInverseDirection) {\n        mode = -mode;\n      }\n\n      this.showMode(mode);\n\n      setTimeout($.proxy(function () {\n\n        this.wheelPause = false\n\n      }, this), this.wheelViewModeNavigationDelay);\n\n    },\n\n    click: function (e) {\n      e.stopPropagation();\n      e.preventDefault();\n      var target = $(e.target).closest('span, td, th, legend');\n      if (target.is('.' + this.icontype)) {\n        target = $(target).parent().closest('span, td, th, legend');\n      }\n      if (target.length === 1) {\n        if (target.is('.disabled')) {\n          this.element.trigger({\n            type:      'outOfRange',\n            date:      this.viewDate,\n            startDate: this.startDate,\n            endDate:   this.endDate\n          });\n          return;\n        }\n        switch (target[0].nodeName.toLowerCase()) {\n          case 'th':\n            switch (target[0].className) {\n              case 'switch':\n                this.showMode(1);\n                break;\n              case 'prev':\n              case 'next':\n                var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1);\n                switch (this.viewMode) {\n                  case 0:\n                    this.viewDate = this.moveHour(this.viewDate, dir);\n                    break;\n                  case 1:\n                    this.viewDate = this.moveDate(this.viewDate, dir);\n                    break;\n                  case 2:\n                    this.viewDate = this.moveMonth(this.viewDate, dir);\n                    break;\n                  case 3:\n                  case 4:\n                    this.viewDate = this.moveYear(this.viewDate, dir);\n                    break;\n                }\n                this.fill();\n                this.element.trigger({\n                  type:      target[0].className + ':' + this.convertViewModeText(this.viewMode),\n                  date:      this.viewDate,\n                  startDate: this.startDate,\n                  endDate:   this.endDate\n                });\n                break;\n              case 'clear':\n                this.reset();\n                if (this.autoclose) {\n                  this.hide();\n                }\n                break;\n              case 'today':\n                var date = new Date();\n                date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), 0);\n\n                // Respect startDate and endDate.\n                if (date < this.startDate) date = this.startDate;\n                else if (date > this.endDate) date = this.endDate;\n\n                this.viewMode = this.startViewMode;\n                this.showMode(0);\n                this._setDate(date);\n                this.fill();\n                if (this.autoclose) {\n                  this.hide();\n                }\n                break;\n            }\n            break;\n          case 'span':\n            if (!target.is('.disabled')) {\n              var year = this.viewDate.getUTCFullYear(),\n                month = this.viewDate.getUTCMonth(),\n                day = this.viewDate.getUTCDate(),\n                hours = this.viewDate.getUTCHours(),\n                minutes = this.viewDate.getUTCMinutes(),\n                seconds = this.viewDate.getUTCSeconds();\n\n              if (target.is('.month')) {\n                this.viewDate.setUTCDate(1);\n                month = target.parent().find('span').index(target);\n                day = this.viewDate.getUTCDate();\n                this.viewDate.setUTCMonth(month);\n                this.element.trigger({\n                  type: 'changeMonth',\n                  date: this.viewDate\n                });\n                if (this.viewSelect >= 3) {\n                  this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n                }\n              } else if (target.is('.year')) {\n                this.viewDate.setUTCDate(1);\n                year = parseInt(target.text(), 10) || 0;\n                this.viewDate.setUTCFullYear(year);\n                this.element.trigger({\n                  type: 'changeYear',\n                  date: this.viewDate\n                });\n                if (this.viewSelect >= 4) {\n                  this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n                }\n              } else if (target.is('.hour')) {\n                hours = parseInt(target.text(), 10) || 0;\n                if (target.hasClass('hour_am') || target.hasClass('hour_pm')) {\n                  if (hours === 12 && target.hasClass('hour_am')) {\n                    hours = 0;\n                  } else if (hours !== 12 && target.hasClass('hour_pm')) {\n                    hours += 12;\n                  }\n                }\n                this.viewDate.setUTCHours(hours);\n                this.element.trigger({\n                  type: 'changeHour',\n                  date: this.viewDate\n                });\n                if (this.viewSelect >= 1) {\n                  this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n                }\n              } else if (target.is('.minute')) {\n                minutes = parseInt(target.text().substr(target.text().indexOf(':') + 1), 10) || 0;\n                this.viewDate.setUTCMinutes(minutes);\n                this.element.trigger({\n                  type: 'changeMinute',\n                  date: this.viewDate\n                });\n                if (this.viewSelect >= 0) {\n                  this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n                }\n              }\n              if (this.viewMode !== 0) {\n                var oldViewMode = this.viewMode;\n                this.showMode(-1);\n                this.fill();\n                if (oldViewMode === this.viewMode && this.autoclose) {\n                  this.hide();\n                }\n              } else {\n                this.fill();\n                if (this.autoclose) {\n                  this.hide();\n                }\n              }\n            }\n            break;\n          case 'td':\n            if (target.is('.day') && !target.is('.disabled')) {\n              var day = parseInt(target.text(), 10) || 1;\n              var year = this.viewDate.getUTCFullYear(),\n                month = this.viewDate.getUTCMonth(),\n                hours = this.viewDate.getUTCHours(),\n                minutes = this.viewDate.getUTCMinutes(),\n                seconds = this.viewDate.getUTCSeconds();\n              if (target.is('.old')) {\n                if (month === 0) {\n                  month = 11;\n                  year -= 1;\n                } else {\n                  month -= 1;\n                }\n              } else if (target.is('.new')) {\n                if (month === 11) {\n                  month = 0;\n                  year += 1;\n                } else {\n                  month += 1;\n                }\n              }\n              this.viewDate.setUTCFullYear(year);\n              this.viewDate.setUTCMonth(month, day);\n              this.element.trigger({\n                type: 'changeDay',\n                date: this.viewDate\n              });\n              if (this.viewSelect >= 2) {\n                this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n              }\n            }\n            var oldViewMode = this.viewMode;\n            this.showMode(-1);\n            this.fill();\n            if (oldViewMode === this.viewMode && this.autoclose) {\n              this.hide();\n            }\n            break;\n        }\n      }\n    },\n\n    _setDate: function (date, which) {\n      if (!which || which === 'date')\n        this.date = date;\n      if (!which || which === 'view')\n        this.viewDate = date;\n      this.fill();\n      this.setValue();\n      var element;\n      if (this.isInput) {\n        element = this.element;\n      } else if (this.component) {\n        element = this.element.find('input');\n      }\n      if (element) {\n        element.change();\n      }\n      this.element.trigger({\n        type: 'changeDate',\n        date: this.getDate()\n      });\n      if(date === null)\n        this.date = this.viewDate;\n    },\n\n    moveMinute: function (date, dir) {\n      if (!dir) return date;\n      var new_date = new Date(date.valueOf());\n      //dir = dir > 0 ? 1 : -1;\n      new_date.setUTCMinutes(new_date.getUTCMinutes() + (dir * this.minuteStep));\n      return new_date;\n    },\n\n    moveHour: function (date, dir) {\n      if (!dir) return date;\n      var new_date = new Date(date.valueOf());\n      //dir = dir > 0 ? 1 : -1;\n      new_date.setUTCHours(new_date.getUTCHours() + dir);\n      return new_date;\n    },\n\n    moveDate: function (date, dir) {\n      if (!dir) return date;\n      var new_date = new Date(date.valueOf());\n      //dir = dir > 0 ? 1 : -1;\n      new_date.setUTCDate(new_date.getUTCDate() + dir);\n      return new_date;\n    },\n\n    moveMonth: function (date, dir) {\n      if (!dir) return date;\n      var new_date = new Date(date.valueOf()),\n        day = new_date.getUTCDate(),\n        month = new_date.getUTCMonth(),\n        mag = Math.abs(dir),\n        new_month, test;\n      dir = dir > 0 ? 1 : -1;\n      if (mag === 1) {\n        test = dir === -1\n          // If going back one month, make sure month is not current month\n          // (eg, Mar 31 -> Feb 31 === Feb 28, not Mar 02)\n          ? function () {\n          return new_date.getUTCMonth() === month;\n        }\n          // If going forward one month, make sure month is as expected\n          // (eg, Jan 31 -> Feb 31 === Feb 28, not Mar 02)\n          : function () {\n          return new_date.getUTCMonth() !== new_month;\n        };\n        new_month = month + dir;\n        new_date.setUTCMonth(new_month);\n        // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11\n        if (new_month < 0 || new_month > 11)\n          new_month = (new_month + 12) % 12;\n      } else {\n        // For magnitudes >1, move one month at a time...\n        for (var i = 0; i < mag; i++)\n          // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...\n          new_date = this.moveMonth(new_date, dir);\n        // ...then reset the day, keeping it in the new month\n        new_month = new_date.getUTCMonth();\n        new_date.setUTCDate(day);\n        test = function () {\n          return new_month !== new_date.getUTCMonth();\n        };\n      }\n      // Common date-resetting loop -- if date is beyond end of month, make it\n      // end of month\n      while (test()) {\n        new_date.setUTCDate(--day);\n        new_date.setUTCMonth(new_month);\n      }\n      return new_date;\n    },\n\n    moveYear: function (date, dir) {\n      return this.moveMonth(date, dir * 12);\n    },\n\n    dateWithinRange: function (date) {\n      return date >= this.startDate && date <= this.endDate;\n    },\n\n    keydown: function (e) {\n      if (this.picker.is(':not(:visible)')) {\n        if (e.keyCode === 27) // allow escape to hide and re-show picker\n          this.show();\n        return;\n      }\n      var dateChanged = false,\n        dir, newDate, newViewDate;\n      switch (e.keyCode) {\n        case 27: // escape\n          this.hide();\n          e.preventDefault();\n          break;\n        case 37: // left\n        case 39: // right\n          if (!this.keyboardNavigation) break;\n          dir = e.keyCode === 37 ? -1 : 1;\n          var viewMode = this.viewMode;\n          if (e.ctrlKey) {\n            viewMode += 2;\n          } else if (e.shiftKey) {\n            viewMode += 1;\n          }\n          if (viewMode === 4) {\n            newDate = this.moveYear(this.date, dir);\n            newViewDate = this.moveYear(this.viewDate, dir);\n          } else if (viewMode === 3) {\n            newDate = this.moveMonth(this.date, dir);\n            newViewDate = this.moveMonth(this.viewDate, dir);\n          } else if (viewMode === 2) {\n            newDate = this.moveDate(this.date, dir);\n            newViewDate = this.moveDate(this.viewDate, dir);\n          } else if (viewMode === 1) {\n            newDate = this.moveHour(this.date, dir);\n            newViewDate = this.moveHour(this.viewDate, dir);\n          } else if (viewMode === 0) {\n            newDate = this.moveMinute(this.date, dir);\n            newViewDate = this.moveMinute(this.viewDate, dir);\n          }\n          if (this.dateWithinRange(newDate)) {\n            this.date = newDate;\n            this.viewDate = newViewDate;\n            this.setValue();\n            this.update();\n            e.preventDefault();\n            dateChanged = true;\n          }\n          break;\n        case 38: // up\n        case 40: // down\n          if (!this.keyboardNavigation) break;\n          dir = e.keyCode === 38 ? -1 : 1;\n          viewMode = this.viewMode;\n          if (e.ctrlKey) {\n            viewMode += 2;\n          } else if (e.shiftKey) {\n            viewMode += 1;\n          }\n          if (viewMode === 4) {\n            newDate = this.moveYear(this.date, dir);\n            newViewDate = this.moveYear(this.viewDate, dir);\n          } else if (viewMode === 3) {\n            newDate = this.moveMonth(this.date, dir);\n            newViewDate = this.moveMonth(this.viewDate, dir);\n          } else if (viewMode === 2) {\n            newDate = this.moveDate(this.date, dir * 7);\n            newViewDate = this.moveDate(this.viewDate, dir * 7);\n          } else if (viewMode === 1) {\n            if (this.showMeridian) {\n              newDate = this.moveHour(this.date, dir * 6);\n              newViewDate = this.moveHour(this.viewDate, dir * 6);\n            } else {\n              newDate = this.moveHour(this.date, dir * 4);\n              newViewDate = this.moveHour(this.viewDate, dir * 4);\n            }\n          } else if (viewMode === 0) {\n            newDate = this.moveMinute(this.date, dir * 4);\n            newViewDate = this.moveMinute(this.viewDate, dir * 4);\n          }\n          if (this.dateWithinRange(newDate)) {\n            this.date = newDate;\n            this.viewDate = newViewDate;\n            this.setValue();\n            this.update();\n            e.preventDefault();\n            dateChanged = true;\n          }\n          break;\n        case 13: // enter\n          if (this.viewMode !== 0) {\n            var oldViewMode = this.viewMode;\n            this.showMode(-1);\n            this.fill();\n            if (oldViewMode === this.viewMode && this.autoclose) {\n              this.hide();\n            }\n          } else {\n            this.fill();\n            if (this.autoclose) {\n              this.hide();\n            }\n          }\n          e.preventDefault();\n          break;\n        case 9: // tab\n          this.hide();\n          break;\n      }\n      if (dateChanged) {\n        var element;\n        if (this.isInput) {\n          element = this.element;\n        } else if (this.component) {\n          element = this.element.find('input');\n        }\n        if (element) {\n          element.change();\n        }\n        this.element.trigger({\n          type: 'changeDate',\n          date: this.getDate()\n        });\n      }\n    },\n\n    showMode: function (dir) {\n      if (dir) {\n        var newViewMode = Math.max(0, Math.min(DPGlobal.modes.length - 1, this.viewMode + dir));\n        if (newViewMode >= this.minView && newViewMode <= this.maxView) {\n          this.element.trigger({\n            type:        'changeMode',\n            date:        this.viewDate,\n            oldViewMode: this.viewMode,\n            newViewMode: newViewMode\n          });\n\n          this.viewMode = newViewMode;\n        }\n      }\n      /*\n       vitalets: fixing bug of very special conditions:\n       jquery 1.7.1 + webkit + show inline datetimepicker in bootstrap popover.\n       Method show() does not set display css correctly and datetimepicker is not shown.\n       Changed to .css('display', 'block') solve the problem.\n       See https://github.com/vitalets/x-editable/issues/37\n\n       In jquery 1.7.2+ everything works fine.\n       */\n      //this.picker.find('>div').hide().filter('.datetimepicker-'+DPGlobal.modes[this.viewMode].clsName).show();\n      this.picker.find('>div').hide().filter('.datetimepicker-' + DPGlobal.modes[this.viewMode].clsName).css('display', 'block');\n      this.updateNavArrows();\n    },\n\n    reset: function () {\n      this._setDate(null, 'date');\n    },\n\n    convertViewModeText:  function (viewMode) {\n      switch (viewMode) {\n        case 4:\n          return 'decade';\n        case 3:\n          return 'year';\n        case 2:\n          return 'month';\n        case 1:\n          return 'day';\n        case 0:\n          return 'hour';\n      }\n    }\n  };\n\n  var old = $.fn.datetimepicker;\n  $.fn.datetimepicker = function (option) {\n    var args = Array.apply(null, arguments);\n    args.shift();\n    var internal_return;\n    this.each(function () {\n      var $this = $(this),\n        data = $this.data('datetimepicker'),\n        options = typeof option === 'object' && option;\n      if (!data) {\n        $this.data('datetimepicker', (data = new Datetimepicker(this, $.extend({}, $.fn.datetimepicker.defaults, options))));\n      }\n      if (typeof option === 'string' && typeof data[option] === 'function') {\n        internal_return = data[option].apply(data, args);\n        if (internal_return !== undefined) {\n          return false;\n        }\n      }\n    });\n    if (internal_return !== undefined)\n      return internal_return;\n    else\n      return this;\n  };\n\n  $.fn.datetimepicker.defaults = {\n  };\n  $.fn.datetimepicker.Constructor = Datetimepicker;\n  var dates = $.fn.datetimepicker.dates = {\n  'zh-cn': {\n      days:        [\"星期日\", \"星期一\", \"星期二\", \"星期三\", \"星期四\", \"星期五\", \"星期六\", \"星期日\"],\n      daysShort:   [\"周日\", \"周一\", \"周二\", \"周三\", \"周四\", \"周五\", \"周六\", \"周日\"],\n      daysMin:     [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\", \"日\"],\n      months:      [\"一月\", \"二月\", \"三月\", \"四月\", \"五月\", \"六月\", \"七月\", \"八月\", \"九月\", \"十月\", \"十一月\", \"十二月\"],\n      monthsShort: [\"一月\", \"二月\", \"三月\", \"四月\", \"五月\", \"六月\", \"七月\", \"八月\", \"九月\", \"十月\", \"十一月\", \"十二月\"],\n      meridiem:    [\"上午\", \"下午\"],\n      suffix:      [\"st\", \"nd\", \"rd\", \"th\"],\n      today:       \"今天\",\n      clear:       \"清除\"\n    },\n    en: {\n      days:        ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],\n      daysShort:   ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],\n      daysMin:     ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],\n      months:      ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n      monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n      meridiem:    ['am', 'pm'],\n      suffix:      ['st', 'nd', 'rd', 'th'],\n      today:       'Today',\n      clear:       'Clear'\n    }\n  };\n\n  var DPGlobal = {\n    modes:            [\n      {\n        clsName: 'minutes',\n        navFnc:  'Hours',\n        navStep: 1\n      },\n      {\n        clsName: 'hours',\n        navFnc:  'Date',\n        navStep: 1\n      },\n      {\n        clsName: 'days',\n        navFnc:  'Month',\n        navStep: 1\n      },\n      {\n        clsName: 'months',\n        navFnc:  'FullYear',\n        navStep: 1\n      },\n      {\n        clsName: 'years',\n        navFnc:  'FullYear',\n        navStep: 10\n      }\n    ],\n    isLeapYear:       function (year) {\n      return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))\n    },\n    getDaysInMonth:   function (year, month) {\n      return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]\n    },\n    getDefaultFormat: function (type, field) {\n      if (type === 'standard') {\n        if (field === 'input')\n          return 'yyyy-mm-dd hh:ii';\n        else\n          return 'yyyy-mm-dd hh:ii:ss';\n      } else if (type === 'php') {\n        if (field === 'input')\n          return 'Y-m-d H:i';\n        else\n          return 'Y-m-d H:i:s';\n      } else {\n        throw new Error('Invalid format type.');\n      }\n    },\n    validParts: function (type) {\n      if (type === 'standard') {\n        return /t|hh?|HH?|p|P|z|Z|ii?|ss?|dd?|DD?|mm?|MM?|yy(?:yy)?/g;\n      } else if (type === 'php') {\n        return /[dDjlNwzFmMnStyYaABgGhHis]/g;\n      } else {\n        throw new Error('Invalid format type.');\n      }\n    },\n    nonpunctuation: /[^ -\\/:-@\\[-`{-~\\t\\n\\rTZ]+/g,\n    parseFormat: function (format, type) {\n      // IE treats \\0 as a string end in inputs (truncating the value),\n      // so it's a bad format delimiter, anyway\n      var separators = format.replace(this.validParts(type), '\\0').split('\\0'),\n        parts = format.match(this.validParts(type));\n      if (!separators || !separators.length || !parts || parts.length === 0) {\n        throw new Error('Invalid date format.');\n      }\n      return {separators: separators, parts: parts};\n    },\n    parseDate: function (date, format, language, type, timezone) {\n      if (date instanceof Date) {\n        var dateUTC = new Date(date.valueOf() - date.getTimezoneOffset() * 60000);\n        dateUTC.setMilliseconds(0);\n        return dateUTC;\n      }\n      if (/^\\d{4}\\-\\d{1,2}\\-\\d{1,2}$/.test(date)) {\n        format = this.parseFormat('yyyy-mm-dd', type);\n      }\n      if (/^\\d{4}\\-\\d{1,2}\\-\\d{1,2}[T ]\\d{1,2}\\:\\d{1,2}$/.test(date)) {\n        format = this.parseFormat('yyyy-mm-dd hh:ii', type);\n      }\n      if (/^\\d{4}\\-\\d{1,2}\\-\\d{1,2}[T ]\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}[Z]{0,1}$/.test(date)) {\n        format = this.parseFormat('yyyy-mm-dd hh:ii:ss', type);\n      }\n      if (/^[-+]\\d+[dmwy]([\\s,]+[-+]\\d+[dmwy])*$/.test(date)) {\n        var part_re = /([-+]\\d+)([dmwy])/,\n          parts = date.match(/([-+]\\d+)([dmwy])/g),\n          part, dir;\n        date = new Date();\n        for (var i = 0; i < parts.length; i++) {\n          part = part_re.exec(parts[i]);\n          dir = parseInt(part[1]);\n          switch (part[2]) {\n            case 'd':\n              date.setUTCDate(date.getUTCDate() + dir);\n              break;\n            case 'm':\n              date = Datetimepicker.prototype.moveMonth.call(Datetimepicker.prototype, date, dir);\n              break;\n            case 'w':\n              date.setUTCDate(date.getUTCDate() + dir * 7);\n              break;\n            case 'y':\n              date = Datetimepicker.prototype.moveYear.call(Datetimepicker.prototype, date, dir);\n              break;\n          }\n        }\n        return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), 0);\n      }\n      var parts = date && date.toString().match(this.nonpunctuation) || [],\n        date = new Date(0, 0, 0, 0, 0, 0, 0),\n        parsed = {},\n        setters_order = ['hh', 'h', 'ii', 'i', 'ss', 's', 'yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'D', 'DD', 'd', 'dd', 'H', 'HH', 'p', 'P', 'z', 'Z'],\n        setters_map = {\n          hh:   function (d, v) {\n            return d.setUTCHours(v);\n          },\n          h:    function (d, v) {\n            return d.setUTCHours(v);\n          },\n          HH:   function (d, v) {\n            return d.setUTCHours(v === 12 ? 0 : v);\n          },\n          H:    function (d, v) {\n            return d.setUTCHours(v === 12 ? 0 : v);\n          },\n          ii:   function (d, v) {\n            return d.setUTCMinutes(v);\n          },\n          i:    function (d, v) {\n            return d.setUTCMinutes(v);\n          },\n          ss:   function (d, v) {\n            return d.setUTCSeconds(v);\n          },\n          s:    function (d, v) {\n            return d.setUTCSeconds(v);\n          },\n          yyyy: function (d, v) {\n            return d.setUTCFullYear(v);\n          },\n          yy:   function (d, v) {\n            return d.setUTCFullYear(2000 + v);\n          },\n          m:    function (d, v) {\n            v -= 1;\n            while (v < 0) v += 12;\n            v %= 12;\n            d.setUTCMonth(v);\n            while (d.getUTCMonth() !== v)\n              if (isNaN(d.getUTCMonth()))\n                return d;\n              else\n                d.setUTCDate(d.getUTCDate() - 1);\n            return d;\n          },\n          d:    function (d, v) {\n            return d.setUTCDate(v);\n          },\n          p:    function (d, v) {\n            return d.setUTCHours(v === 1 ? d.getUTCHours() + 12 : d.getUTCHours());\n          },\n          z:    function () {\n            return timezone\n          }\n        },\n        val, filtered, part;\n      setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];\n      setters_map['dd'] = setters_map['d'];\n      setters_map['P'] = setters_map['p'];\n      setters_map['Z'] = setters_map['z'];\n      date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());\n      if (parts.length === format.parts.length) {\n        for (var i = 0, cnt = format.parts.length; i < cnt; i++) {\n          val = parseInt(parts[i], 10);\n          part = format.parts[i];\n          if (isNaN(val)) {\n            switch (part) {\n              case 'MM':\n                filtered = $(dates[language].months).filter(function () {\n                  var m = this.slice(0, parts[i].length),\n                    p = parts[i].slice(0, m.length);\n                  return m === p;\n                });\n                val = $.inArray(filtered[0], dates[language].months) + 1;\n                break;\n              case 'M':\n                filtered = $(dates[language].monthsShort).filter(function () {\n                  var m = this.slice(0, parts[i].length),\n                    p = parts[i].slice(0, m.length);\n                  return m.toLowerCase() === p.toLowerCase();\n                });\n                val = $.inArray(filtered[0], dates[language].monthsShort) + 1;\n                break;\n              case 'p':\n              case 'P':\n                val = $.inArray(parts[i].toLowerCase(), dates[language].meridiem);\n                break;\n              case 'z':\n              case 'Z':\n                timezone;\n                break;\n\n            }\n          }\n          parsed[part] = val;\n        }\n        for (var i = 0, s; i < setters_order.length; i++) {\n          s = setters_order[i];\n          if (s in parsed && !isNaN(parsed[s]))\n            setters_map[s](date, parsed[s])\n        }\n      }\n      return date;\n    },\n    formatDate:       function (date, format, language, type, timezone) {\n      if (date === null) {\n        return '';\n      }\n      var val;\n      if (type === 'standard') {\n        val = {\n          t:    date.getTime(),\n          // year\n          yy:   date.getUTCFullYear().toString().substring(2),\n          yyyy: date.getUTCFullYear(),\n          // month\n          m:    date.getUTCMonth() + 1,\n          M:    dates[language].monthsShort[date.getUTCMonth()],\n          MM:   dates[language].months[date.getUTCMonth()],\n          // day\n          d:    date.getUTCDate(),\n          D:    dates[language].daysShort[date.getUTCDay()],\n          DD:   dates[language].days[date.getUTCDay()],\n          p:    (dates[language].meridiem.length === 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''),\n          // hour\n          h:    date.getUTCHours(),\n          // minute\n          i:    date.getUTCMinutes(),\n          // second\n          s:    date.getUTCSeconds(),\n          // timezone\n          z:    timezone\n        };\n\n        if (dates[language].meridiem.length === 2) {\n          val.H = (val.h % 12 === 0 ? 12 : val.h % 12);\n        }\n        else {\n          val.H = val.h;\n        }\n        val.HH = (val.H < 10 ? '0' : '') + val.H;\n        val.P = val.p.toUpperCase();\n        val.Z = val.z;\n        val.hh = (val.h < 10 ? '0' : '') + val.h;\n        val.ii = (val.i < 10 ? '0' : '') + val.i;\n        val.ss = (val.s < 10 ? '0' : '') + val.s;\n        val.dd = (val.d < 10 ? '0' : '') + val.d;\n        val.mm = (val.m < 10 ? '0' : '') + val.m;\n      } else if (type === 'php') {\n        // php format\n        val = {\n          // year\n          y: date.getUTCFullYear().toString().substring(2),\n          Y: date.getUTCFullYear(),\n          // month\n          F: dates[language].months[date.getUTCMonth()],\n          M: dates[language].monthsShort[date.getUTCMonth()],\n          n: date.getUTCMonth() + 1,\n          t: DPGlobal.getDaysInMonth(date.getUTCFullYear(), date.getUTCMonth()),\n          // day\n          j: date.getUTCDate(),\n          l: dates[language].days[date.getUTCDay()],\n          D: dates[language].daysShort[date.getUTCDay()],\n          w: date.getUTCDay(), // 0 -> 6\n          N: (date.getUTCDay() === 0 ? 7 : date.getUTCDay()),       // 1 -> 7\n          S: (date.getUTCDate() % 10 <= dates[language].suffix.length ? dates[language].suffix[date.getUTCDate() % 10 - 1] : ''),\n          // hour\n          a: (dates[language].meridiem.length === 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''),\n          g: (date.getUTCHours() % 12 === 0 ? 12 : date.getUTCHours() % 12),\n          G: date.getUTCHours(),\n          // minute\n          i: date.getUTCMinutes(),\n          // second\n          s: date.getUTCSeconds()\n        };\n        val.m = (val.n < 10 ? '0' : '') + val.n;\n        val.d = (val.j < 10 ? '0' : '') + val.j;\n        val.A = val.a.toString().toUpperCase();\n        val.h = (val.g < 10 ? '0' : '') + val.g;\n        val.H = (val.G < 10 ? '0' : '') + val.G;\n        val.i = (val.i < 10 ? '0' : '') + val.i;\n        val.s = (val.s < 10 ? '0' : '') + val.s;\n      } else {\n        throw new Error('Invalid format type.');\n      }\n      var date = [],\n        seps = $.extend([], format.separators);\n      for (var i = 0, cnt = format.parts.length; i < cnt; i++) {\n        if (seps.length) {\n          date.push(seps.shift());\n        }\n        date.push(val[format.parts[i]]);\n      }\n      if (seps.length) {\n        date.push(seps.shift());\n      }\n      return date.join('');\n    },\n    convertViewMode:  function (viewMode) {\n      switch (viewMode) {\n        case 4:\n        case 'decade':\n          viewMode = 4;\n          break;\n        case 3:\n        case 'year':\n          viewMode = 3;\n          break;\n        case 2:\n        case 'month':\n          viewMode = 2;\n          break;\n        case 1:\n        case 'day':\n          viewMode = 1;\n          break;\n        case 0:\n        case 'hour':\n          viewMode = 0;\n          break;\n      }\n\n      return viewMode;\n    },\n    headTemplate: '<thead>' +\n                '<tr>' +\n                '<th class=\"prev\"><i class=\"{iconType} {leftArrow}\"/></th>' +\n                '<th colspan=\"5\" class=\"switch\"></th>' +\n                '<th class=\"next\"><i class=\"{iconType} {rightArrow}\"/></th>' +\n                '</tr>' +\n      '</thead>',\n    headTemplateV3: '<thead>' +\n                '<tr>' +\n                '<th class=\"prev\"><span class=\"{iconType} {leftArrow}\"></span> </th>' +\n                '<th colspan=\"5\" class=\"switch\"></th>' +\n                '<th class=\"next\"><span class=\"{iconType} {rightArrow}\"></span> </th>' +\n                '</tr>' +\n      '</thead>',\n    contTemplate: '<tbody><tr><td colspan=\"7\"></td></tr></tbody>',\n    footTemplate: '<tfoot>' + \n                    '<tr><th colspan=\"7\" class=\"today\"></th></tr>' +\n                    '<tr><th colspan=\"7\" class=\"clear\"></th></tr>' +\n                  '</tfoot>'\n  };\n  DPGlobal.template = '<div class=\"datetimepicker\">' +\n    '<div class=\"datetimepicker-minutes\">' +\n    '<table class=\" table-condensed\">' +\n    DPGlobal.headTemplate +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-hours\">' +\n    '<table class=\" table-condensed\">' +\n    DPGlobal.headTemplate +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-days\">' +\n    '<table class=\" table-condensed\">' +\n    DPGlobal.headTemplate +\n    '<tbody></tbody>' +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-months\">' +\n    '<table class=\"table-condensed\">' +\n    DPGlobal.headTemplate +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-years\">' +\n    '<table class=\"table-condensed\">' +\n    DPGlobal.headTemplate +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '</div>';\n  DPGlobal.templateV3 = '<div class=\"datetimepicker\">' +\n    '<div class=\"datetimepicker-minutes\">' +\n    '<table class=\" table-condensed\">' +\n    DPGlobal.headTemplateV3 +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-hours\">' +\n    '<table class=\" table-condensed\">' +\n    DPGlobal.headTemplateV3 +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-days\">' +\n    '<table class=\" table-condensed\">' +\n    DPGlobal.headTemplateV3 +\n    '<tbody></tbody>' +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-months\">' +\n    '<table class=\"table-condensed\">' +\n    DPGlobal.headTemplateV3 +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '<div class=\"datetimepicker-years\">' +\n    '<table class=\"table-condensed\">' +\n    DPGlobal.headTemplateV3 +\n    DPGlobal.contTemplate +\n    DPGlobal.footTemplate +\n    '</table>' +\n    '</div>' +\n    '</div>';\n  $.fn.datetimepicker.DPGlobal = DPGlobal;\n\n  /* DATETIMEPICKER NO CONFLICT\n   * =================== */\n\n  $.fn.datetimepicker.noConflict = function () {\n    $.fn.datetimepicker = old;\n    return this;\n  };\n\n  /* DATETIMEPICKER DATA-API\n   * ================== */\n\n  $(document).on(\n    'focus.datetimepicker.data-api click.datetimepicker.data-api',\n    '[data-provide=\"datetimepicker\"]',\n    function (e) {\n      var $this = $(this);\n      if ($this.data('datetimepicker')) return;\n      e.preventDefault();\n      // component click requires us to explicitly show it\n      $this.datetimepicker('show');\n    }\n  );\n  $(function () {\n    $('[data-provide=\"datetimepicker-inline\"]').datetimepicker();\n  });\n\n}));\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/duallistbox/bootstrap-duallistbox.css",
    "content": "/*\n *  Bootstrap Duallistbox - v3.0.9\n *  A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.\n *  https://www.virtuosoft.eu/code/bootstrap-duallistbox/\n *\n *  Made by István Ujj-Mészáros\n *  Under Apache License v2.0 License\n */\n.bootstrap-duallistbox-container .buttons {\n  width: 100%;\n  margin-bottom: -1px;\n}\n\n.bootstrap-duallistbox-container label {\n  display: block;\n}\n\n.bootstrap-duallistbox-container .info {\n  display: inline-block;\n  margin-bottom: 5px;\n  font-size: 11px;\n}\n\n.bootstrap-duallistbox-container .clear1,\n.bootstrap-duallistbox-container .clear2 {\n  display: none;\n  font-size: 10px;\n}\n\n.bootstrap-duallistbox-container .box1.filtered .clear1,\n.bootstrap-duallistbox-container .box2.filtered .clear2 {\n  display: inline-block;\n}\n\n.bootstrap-duallistbox-container .move,\n.bootstrap-duallistbox-container .remove {\n  width: 60%;\n}\n\n.bootstrap-duallistbox-container .btn-group .btn {\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.bootstrap-duallistbox-container select {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.bootstrap-duallistbox-container .moveall,\n.bootstrap-duallistbox-container .removeall {\n  width: 40%;\n}\n\n.bootstrap-duallistbox-container.bs2compatible .btn-group > .btn + .btn {\n  margin-left: 0;\n}\n\n.bootstrap-duallistbox-container select {\n  width: 100%;\n  height: 300px;\n  padding: 0;\n}\n\n.bootstrap-duallistbox-container .filter {\n  display: inline-block;\n  width: 100%;\n  height: 31px;\n  margin: 0 0 5px 0;\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.bootstrap-duallistbox-container .filter.placeholder {\n  color: #aaa;\n}\n\n.bootstrap-duallistbox-container.moveonselect .move,\n.bootstrap-duallistbox-container.moveonselect .remove {\n  display:none;\n}\n\n.bootstrap-duallistbox-container.moveonselect .moveall,\n.bootstrap-duallistbox-container.moveonselect .removeall {\n  width: 100%;\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/duallistbox/bootstrap-duallistbox.js",
    "content": "/*\r\n *  Bootstrap Duallistbox - v3.0.9\r\n *  A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.\r\n *  https://www.virtuosoft.eu/code/bootstrap-duallistbox/\r\n *\r\n *  Made by István Ujj-Mészáros\r\n *  Under Apache License v2.0 License\r\n */\r\n;(function ($, window, document, undefined) {\r\n  // Create the defaults once\r\n  var pluginName = 'bootstrapDualListbox',\r\n    defaults = {\r\n      bootstrap2Compatible: false,\r\n      filterTextClear: 'show all',\r\n      filterPlaceHolder: 'Filter',\r\n      moveSelectedLabel: 'Move selected',\r\n      moveAllLabel: 'Move all',\r\n      removeSelectedLabel: 'Remove selected',\r\n      removeAllLabel: 'Remove all',\r\n      moveOnSelect: true,                                                                 // true/false (forced true on androids, see the comment later)\r\n      moveOnDoubleClick: true,                                                            // true/false (forced false on androids, cause moveOnSelect is forced to true)\r\n      preserveSelectionOnMove: false,                                                     // 'all' / 'moved' / false\r\n      selectedListLabel: false,                                                           // 'string', false\r\n      nonSelectedListLabel: false,                                                        // 'string', false\r\n      helperSelectNamePostfix: '_helper',                                                 // 'string_of_postfix' / false\r\n      selectorMinimalHeight: 100,\r\n      showFilterInputs: true,                                                             // whether to show filter inputs\r\n      nonSelectedFilter: '',                                                              // string, filter the non selected options\r\n      selectedFilter: '',                                                                 // string, filter the selected options\r\n      infoText: 'Showing all {0}',                                                        // text when all options are visible / false for no info text\r\n      infoTextFiltered: '<span class=\"label label-warning\">Filtered</span> {0} from {1}', // when not all of the options are visible due to the filter\r\n      infoTextEmpty: 'Empty list',                                                        // when there are no options present in the list\r\n      filterOnValues: false,                                                              // filter by selector's values, boolean\r\n      sortByInputOrder: false,\r\n      eventMoveOverride: false,                                                           // boolean, allows user to unbind default event behaviour and run their own instead\r\n      eventMoveAllOverride: false,                                                        // boolean, allows user to unbind default event behaviour and run their own instead\r\n      eventRemoveOverride: false,                                                         // boolean, allows user to unbind default event behaviour and run their own instead\r\n      eventRemoveAllOverride: false                                                       // boolean, allows user to unbind default event behaviour and run their own instead\r\n    },\r\n    // Selections are invisible on android if the containing select is styled with CSS\r\n    // http://code.google.com/p/android/issues/detail?id=16922\r\n    isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase());\r\n\r\n  // The actual plugin constructor\r\n  function BootstrapDualListbox(element, options) {\r\n    this.element = $(element);\r\n    // jQuery has an extend method which merges the contents of two or\r\n    // more objects, storing the result in the first object. The first object\r\n    // is generally empty as we don't want to alter the default options for\r\n    // future instances of the plugin\r\n    this.settings = $.extend({}, defaults, options);\r\n    this._defaults = defaults;\r\n    this._name = pluginName;\r\n    this.init();\r\n  }\r\n\r\n  function triggerChangeEvent(dualListbox) {\r\n    dualListbox.element.trigger('change');\r\n  }\r\n\r\n  function updateSelectionStates(dualListbox) {\r\n    dualListbox.element.find('option').each(function(index, item) {\r\n      var $item = $(item);\r\n      if (typeof($item.data('original-index')) === 'undefined') {\r\n        $item.data('original-index', dualListbox.elementCount++);\r\n      }\r\n      if (typeof($item.data('_selected')) === 'undefined') {\r\n        $item.data('_selected', false);\r\n      }\r\n    });\r\n  }\r\n\r\n  function changeSelectionState(dualListbox, original_index, selected) {\r\n    dualListbox.element.find('option').each(function(index, item) {\r\n      var $item = $(item);\r\n      if ($item.data('original-index') === original_index) {\r\n        $item.prop('selected', selected);\r\n        if(selected){\r\n          $item.attr('data-sortindex', dualListbox.sortIndex);\r\n          dualListbox.sortIndex++;\r\n        } else {\r\n          $item.removeAttr('data-sortindex');\r\n        }\r\n      }\r\n    });\r\n  }\r\n\r\n  function formatString(s, args) {\r\n    return s.replace(/\\{(\\d+)\\}/g, function(match, number) {\r\n      return typeof args[number] !== 'undefined' ? args[number] : match;\r\n    });\r\n  }\r\n\r\n  function refreshInfo(dualListbox) {\r\n    if (!dualListbox.settings.infoText) {\r\n      return;\r\n    }\r\n\r\n    var visible1 = dualListbox.elements.select1.find('option').length,\r\n      visible2 = dualListbox.elements.select2.find('option').length,\r\n      all1 = dualListbox.element.find('option').length - dualListbox.selectedElements,\r\n      all2 = dualListbox.selectedElements,\r\n      content = '';\r\n\r\n    if (all1 === 0) {\r\n      content = dualListbox.settings.infoTextEmpty;\r\n    } else if (visible1 === all1) {\r\n      content = formatString(dualListbox.settings.infoText, [visible1, all1]);\r\n    } else {\r\n      content = formatString(dualListbox.settings.infoTextFiltered, [visible1, all1]);\r\n    }\r\n\r\n    dualListbox.elements.info1.html(content);\r\n    dualListbox.elements.box1.toggleClass('filtered', !(visible1 === all1 || all1 === 0));\r\n\r\n    if (all2 === 0) {\r\n      content = dualListbox.settings.infoTextEmpty;\r\n    } else if (visible2 === all2) {\r\n      content = formatString(dualListbox.settings.infoText, [visible2, all2]);\r\n    } else {\r\n      content = formatString(dualListbox.settings.infoTextFiltered, [visible2, all2]);\r\n    }\r\n\r\n    dualListbox.elements.info2.html(content);\r\n    dualListbox.elements.box2.toggleClass('filtered', !(visible2 === all2 || all2 === 0));\r\n  }\r\n\r\n  function refreshSelects(dualListbox) {\r\n    dualListbox.selectedElements = 0;\r\n\r\n    dualListbox.elements.select1.empty();\r\n    dualListbox.elements.select2.empty();\r\n\r\n    dualListbox.element.find('option').each(function(index, item) {\r\n      var $item = $(item);\r\n      if ($item.prop('selected')) {\r\n        dualListbox.selectedElements++;\r\n        dualListbox.elements.select2.append($item.clone(true).prop('selected', $item.data('_selected')));\r\n      } else {\r\n        dualListbox.elements.select1.append($item.clone(true).prop('selected', $item.data('_selected')));\r\n      }\r\n    });\r\n\r\n    if (dualListbox.settings.showFilterInputs) {\r\n      filter(dualListbox, 1);\r\n      filter(dualListbox, 2);\r\n    }\r\n    refreshInfo(dualListbox);\r\n  }\r\n\r\n  function filter(dualListbox, selectIndex) {\r\n    if (!dualListbox.settings.showFilterInputs) {\r\n      return;\r\n    }\r\n\r\n    saveSelections(dualListbox, selectIndex);\r\n\r\n    dualListbox.elements['select'+selectIndex].empty().scrollTop(0);\r\n    var regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi'),\r\n      allOptions = dualListbox.element.find('option'),\r\n      options = dualListbox.element;\r\n\r\n    if (selectIndex === 1) {\r\n      options = allOptions.not(':selected');\r\n    } else  {\r\n      options = options.find('option:selected');\r\n    }\r\n\r\n    options.each(function(index, item) {\r\n      var $item = $(item),\r\n        isFiltered = true;\r\n      if (item.text.match(regex) || (dualListbox.settings.filterOnValues && $item.attr('value').match(regex) ) ) {\r\n        isFiltered = false;\r\n        dualListbox.elements['select'+selectIndex].append($item.clone(true).prop('selected', $item.data('_selected')));\r\n      }\r\n      allOptions.eq($item.data('original-index')).data('filtered'+selectIndex, isFiltered);\r\n    });\r\n\r\n    refreshInfo(dualListbox);\r\n  }\r\n\r\n  function saveSelections(dualListbox, selectIndex) {\r\n    var options = dualListbox.element.find('option');\r\n    dualListbox.elements['select'+selectIndex].find('option').each(function(index, item) {\r\n      var $item = $(item);\r\n      options.eq($item.data('original-index')).data('_selected', $item.prop('selected'));\r\n    });\r\n  }\r\n\r\n  function sortOptionsByInputOrder(select){\r\n    var selectopt = select.children('option');\r\n\r\n    selectopt.sort(function(a,b){\r\n      var an = parseInt(a.getAttribute('data-sortindex')),\r\n          bn = parseInt(b.getAttribute('data-sortindex'));\r\n\r\n          if(an > bn) {\r\n             return 1;\r\n          }\r\n          if(an < bn) {\r\n            return -1;\r\n          }\r\n          return 0;\r\n    });\r\n\r\n    selectopt.detach().appendTo(select);\r\n  }\r\n\r\n  function sortOptions(select, dualListbox) {\r\n    select.find('option').sort(function(a, b) {\r\n      return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;\r\n    }).appendTo(select);\r\n\r\n    // workaround for chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1072475\r\n    refreshSelects(dualListbox);\r\n  }\r\n\r\n  function clearSelections(dualListbox) {\r\n    dualListbox.elements.select1.find('option').each(function() {\r\n      dualListbox.element.find('option').data('_selected', false);\r\n    });\r\n  }\r\n\r\n  function move(dualListbox) {\r\n    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 1);\r\n      saveSelections(dualListbox, 2);\r\n    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 1);\r\n    }\r\n\r\n    dualListbox.elements.select1.find('option:selected').each(function(index, item) {\r\n      var $item = $(item);\r\n      if (!$item.data('filtered1')) {\r\n        changeSelectionState(dualListbox, $item.data('original-index'), true);\r\n      }\r\n    });\r\n\r\n    refreshSelects(dualListbox);\r\n    triggerChangeEvent(dualListbox);\r\n    if(dualListbox.settings.sortByInputOrder){\r\n        sortOptionsByInputOrder(dualListbox.elements.select2);\r\n    } else {\r\n        sortOptions(dualListbox.elements.select2, dualListbox);\r\n    }\r\n  }\r\n\r\n  function remove(dualListbox) {\r\n    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 1);\r\n      saveSelections(dualListbox, 2);\r\n    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 2);\r\n    }\r\n\r\n    dualListbox.elements.select2.find('option:selected').each(function(index, item) {\r\n      var $item = $(item);\r\n      if (!$item.data('filtered2')) {\r\n        changeSelectionState(dualListbox, $item.data('original-index'), false);\r\n      }\r\n    });\r\n\r\n    refreshSelects(dualListbox);\r\n    triggerChangeEvent(dualListbox);\r\n    sortOptions(dualListbox.elements.select1, dualListbox);\r\n    if(dualListbox.settings.sortByInputOrder){\r\n        sortOptionsByInputOrder(dualListbox.elements.select2);\r\n    }\r\n  }\r\n\r\n  function moveAll(dualListbox) {\r\n    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 1);\r\n      saveSelections(dualListbox, 2);\r\n    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 1);\r\n    }\r\n\r\n    dualListbox.element.find('option').each(function(index, item) {\r\n      var $item = $(item);\r\n      if (!$item.data('filtered1')) {\r\n        $item.prop('selected', true);\r\n        $item.attr('data-sortindex', dualListbox.sortIndex);\r\n        dualListbox.sortIndex++;\r\n      }\r\n    });\r\n\r\n    refreshSelects(dualListbox);\r\n    triggerChangeEvent(dualListbox);\r\n  }\r\n\r\n  function removeAll(dualListbox) {\r\n    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 1);\r\n      saveSelections(dualListbox, 2);\r\n    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {\r\n      saveSelections(dualListbox, 2);\r\n    }\r\n\r\n    dualListbox.element.find('option').each(function(index, item) {\r\n      var $item = $(item);\r\n      if (!$item.data('filtered2')) {\r\n        $item.prop('selected', false);\r\n        $item.removeAttr('data-sortindex');\r\n      }\r\n    });\r\n\r\n    refreshSelects(dualListbox);\r\n    triggerChangeEvent(dualListbox);\r\n  }\r\n\r\n  function bindEvents(dualListbox) {\r\n    dualListbox.elements.form.submit(function(e) {\r\n      if (dualListbox.elements.filterInput1.is(':focus')) {\r\n        e.preventDefault();\r\n        dualListbox.elements.filterInput1.focusout();\r\n      } else if (dualListbox.elements.filterInput2.is(':focus')) {\r\n        e.preventDefault();\r\n        dualListbox.elements.filterInput2.focusout();\r\n      }\r\n    });\r\n\r\n    dualListbox.element.on('bootstrapDualListbox.refresh', function(e, mustClearSelections){\r\n      dualListbox.refresh(mustClearSelections);\r\n    });\r\n\r\n    dualListbox.elements.filterClear1.on('click', function() {\r\n      dualListbox.setNonSelectedFilter('', true);\r\n    });\r\n\r\n    dualListbox.elements.filterClear2.on('click', function() {\r\n      dualListbox.setSelectedFilter('', true);\r\n    });\r\n\r\n    if (dualListbox.settings.eventMoveOverride === false) {\r\n      dualListbox.elements.moveButton.on('click', function() {\r\n        move(dualListbox);\r\n      });\r\n    }\r\n\r\n    if (dualListbox.settings.eventMoveAllOverride === false) {\r\n      dualListbox.elements.moveAllButton.on('click', function() {\r\n        moveAll(dualListbox);\r\n      });\r\n    }\r\n\r\n    if (dualListbox.settings.eventRemoveOverride === false) {\r\n      dualListbox.elements.removeButton.on('click', function() {\r\n        remove(dualListbox);\r\n      });\r\n    }\r\n\r\n    if (dualListbox.settings.eventRemoveAllOverride === false) {\r\n      dualListbox.elements.removeAllButton.on('click', function() {\r\n        removeAll(dualListbox);\r\n      });\r\n    }\r\n\r\n    dualListbox.elements.filterInput1.on('change keyup', function() {\r\n      filter(dualListbox, 1);\r\n    });\r\n\r\n    dualListbox.elements.filterInput2.on('change keyup', function() {\r\n      filter(dualListbox, 2);\r\n    });\r\n  }\r\n\r\n  BootstrapDualListbox.prototype = {\r\n    init: function () {\r\n      // Add the custom HTML template\r\n      this.container = $('' +\r\n        '<div class=\"bootstrap-duallistbox-container\">' +\r\n        ' <div class=\"box1\">' +\r\n        '   <label></label>' +\r\n        '   <span class=\"info-container\">' +\r\n        '     <span class=\"info\"></span>' +\r\n        '     <button type=\"button\" class=\"btn clear1 pull-right\"></button>' +\r\n        '   </span>' +\r\n        '   <input class=\"filter\" type=\"text\">' +\r\n        '   <div class=\"btn-group buttons\">' +\r\n        '     <button type=\"button\" class=\"btn moveall\">' +\r\n        '       <i></i>' +\r\n        '       <i></i>' +\r\n        '     </button>' +\r\n        '     <button type=\"button\" class=\"btn move\">' +\r\n        '       <i></i>' +\r\n        '     </button>' +\r\n        '   </div>' +\r\n        '   <select multiple=\"multiple\"></select>' +\r\n        ' </div>' +\r\n        ' <div class=\"box2\">' +\r\n        '   <label></label>' +\r\n        '   <span class=\"info-container\">' +\r\n        '     <span class=\"info\"></span>' +\r\n        '     <button type=\"button\" class=\"btn clear2 pull-right\"></button>' +\r\n        '   </span>' +\r\n        '   <input class=\"filter\" type=\"text\">' +\r\n        '   <div class=\"btn-group buttons\">' +\r\n        '     <button type=\"button\" class=\"btn remove\">' +\r\n        '       <i></i>' +\r\n        '     </button>' +\r\n        '     <button type=\"button\" class=\"btn removeall\">' +\r\n        '       <i></i>' +\r\n        '       <i></i>' +\r\n        '     </button>' +\r\n        '   </div>' +\r\n        '   <select multiple=\"multiple\"></select>' +\r\n        ' </div>' +\r\n        '</div>')\r\n        .insertBefore(this.element);\r\n\r\n      // Cache the inner elements\r\n      this.elements = {\r\n        originalSelect: this.element,\r\n        box1: $('.box1', this.container),\r\n        box2: $('.box2', this.container),\r\n        filterInput1: $('.box1 .filter', this.container),\r\n        filterInput2: $('.box2 .filter', this.container),\r\n        filterClear1: $('.box1 .clear1', this.container),\r\n        filterClear2: $('.box2 .clear2', this.container),\r\n        label1: $('.box1 > label', this.container),\r\n        label2: $('.box2 > label', this.container),\r\n        info1: $('.box1 .info', this.container),\r\n        info2: $('.box2 .info', this.container),\r\n        select1: $('.box1 select', this.container),\r\n        select2: $('.box2 select', this.container),\r\n        moveButton: $('.box1 .move', this.container),\r\n        removeButton: $('.box2 .remove', this.container),\r\n        moveAllButton: $('.box1 .moveall', this.container),\r\n        removeAllButton: $('.box2 .removeall', this.container),\r\n        form: $($('.box1 .filter', this.container)[0].form)\r\n      };\r\n\r\n      // Set select IDs\r\n      this.originalSelectName = this.element.attr('name') || '';\r\n      var select1Id = 'bootstrap-duallistbox-nonselected-list_' + this.originalSelectName,\r\n        select2Id = 'bootstrap-duallistbox-selected-list_' + this.originalSelectName;\r\n      this.elements.select1.attr('id', select1Id);\r\n      this.elements.select2.attr('id', select2Id);\r\n      this.elements.label1.attr('for', select1Id);\r\n      this.elements.label2.attr('for', select2Id);\r\n\r\n      // Apply all settings\r\n      this.selectedElements = 0;\r\n      this.sortIndex = 0;\r\n      this.elementCount = 0;\r\n      this.setBootstrap2Compatible(this.settings.bootstrap2Compatible);\r\n      this.setFilterTextClear(this.settings.filterTextClear);\r\n      this.setFilterPlaceHolder(this.settings.filterPlaceHolder);\r\n      this.setMoveSelectedLabel(this.settings.moveSelectedLabel);\r\n      this.setMoveAllLabel(this.settings.moveAllLabel);\r\n      this.setRemoveSelectedLabel(this.settings.removeSelectedLabel);\r\n      this.setRemoveAllLabel(this.settings.removeAllLabel);\r\n      this.setMoveOnSelect(this.settings.moveOnSelect);\r\n      this.setMoveOnDoubleClick(this.settings.moveOnDoubleClick);\r\n      this.setPreserveSelectionOnMove(this.settings.preserveSelectionOnMove);\r\n      this.setSelectedListLabel(this.settings.selectedListLabel);\r\n      this.setNonSelectedListLabel(this.settings.nonSelectedListLabel);\r\n      this.setHelperSelectNamePostfix(this.settings.helperSelectNamePostfix);\r\n      this.setSelectOrMinimalHeight(this.settings.selectorMinimalHeight);\r\n\r\n      updateSelectionStates(this);\r\n\r\n      this.setShowFilterInputs(this.settings.showFilterInputs);\r\n      this.setNonSelectedFilter(this.settings.nonSelectedFilter);\r\n      this.setSelectedFilter(this.settings.selectedFilter);\r\n      this.setInfoText(this.settings.infoText);\r\n      this.setInfoTextFiltered(this.settings.infoTextFiltered);\r\n      this.setInfoTextEmpty(this.settings.infoTextEmpty);\r\n      this.setFilterOnValues(this.settings.filterOnValues);\r\n      this.setSortByInputOrder(this.settings.sortByInputOrder);\r\n      this.setEventMoveOverride(this.settings.eventMoveOverride);\r\n      this.setEventMoveAllOverride(this.settings.eventMoveAllOverride);\r\n      this.setEventRemoveOverride(this.settings.eventRemoveOverride);\r\n      this.setEventRemoveAllOverride(this.settings.eventRemoveAllOverride);\r\n\r\n      // Hide the original select\r\n      this.element.hide();\r\n\r\n      bindEvents(this);\r\n      refreshSelects(this);\r\n\r\n      return this.element;\r\n    },\r\n    setBootstrap2Compatible: function(value, refresh) {\r\n      this.settings.bootstrap2Compatible = value;\r\n      if (value) {\r\n        this.container.removeClass('row').addClass('row-fluid bs2compatible');\r\n        this.container.find('.box1, .box2').removeClass('col-md-6').addClass('span6');\r\n        this.container.find('.clear1, .clear2').removeClass('btn-default btn-xs').addClass('btn-mini');\r\n        this.container.find('input, select').removeClass('form-control');\r\n        this.container.find('.btn').removeClass('btn-default');\r\n        this.container.find('.moveall > i, .move > i').removeClass('glyphicon glyphicon-arrow-right').addClass('icon-arrow-right');\r\n        this.container.find('.removeall > i, .remove > i').removeClass('glyphicon glyphicon-arrow-left').addClass('icon-arrow-left');\r\n      } else {\r\n        this.container.removeClass('row-fluid bs2compatible').addClass('row');\r\n        this.container.find('.box1, .box2').removeClass('span6').addClass('col-md-6');\r\n        this.container.find('.clear1, .clear2').removeClass('btn-mini').addClass('btn-default btn-xs');\r\n        this.container.find('input, select').addClass('form-control');\r\n        this.container.find('.btn').addClass('btn-default');\r\n        this.container.find('.moveall > i, .move > i').removeClass('icon-arrow-right').addClass('glyphicon glyphicon-arrow-right');\r\n        this.container.find('.removeall > i, .remove > i').removeClass('icon-arrow-left').addClass('glyphicon glyphicon-arrow-left');\r\n      }\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setFilterTextClear: function(value, refresh) {\r\n      this.settings.filterTextClear = value;\r\n      this.elements.filterClear1.html(value);\r\n      this.elements.filterClear2.html(value);\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setFilterPlaceHolder: function(value, refresh) {\r\n      this.settings.filterPlaceHolder = value;\r\n      this.elements.filterInput1.attr('placeholder', value);\r\n      this.elements.filterInput2.attr('placeholder', value);\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setMoveSelectedLabel: function(value, refresh) {\r\n      this.settings.moveSelectedLabel = value;\r\n      this.elements.moveButton.attr('title', value);\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setMoveAllLabel: function(value, refresh) {\r\n      this.settings.moveAllLabel = value;\r\n      this.elements.moveAllButton.attr('title', value);\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setRemoveSelectedLabel: function(value, refresh) {\r\n      this.settings.removeSelectedLabel = value;\r\n      this.elements.removeButton.attr('title', value);\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setRemoveAllLabel: function(value, refresh) {\r\n      this.settings.removeAllLabel = value;\r\n      this.elements.removeAllButton.attr('title', value);\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setMoveOnSelect: function(value, refresh) {\r\n      if (isBuggyAndroid) {\r\n        value = true;\r\n      }\r\n      this.settings.moveOnSelect = value;\r\n      if (this.settings.moveOnSelect) {\r\n        this.container.addClass('moveonselect');\r\n        var self = this;\r\n        this.elements.select1.on('change', function() {\r\n          move(self);\r\n        });\r\n        this.elements.select2.on('change', function() {\r\n          remove(self);\r\n        });\r\n      } else {\r\n        this.container.removeClass('moveonselect');\r\n        this.elements.select1.off('change');\r\n        this.elements.select2.off('change');\r\n      }\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setMoveOnDoubleClick: function(value, refresh) {\r\n      if (isBuggyAndroid) {\r\n        value = false;\r\n      }\r\n      this.settings.moveOnDoubleClick = value;\r\n      if (this.settings.moveOnDoubleClick) {\r\n        this.container.addClass('moveondoubleclick');\r\n        var self = this;\r\n        this.elements.select1.on('dblclick', function() {\r\n          move(self);\r\n        });\r\n        this.elements.select2.on('dblclick', function() {\r\n          remove(self);\r\n        });\r\n      } else {\r\n        this.container.removeClass('moveondoubleclick');\r\n        this.elements.select1.off('dblclick');\r\n        this.elements.select2.off('dblclick');\r\n      }\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setPreserveSelectionOnMove: function(value, refresh) {\r\n      // We are forcing to move on select and disabling preserveSelectionOnMove on Android\r\n      if (isBuggyAndroid) {\r\n        value = false;\r\n      }\r\n      this.settings.preserveSelectionOnMove = value;\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setSelectedListLabel: function(value, refresh) {\r\n      this.settings.selectedListLabel = value;\r\n      if (value) {\r\n        this.elements.label2.show().html(value);\r\n      } else {\r\n        this.elements.label2.hide().html(value);\r\n      }\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setNonSelectedListLabel: function(value, refresh) {\r\n      this.settings.nonSelectedListLabel = value;\r\n      if (value) {\r\n        this.elements.label1.show().html(value);\r\n      } else {\r\n        this.elements.label1.hide().html(value);\r\n      }\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setHelperSelectNamePostfix: function(value, refresh) {\r\n      this.settings.helperSelectNamePostfix = value;\r\n      if (value) {\r\n        this.elements.select1.attr('name', this.originalSelectName + value + '1');\r\n        this.elements.select2.attr('name', this.originalSelectName + value + '2');\r\n      } else {\r\n        this.elements.select1.removeAttr('name');\r\n        this.elements.select2.removeAttr('name');\r\n      }\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setSelectOrMinimalHeight: function(value, refresh) {\r\n      this.settings.selectorMinimalHeight = value;\r\n      var height = this.element.height();\r\n      if (this.element.height() < value) {\r\n        height = value;\r\n      }\r\n      this.elements.select1.height(height);\r\n      this.elements.select2.height(height);\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setShowFilterInputs: function(value, refresh) {\r\n      if (!value) {\r\n        this.setNonSelectedFilter('');\r\n        this.setSelectedFilter('');\r\n        refreshSelects(this);\r\n        this.elements.filterInput1.hide();\r\n        this.elements.filterInput2.hide();\r\n      } else {\r\n        this.elements.filterInput1.show();\r\n        this.elements.filterInput2.show();\r\n      }\r\n      this.settings.showFilterInputs = value;\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setNonSelectedFilter: function(value, refresh) {\r\n      if (this.settings.showFilterInputs) {\r\n        this.settings.nonSelectedFilter = value;\r\n        this.elements.filterInput1.val(value);\r\n        if (refresh) {\r\n          refreshSelects(this);\r\n        }\r\n        return this.element;\r\n      }\r\n    },\r\n    setSelectedFilter: function(value, refresh) {\r\n      if (this.settings.showFilterInputs) {\r\n        this.settings.selectedFilter = value;\r\n        this.elements.filterInput2.val(value);\r\n        if (refresh) {\r\n          refreshSelects(this);\r\n        }\r\n        return this.element;\r\n      }\r\n    },\r\n    setInfoText: function(value, refresh) {\r\n      this.settings.infoText = value;\r\n      if (value) {\r\n        this.elements.info1.show();\r\n        this.elements.info2.show();\r\n      } else {\r\n        this.elements.info1.hide();\r\n        this.elements.info2.hide();\r\n      }\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setInfoTextFiltered: function(value, refresh) {\r\n      this.settings.infoTextFiltered = value;\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setInfoTextEmpty: function(value, refresh) {\r\n      this.settings.infoTextEmpty = value;\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setFilterOnValues: function(value, refresh) {\r\n      this.settings.filterOnValues = value;\r\n      if (refresh) {\r\n        refreshSelects(this);\r\n      }\r\n      return this.element;\r\n    },\r\n    setSortByInputOrder: function(value, refresh){\r\n        this.settings.sortByInputOrder = value;\r\n        if (refresh) {\r\n          refreshSelects(this);\r\n        }\r\n        return this.element;\r\n    },\r\n    setEventMoveOverride: function(value, refresh) {\r\n        this.settings.eventMoveOverride = value;\r\n        if (refresh) {\r\n          refreshSelects(this);\r\n        }\r\n        return this.element;\r\n    },\r\n    setEventMoveAllOverride: function(value, refresh) {\r\n        this.settings.eventMoveAllOverride = value;\r\n        if (refresh) {\r\n          refreshSelects(this);\r\n        }\r\n        return this.element;\r\n    },\r\n    setEventRemoveOverride: function(value, refresh) {\r\n        this.settings.eventRemoveOverride = value;\r\n        if (refresh) {\r\n          refreshSelects(this);\r\n        }\r\n        return this.element;\r\n    },\r\n    setEventRemoveAllOverride: function(value, refresh) {\r\n        this.settings.eventRemoveAllOverride = value;\r\n        if (refresh) {\r\n          refreshSelects(this);\r\n        }\r\n        return this.element;\r\n    },\r\n    getContainer: function() {\r\n      return this.container;\r\n    },\r\n    refresh: function(mustClearSelections) {\r\n      updateSelectionStates(this);\r\n\r\n      if (!mustClearSelections) {\r\n        saveSelections(this, 1);\r\n        saveSelections(this, 2);\r\n      } else {\r\n        clearSelections(this);\r\n      }\r\n\r\n      refreshSelects(this);\r\n    },\r\n    destroy: function() {\r\n      this.container.remove();\r\n      this.element.show();\r\n      $.data(this, 'plugin_' + pluginName, null);\r\n      return this.element;\r\n    }\r\n  };\r\n\r\n  // A really lightweight plugin wrapper around the constructor,\r\n  // preventing against multiple instantiations\r\n  $.fn[ pluginName ] = function (options) {\r\n    var args = arguments;\r\n\r\n    // Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.\r\n    if (options === undefined || typeof options === 'object') {\r\n      return this.each(function () {\r\n        // If this is not a select\r\n        if (!$(this).is('select')) {\r\n          $(this).find('select').each(function(index, item) {\r\n            // For each nested select, instantiate the Dual List Box\r\n            $(item).bootstrapDualListbox(options);\r\n          });\r\n        } else if (!$.data(this, 'plugin_' + pluginName)) {\r\n          // Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet\r\n\r\n          // if it has no instance, create a new one, pass options to our plugin constructor,\r\n          // and store the plugin instance in the elements jQuery data object.\r\n          $.data(this, 'plugin_' + pluginName, new BootstrapDualListbox(this, options));\r\n        }\r\n      });\r\n      // If the first parameter is a string and it doesn't start with an underscore or \"contains\" the `init`-function,\r\n      // treat this as a call to a public method.\r\n    } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {\r\n\r\n      // Cache the method call to make it possible to return a value\r\n      var returns;\r\n\r\n      this.each(function () {\r\n        var instance = $.data(this, 'plugin_' + pluginName);\r\n        // Tests that there's already a plugin-instance and checks that the requested public method exists\r\n        if (instance instanceof BootstrapDualListbox && typeof instance[options] === 'function') {\r\n          // Call the method of our plugin instance, and pass it the supplied arguments.\r\n          returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));\r\n        }\r\n      });\r\n\r\n      // If the earlier cached method gives a value back return the value,\r\n      // otherwise return this to preserve chainability.\r\n      return returns !== undefined ? returns : this;\r\n    }\r\n\r\n  };\r\n\r\n})(jQuery, window, document);\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/flot/curvedLines.js",
    "content": "/* The MIT License\n\n Copyright (c) 2011 by Michael Zinsmaier and nergal.dev\n Copyright (c) 2012 by Thomas Ritou\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n */\n\n/*\n\n ____________________________________________________\n\n what it is:\n ____________________________________________________\n\n curvedLines is a plugin for flot, that tries to display lines in a smoother way.\n The plugin is based on nergal.dev's work https://code.google.com/p/flot/issues/detail?id=226\n and further extended with a mode that forces the min/max points of the curves to be on the\n points. Both modes are achieved through adding of more data points\n => 1) with large data sets you may get trouble\n => 2) if you want to display the points too, you have to plot them as 2nd data series over the lines\n\n && 3) consecutive x data points are not allowed to have the same value\n\n This is version 0.5 of curvedLines so it will probably not work in every case. However\n the basic form of use descirbed next works (:\n\n Feel free to further improve the code\n\n ____________________________________________________\n\n how to use it:\n ____________________________________________________\n\n var d1 = [[5,5],[7,3],[9,12]];\n\n var options = { series: { curvedLines: {  active: true }}};\n\n $.plot($(\"#placeholder\"), [{data = d1, lines: { show: true}, curvedLines: {apply: true}}], options);\n\n _____________________________________________________\n\n options:\n _____________________________________________________\n\n active:           bool true => plugin can be used\n apply:            bool true => series will be drawn as curved line\n fit:              bool true => forces the max,mins of the curve to be on the datapoints\n curvePointFactor  int  defines how many \"virtual\" points are used per \"real\" data point to\n emulate the curvedLines (points total = real points * curvePointFactor)\n fitPointDist:     int  defines the x axis distance of the additional two points that are used\n to enforce the min max condition.\n\n + line options (since v0.5 curved lines use flots line implementation for drawing\n => line options like fill, show ... are supported out of the box)\n\n */\n\n/*\n *  v0.1   initial commit\n *  v0.15  negative values should work now (outcommented a negative -> 0 hook hope it does no harm)\n *  v0.2   added fill option (thanks to monemihir) and multi axis support (thanks to soewono effendi)\n *  v0.3   improved saddle handling and added basic handling of Dates\n *  v0.4   rewritten fill option (thomas ritou) mostly from original flot code (now fill between points rather than to graph bottom), corrected fill Opacity bug\n *  v0.5   rewritten instead of implementing a own draw function CurvedLines is now based on the processDatapoints flot hook (credits go to thomas ritou).\n * \t\t   This change breakes existing code however CurvedLines are now just many tiny straight lines to flot and therefore all flot lines options (like gradient fill,\n * \t       shadow) are now supported out of the box\n *  v0.6   flot 0.8 compatibility and some bug fixes\n */\n\n(function($) {\n\n    var options = {\n        series : {\n            curvedLines : {\n                active : false,\n                apply: false,\n                fit : false,\n                curvePointFactor : 20,\n                fitPointDist : undefined\n            }\n        }\n    };\n\n    function init(plot) {\n\n        plot.hooks.processOptions.push(processOptions);\n\n        //if the plugin is active register processDatapoints method\n        function processOptions(plot, options) {\n            if (options.series.curvedLines.active) {\n                plot.hooks.processDatapoints.unshift(processDatapoints);\n            }\n        }\n\n        //only if the plugin is active\n        function processDatapoints(plot, series, datapoints) {\n            var nrPoints = datapoints.points.length / datapoints.pointsize;\n            var EPSILON = 0.5; //pretty large epsilon but save\n\n            if (series.curvedLines.apply == true && series.originSeries === undefined && nrPoints > (1 + EPSILON)) {\n                if (series.lines.fill) {\n\n                    var pointsTop = calculateCurvePoints(datapoints, series.curvedLines, 1)\n                        ,pointsBottom = calculateCurvePoints(datapoints, series.curvedLines, 2); //flot makes sure for us that we've got a second y point if fill is true !\n\n                    //Merge top and bottom curve\n                    datapoints.pointsize = 3;\n                    datapoints.points = [];\n                    var j = 0;\n                    var k = 0;\n                    var i = 0;\n                    var ps = 2;\n                    while (i < pointsTop.length || j < pointsBottom.length) {\n                        if (pointsTop[i] == pointsBottom[j]) {\n                            datapoints.points[k] = pointsTop[i];\n                            datapoints.points[k + 1] = pointsTop[i + 1];\n                            datapoints.points[k + 2] = pointsBottom[j + 1];\n                            j += ps;\n                            i += ps;\n\n                        } else if (pointsTop[i] < pointsBottom[j]) {\n                            datapoints.points[k] = pointsTop[i];\n                            datapoints.points[k + 1] = pointsTop[i + 1];\n                            datapoints.points[k + 2] = k > 0 ? datapoints.points[k-1] : null;\n                            i += ps;\n                        } else {\n                            datapoints.points[k] = pointsBottom[j];\n                            datapoints.points[k + 1] = k > 1 ? datapoints.points[k-2] : null;\n                            datapoints.points[k + 2] = pointsBottom[j + 1];\n                            j += ps;\n                        }\n                        k += 3;\n                    }\n                } else if (series.lines.lineWidth > 0) {\n                    datapoints.points = calculateCurvePoints(datapoints, series.curvedLines, 1);\n                    datapoints.pointsize = 2;\n                }\n            }\n        }\n\n        //no real idea whats going on here code mainly from https://code.google.com/p/flot/issues/detail?id=226\n        //if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code.\n        function calculateCurvePoints(datapoints, curvedLinesOptions, yPos) {\n\n            var points = datapoints.points, ps = datapoints.pointsize;\n            var num = curvedLinesOptions.curvePointFactor * (points.length / ps);\n\n            var xdata = new Array;\n            var ydata = new Array;\n\n            var curX = -1;\n            var curY = -1;\n            var j = 0;\n\n            if (curvedLinesOptions.fit) {\n                //insert a point before and after the \"real\" data point to force the line\n                //to have a max,min at the data point.\n\n                var fpDist;\n                if(typeof curvedLinesOptions.fitPointDist == 'undefined') {\n                    //estimate it\n                    var minX = points[0];\n                    var maxX = points[points.length-ps];\n                    fpDist = (maxX - minX) / (500 * 100); //x range / (estimated pixel length of placeholder * factor)\n                } else {\n                    //use user defined value\n                    fpDist = curvedLinesOptions.fitPointDist;\n                }\n\n                for (var i = 0; i < points.length; i += ps) {\n\n                    var frontX;\n                    var backX;\n                    curX = i;\n                    curY = i + yPos;\n\n                    //add point X s\n                    frontX = points[curX] - fpDist;\n                    backX = points[curX] + fpDist;\n\n                    var factor = 2;\n                    while (frontX == points[curX] || backX == points[curX]) {\n                        //inside the ulp\n                        frontX = points[curX] - (fpDist * factor);\n                        backX = points[curX] + (fpDist * factor);\n                        factor++;\n                    }\n\n                    //add curve points\n                    xdata[j] = frontX;\n                    ydata[j] = points[curY];\n                    j++;\n\n                    xdata[j] = points[curX];\n                    ydata[j] = points[curY];\n                    j++;\n\n                    xdata[j] = backX;\n                    ydata[j] = points[curY];\n                    j++;\n                }\n            } else {\n                //just use the datapoints\n                for (var i = 0; i < points.length; i += ps) {\n                    curX = i;\n                    curY = i + yPos;\n\n                    xdata[j] = points[curX];\n                    ydata[j] = points[curY];\n                    j++;\n                }\n            }\n\n            var n = xdata.length;\n\n            var y2 = new Array();\n            var delta = new Array();\n            y2[0] = 0;\n            y2[n - 1] = 0;\n            delta[0] = 0;\n\n            for (var i = 1; i < n - 1; ++i) {\n                var d = (xdata[i + 1] - xdata[i - 1]);\n                if (d == 0) {\n                    //point before current point and after current point need some space in between\n                    return [];\n                }\n\n                var s = (xdata[i] - xdata[i - 1]) / d;\n                var p = s * y2[i - 1] + 2;\n                y2[i] = (s - 1) / p;\n                delta[i] = (ydata[i + 1] - ydata[i]) / (xdata[i + 1] - xdata[i]) - (ydata[i] - ydata[i - 1]) / (xdata[i] - xdata[i - 1]);\n                delta[i] = (6 * delta[i] / (xdata[i + 1] - xdata[i - 1]) - s * delta[i - 1]) / p;\n            }\n\n            for (var j = n - 2; j >= 0; --j) {\n                y2[j] = y2[j] * y2[j + 1] + delta[j];\n            }\n\n            //   xmax  - xmin  / #points\n            var step = (xdata[n - 1] - xdata[0]) / (num - 1);\n\n            var xnew = new Array;\n            var ynew = new Array;\n            var result = new Array;\n\n            xnew[0] = xdata[0];\n            ynew[0] = ydata[0];\n\n            result.push(xnew[0]);\n            result.push(ynew[0]);\n\n            for ( j = 1; j < num; ++j) {\n                //new x point (sampling point for the created curve)\n                xnew[j] = xnew[0] + j * step;\n\n                var max = n - 1;\n                var min = 0;\n\n                while (max - min > 1) {\n                    var k = Math.round((max + min) / 2);\n                    if (xdata[k] > xnew[j]) {\n                        max = k;\n                    } else {\n                        min = k;\n                    }\n                }\n\n                //found point one to the left and one to the right of generated new point\n                var h = (xdata[max] - xdata[min]);\n\n                if (h == 0) {\n                    //similar to above two points from original x data need some space between them\n                    return [];\n                }\n\n                var a = (xdata[max] - xnew[j]) / h;\n                var b = (xnew[j] - xdata[min]) / h;\n\n                ynew[j] = a * ydata[min] + b * ydata[max] + ((a * a * a - a) * y2[min] + (b * b * b - b) * y2[max]) * (h * h) / 6;\n\n                result.push(xnew[j]);\n                result.push(ynew[j]);\n            }\n\n            return result;\n        }\n\n    }//end init\n\n    $.plot.plugins.push({\n        init : init,\n        options : options,\n        name : 'curvedLines',\n        version : '0.5'\n    });\n\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/flot/jquery.flot.js",
    "content": "/*! Javascript plotting library for jQuery, v. 0.7.\n *\n * Released under the MIT license by IOLA, December 2007.\n *\n */\n\n// first an inline dependency, jquery.colorhelpers.js, we inline it here\n// for convenience\n\n/* Plugin for jQuery for working with colors.\n *\n * Version 1.1.\n *\n * Inspiration from jQuery color animation plugin by John Resig.\n *\n * Released under the MIT license by Ole Laursen, October 2009.\n *\n * Examples:\n *\n *   $.color.parse(\"#fff\").scale('rgb', 0.25).add('a', -0.5).toString()\n *   var c = $.color.extract($(\"#mydiv\"), 'background-color');\n *   console.log(c.r, c.g, c.b, c.a);\n *   $.color.make(100, 50, 25, 0.4).toString() // returns \"rgba(100,50,25,0.4)\"\n *\n * Note that .scale() and .add() return the same modified object\n * instead of making a new one.\n *\n * V. 1.1: Fix error handling so e.g. parsing an empty string does\n * produce a color rather than just crashing.\n */\n(function(B){B.color={};B.color.make=function(F,E,C,D){var G={};G.r=F||0;G.g=E||0;G.b=C||0;G.a=D!=null?D:1;G.add=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]+=I}return G.normalize()};G.scale=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]*=I}return G.normalize()};G.toString=function(){if(G.a>=1){return\"rgb(\"+[G.r,G.g,G.b].join(\",\")+\")\"}else{return\"rgba(\"+[G.r,G.g,G.b,G.a].join(\",\")+\")\"}};G.normalize=function(){function H(J,K,I){return K<J?J:(K>I?I:K)}G.r=H(0,parseInt(G.r),255);G.g=H(0,parseInt(G.g),255);G.b=H(0,parseInt(G.b),255);G.a=H(0,G.a,1);return G};G.clone=function(){return B.color.make(G.r,G.b,G.g,G.a)};return G.normalize()};B.color.extract=function(D,C){var E;do{E=D.css(C).toLowerCase();if(E!=\"\"&&E!=\"transparent\"){break}D=D.parent()}while(!B.nodeName(D.get(0),\"body\"));if(E==\"rgba(0, 0, 0, 0)\"){E=\"transparent\"}return B.color.parse(E)};B.color.parse=function(F){var E,C=B.color.make;if(E=/rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10))}if(E=/rgba\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10),parseFloat(E[4]))}if(E=/rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55)}if(E=/rgba\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55,parseFloat(E[4]))}if(E=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(F)){return C(parseInt(E[1],16),parseInt(E[2],16),parseInt(E[3],16))}if(E=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(F)){return C(parseInt(E[1]+E[1],16),parseInt(E[2]+E[2],16),parseInt(E[3]+E[3],16))}var D=B.trim(F).toLowerCase();if(D==\"transparent\"){return C(255,255,255,0)}else{E=A[D]||[0,0,0];return C(E[0],E[1],E[2])}};var A={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);\n\n// the actual Flot code\n(function($) {\n    function Plot(placeholder, data_, options_, plugins) {\n        // data is on the form:\n        //   [ series1, series2 ... ]\n        // where series is either just the data as [ [x1, y1], [x2, y2], ... ]\n        // or { data: [ [x1, y1], [x2, y2], ... ], label: \"some label\", ... }\n\n        var series = [],\n            options = {\n                // the color theme used for graphs\n                colors: [\"#edc240\", \"#afd8f8\", \"#cb4b4b\", \"#4da74d\", \"#9440ed\"],\n                legend: {\n                    show: true,\n                    noColumns: 1, // number of colums in legend table\n                    labelFormatter: null, // fn: string -> string\n                    labelBoxBorderColor: \"#ccc\", // border color for the little label boxes\n                    container: null, // container (as jQuery object) to put legend in, null means default on top of graph\n                    position: \"ne\", // position of default legend container within plot\n                    margin: 5, // distance from grid edge to default legend container within plot\n                    backgroundColor: null, // null means auto-detect\n                    backgroundOpacity: 0.85 // set to 0 to avoid background\n                },\n                xaxis: {\n                    show: null, // null = auto-detect, true = always, false = never\n                    position: \"bottom\", // or \"top\"\n                    mode: null, // null or \"time\"\n                    color: null, // base color, labels, ticks\n                    tickColor: null, // possibly different color of ticks, e.g. \"rgba(0,0,0,0.15)\"\n                    transform: null, // null or f: number -> number to transform axis\n                    inverseTransform: null, // if transform is set, this should be the inverse function\n                    min: null, // min. value to show, null means set automatically\n                    max: null, // max. value to show, null means set automatically\n                    autoscaleMargin: null, // margin in % to add if auto-setting min/max\n                    ticks: null, // either [1, 3] or [[1, \"a\"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks\n                    tickFormatter: null, // fn: number -> string\n                    labelWidth: null, // size of tick labels in pixels\n                    labelHeight: null,\n                    reserveSpace: null, // whether to reserve space even if axis isn't shown\n                    tickLength: null, // size in pixels of ticks, or \"full\" for whole line\n                    alignTicksWithAxis: null, // axis number or null for no sync\n\n                    // mode specific options\n                    tickDecimals: null, // no. of decimals, null means auto\n                    tickSize: null, // number or [number, \"unit\"]\n                    minTickSize: null, // number or [number, \"unit\"]\n                    monthNames: null, // list of names of months\n                    timeformat: null, // format string to use\n                    twelveHourClock: false // 12 or 24 time in time mode\n                },\n                yaxis: {\n                    autoscaleMargin: 0.02,\n                    position: \"left\" // or \"right\"\n                },\n                xaxes: [],\n                yaxes: [],\n                series: {\n                    points: {\n                        show: false,\n                        radius: 3,\n                        lineWidth: 2, // in pixels\n                        fill: true,\n                        fillColor: \"#ffffff\",\n                        symbol: \"circle\" // or callback\n                    },\n                    lines: {\n                        // we don't put in show: false so we can see\n                        // whether lines were actively disabled\n                        lineWidth: 2, // in pixels\n                        fill: false,\n                        fillColor: null,\n                        steps: false\n                    },\n                    bars: {\n                        show: false,\n                        lineWidth: 2, // in pixels\n                        barWidth: 1, // in units of the x axis\n                        fill: true,\n                        fillColor: null,\n                        align: \"left\", // or \"center\"\n                        horizontal: false\n                    },\n                    shadowSize: 3\n                },\n                grid: {\n                    show: true,\n                    aboveData: false,\n                    color: \"#545454\", // primary color used for outline and labels\n                    backgroundColor: null, // null for transparent, else color\n                    borderColor: null, // set if different from the grid color\n                    tickColor: null, // color for the ticks, e.g. \"rgba(0,0,0,0.15)\"\n                    labelMargin: 5, // in pixels\n                    axisMargin: 8, // in pixels\n                    borderWidth: 2, // in pixels\n                    minBorderMargin: null, // in pixels, null means taken from points radius\n                    markings: null, // array of ranges or fn: axes -> array of ranges\n                    markingsColor: \"#f4f4f4\",\n                    markingsLineWidth: 2,\n                    // interactive stuff\n                    clickable: false,\n                    hoverable: false,\n                    autoHighlight: true, // highlight in case mouse is near\n                    mouseActiveRadius: 10 // how far the mouse can be away to activate an item\n                },\n                hooks: {}\n            },\n        canvas = null,      // the canvas for the plot itself\n        overlay = null,     // canvas for interactive stuff on top of plot\n        eventHolder = null, // jQuery object that events should be bound to\n        ctx = null, octx = null,\n        xaxes = [], yaxes = [],\n        plotOffset = { left: 0, right: 0, top: 0, bottom: 0},\n        canvasWidth = 0, canvasHeight = 0,\n        plotWidth = 0, plotHeight = 0,\n        hooks = {\n            processOptions: [],\n            processRawData: [],\n            processDatapoints: [],\n            drawSeries: [],\n            draw: [],\n            bindEvents: [],\n            drawOverlay: [],\n            shutdown: []\n        },\n        plot = this;\n\n        // public functions\n        plot.setData = setData;\n        plot.setupGrid = setupGrid;\n        plot.draw = draw;\n        plot.getPlaceholder = function() { return placeholder; };\n        plot.getCanvas = function() { return canvas; };\n        plot.getPlotOffset = function() { return plotOffset; };\n        plot.width = function () { return plotWidth; };\n        plot.height = function () { return plotHeight; };\n        plot.offset = function () {\n            var o = eventHolder.offset();\n            o.left += plotOffset.left;\n            o.top += plotOffset.top;\n            return o;\n        };\n        plot.getData = function () { return series; };\n        plot.getAxes = function () {\n            var res = {}, i;\n            $.each(xaxes.concat(yaxes), function (_, axis) {\n                if (axis)\n                    res[axis.direction + (axis.n != 1 ? axis.n : \"\") + \"axis\"] = axis;\n            });\n            return res;\n        };\n        plot.getXAxes = function () { return xaxes; };\n        plot.getYAxes = function () { return yaxes; };\n        plot.c2p = canvasToAxisCoords;\n        plot.p2c = axisToCanvasCoords;\n        plot.getOptions = function () { return options; };\n        plot.highlight = highlight;\n        plot.unhighlight = unhighlight;\n        plot.triggerRedrawOverlay = triggerRedrawOverlay;\n        plot.pointOffset = function(point) {\n            return {\n                left: parseInt(xaxes[axisNumber(point, \"x\") - 1].p2c(+point.x) + plotOffset.left),\n                top: parseInt(yaxes[axisNumber(point, \"y\") - 1].p2c(+point.y) + plotOffset.top)\n            };\n        };\n        plot.shutdown = shutdown;\n        plot.resize = function () {\n            getCanvasDimensions();\n            resizeCanvas(canvas);\n            resizeCanvas(overlay);\n        };\n\n        // public attributes\n        plot.hooks = hooks;\n\n        // initialize\n        initPlugins(plot);\n        parseOptions(options_);\n        setupCanvases();\n        setData(data_);\n        setupGrid();\n        draw();\n        bindEvents();\n\n\n        function executeHooks(hook, args) {\n            args = [plot].concat(args);\n            for (var i = 0; i < hook.length; ++i)\n                hook[i].apply(this, args);\n        }\n\n        function initPlugins() {\n            for (var i = 0; i < plugins.length; ++i) {\n                var p = plugins[i];\n                p.init(plot);\n                if (p.options)\n                    $.extend(true, options, p.options);\n            }\n        }\n\n        function parseOptions(opts) {\n            var i;\n\n            $.extend(true, options, opts);\n\n            if (options.xaxis.color == null)\n                options.xaxis.color = options.grid.color;\n            if (options.yaxis.color == null)\n                options.yaxis.color = options.grid.color;\n\n            if (options.xaxis.tickColor == null) // backwards-compatibility\n                options.xaxis.tickColor = options.grid.tickColor;\n            if (options.yaxis.tickColor == null) // backwards-compatibility\n                options.yaxis.tickColor = options.grid.tickColor;\n\n            if (options.grid.borderColor == null)\n                options.grid.borderColor = options.grid.color;\n            if (options.grid.tickColor == null)\n                options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();\n\n            // fill in defaults in axes, copy at least always the\n            // first as the rest of the code assumes it'll be there\n            for (i = 0; i < Math.max(1, options.xaxes.length); ++i)\n                options.xaxes[i] = $.extend(true, {}, options.xaxis, options.xaxes[i]);\n            for (i = 0; i < Math.max(1, options.yaxes.length); ++i)\n                options.yaxes[i] = $.extend(true, {}, options.yaxis, options.yaxes[i]);\n\n            // backwards compatibility, to be removed in future\n            if (options.xaxis.noTicks && options.xaxis.ticks == null)\n                options.xaxis.ticks = options.xaxis.noTicks;\n            if (options.yaxis.noTicks && options.yaxis.ticks == null)\n                options.yaxis.ticks = options.yaxis.noTicks;\n            if (options.x2axis) {\n                options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);\n                options.xaxes[1].position = \"top\";\n            }\n            if (options.y2axis) {\n                options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);\n                options.yaxes[1].position = \"right\";\n            }\n            if (options.grid.coloredAreas)\n                options.grid.markings = options.grid.coloredAreas;\n            if (options.grid.coloredAreasColor)\n                options.grid.markingsColor = options.grid.coloredAreasColor;\n            if (options.lines)\n                $.extend(true, options.series.lines, options.lines);\n            if (options.points)\n                $.extend(true, options.series.points, options.points);\n            if (options.bars)\n                $.extend(true, options.series.bars, options.bars);\n            if (options.shadowSize != null)\n                options.series.shadowSize = options.shadowSize;\n\n            // save options on axes for future reference\n            for (i = 0; i < options.xaxes.length; ++i)\n                getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];\n            for (i = 0; i < options.yaxes.length; ++i)\n                getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];\n\n            // add hooks from options\n            for (var n in hooks)\n                if (options.hooks[n] && options.hooks[n].length)\n                    hooks[n] = hooks[n].concat(options.hooks[n]);\n\n            executeHooks(hooks.processOptions, [options]);\n        }\n\n        function setData(d) {\n            series = parseData(d);\n            fillInSeriesOptions();\n            processData();\n        }\n\n        function parseData(d) {\n            var res = [];\n            for (var i = 0; i < d.length; ++i) {\n                var s = $.extend(true, {}, options.series);\n\n                if (d[i].data != null) {\n                    s.data = d[i].data; // move the data instead of deep-copy\n                    delete d[i].data;\n\n                    $.extend(true, s, d[i]);\n\n                    d[i].data = s.data;\n                }\n                else\n                    s.data = d[i];\n                res.push(s);\n            }\n\n            return res;\n        }\n\n        function axisNumber(obj, coord) {\n            var a = obj[coord + \"axis\"];\n            if (typeof a == \"object\") // if we got a real axis, extract number\n                a = a.n;\n            if (typeof a != \"number\")\n                a = 1; // default to first axis\n            return a;\n        }\n\n        function allAxes() {\n            // return flat array without annoying null entries\n            return $.grep(xaxes.concat(yaxes), function (a) { return a; });\n        }\n\n        function canvasToAxisCoords(pos) {\n            // return an object with x/y corresponding to all used axes\n            var res = {}, i, axis;\n            for (i = 0; i < xaxes.length; ++i) {\n                axis = xaxes[i];\n                if (axis && axis.used)\n                    res[\"x\" + axis.n] = axis.c2p(pos.left);\n            }\n\n            for (i = 0; i < yaxes.length; ++i) {\n                axis = yaxes[i];\n                if (axis && axis.used)\n                    res[\"y\" + axis.n] = axis.c2p(pos.top);\n            }\n\n            if (res.x1 !== undefined)\n                res.x = res.x1;\n            if (res.y1 !== undefined)\n                res.y = res.y1;\n\n            return res;\n        }\n\n        function axisToCanvasCoords(pos) {\n            // get canvas coords from the first pair of x/y found in pos\n            var res = {}, i, axis, key;\n\n            for (i = 0; i < xaxes.length; ++i) {\n                axis = xaxes[i];\n                if (axis && axis.used) {\n                    key = \"x\" + axis.n;\n                    if (pos[key] == null && axis.n == 1)\n                        key = \"x\";\n\n                    if (pos[key] != null) {\n                        res.left = axis.p2c(pos[key]);\n                        break;\n                    }\n                }\n            }\n\n            for (i = 0; i < yaxes.length; ++i) {\n                axis = yaxes[i];\n                if (axis && axis.used) {\n                    key = \"y\" + axis.n;\n                    if (pos[key] == null && axis.n == 1)\n                        key = \"y\";\n\n                    if (pos[key] != null) {\n                        res.top = axis.p2c(pos[key]);\n                        break;\n                    }\n                }\n            }\n\n            return res;\n        }\n\n        function getOrCreateAxis(axes, number) {\n            if (!axes[number - 1])\n                axes[number - 1] = {\n                    n: number, // save the number for future reference\n                    direction: axes == xaxes ? \"x\" : \"y\",\n                    options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)\n                };\n\n            return axes[number - 1];\n        }\n\n        function fillInSeriesOptions() {\n            var i;\n\n            // collect what we already got of colors\n            var neededColors = series.length,\n                usedColors = [],\n                assignedColors = [];\n            for (i = 0; i < series.length; ++i) {\n                var sc = series[i].color;\n                if (sc != null) {\n                    --neededColors;\n                    if (typeof sc == \"number\")\n                        assignedColors.push(sc);\n                    else\n                        usedColors.push($.color.parse(series[i].color));\n                }\n            }\n\n            // we might need to generate more colors if higher indices\n            // are assigned\n            for (i = 0; i < assignedColors.length; ++i) {\n                neededColors = Math.max(neededColors, assignedColors[i] + 1);\n            }\n\n            // produce colors as needed\n            var colors = [], variation = 0;\n            i = 0;\n            while (colors.length < neededColors) {\n                var c;\n                if (options.colors.length == i) // check degenerate case\n                    c = $.color.make(100, 100, 100);\n                else\n                    c = $.color.parse(options.colors[i]);\n\n                // vary color if needed\n                var sign = variation % 2 == 1 ? -1 : 1;\n                c.scale('rgb', 1 + sign * Math.ceil(variation / 2) * 0.2)\n\n                // FIXME: if we're getting to close to something else,\n                // we should probably skip this one\n                colors.push(c);\n\n                ++i;\n                if (i >= options.colors.length) {\n                    i = 0;\n                    ++variation;\n                }\n            }\n\n            // fill in the options\n            var colori = 0, s;\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n\n                // assign colors\n                if (s.color == null) {\n                    s.color = colors[colori].toString();\n                    ++colori;\n                }\n                else if (typeof s.color == \"number\")\n                    s.color = colors[s.color].toString();\n\n                // turn on lines automatically in case nothing is set\n                if (s.lines.show == null) {\n                    var v, show = true;\n                    for (v in s)\n                        if (s[v] && s[v].show) {\n                            show = false;\n                            break;\n                        }\n                    if (show)\n                        s.lines.show = true;\n                }\n\n                // setup axes\n                s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, \"x\"));\n                s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, \"y\"));\n            }\n        }\n\n        function processData() {\n            var topSentry = Number.POSITIVE_INFINITY,\n                bottomSentry = Number.NEGATIVE_INFINITY,\n                fakeInfinity = Number.MAX_VALUE,\n                i, j, k, m, length,\n                s, points, ps, x, y, axis, val, f, p;\n\n            function updateAxis(axis, min, max) {\n                if (min < axis.datamin && min != -fakeInfinity)\n                    axis.datamin = min;\n                if (max > axis.datamax && max != fakeInfinity)\n                    axis.datamax = max;\n            }\n\n            $.each(allAxes(), function (_, axis) {\n                // init axis\n                axis.datamin = topSentry;\n                axis.datamax = bottomSentry;\n                axis.used = false;\n            });\n\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n                s.datapoints = { points: [] };\n\n                executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);\n            }\n\n            // first pass: clean and copy data\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n\n                var data = s.data, format = s.datapoints.format;\n\n                if (!format) {\n                    format = [];\n                    // find out how to copy\n                    format.push({ x: true, number: true, required: true });\n                    format.push({ y: true, number: true, required: true });\n\n                    if (s.bars.show || (s.lines.show && s.lines.fill)) {\n                        format.push({ y: true, number: true, required: false, defaultValue: 0 });\n                        if (s.bars.horizontal) {\n                            delete format[format.length - 1].y;\n                            format[format.length - 1].x = true;\n                        }\n                    }\n\n                    s.datapoints.format = format;\n                }\n\n                if (s.datapoints.pointsize != null)\n                    continue; // already filled in\n\n                s.datapoints.pointsize = format.length;\n\n                ps = s.datapoints.pointsize;\n                points = s.datapoints.points;\n\n                insertSteps = s.lines.show && s.lines.steps;\n                s.xaxis.used = s.yaxis.used = true;\n\n                for (j = k = 0; j < data.length; ++j, k += ps) {\n                    p = data[j];\n\n                    var nullify = p == null;\n                    if (!nullify) {\n                        for (m = 0; m < ps; ++m) {\n                            val = p[m];\n                            f = format[m];\n\n                            if (f) {\n                                if (f.number && val != null) {\n                                    val = +val; // convert to number\n                                    if (isNaN(val))\n                                        val = null;\n                                    else if (val == Infinity)\n                                        val = fakeInfinity;\n                                    else if (val == -Infinity)\n                                        val = -fakeInfinity;\n                                }\n\n                                if (val == null) {\n                                    if (f.required)\n                                        nullify = true;\n\n                                    if (f.defaultValue != null)\n                                        val = f.defaultValue;\n                                }\n                            }\n\n                            points[k + m] = val;\n                        }\n                    }\n\n                    if (nullify) {\n                        for (m = 0; m < ps; ++m) {\n                            val = points[k + m];\n                            if (val != null) {\n                                f = format[m];\n                                // extract min/max info\n                                if (f.x)\n                                    updateAxis(s.xaxis, val, val);\n                                if (f.y)\n                                    updateAxis(s.yaxis, val, val);\n                            }\n                            points[k + m] = null;\n                        }\n                    }\n                    else {\n                        // a little bit of line specific stuff that\n                        // perhaps shouldn't be here, but lacking\n                        // better means...\n                        if (insertSteps && k > 0\n                            && points[k - ps] != null\n                            && points[k - ps] != points[k]\n                            && points[k - ps + 1] != points[k + 1]) {\n                            // copy the point to make room for a middle point\n                            for (m = 0; m < ps; ++m)\n                                points[k + ps + m] = points[k + m];\n\n                            // middle point has same y\n                            points[k + 1] = points[k - ps + 1];\n\n                            // we've added a point, better reflect that\n                            k += ps;\n                        }\n                    }\n                }\n            }\n\n            // give the hooks a chance to run\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n\n                executeHooks(hooks.processDatapoints, [ s, s.datapoints]);\n            }\n\n            // second pass: find datamax/datamin for auto-scaling\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n                points = s.datapoints.points,\n                ps = s.datapoints.pointsize;\n\n                var xmin = topSentry, ymin = topSentry,\n                    xmax = bottomSentry, ymax = bottomSentry;\n\n                for (j = 0; j < points.length; j += ps) {\n                    if (points[j] == null)\n                        continue;\n\n                    for (m = 0; m < ps; ++m) {\n                        val = points[j + m];\n                        f = format[m];\n                        if (!f || val == fakeInfinity || val == -fakeInfinity)\n                            continue;\n\n                        if (f.x) {\n                            if (val < xmin)\n                                xmin = val;\n                            if (val > xmax)\n                                xmax = val;\n                        }\n                        if (f.y) {\n                            if (val < ymin)\n                                ymin = val;\n                            if (val > ymax)\n                                ymax = val;\n                        }\n                    }\n                }\n\n                if (s.bars.show) {\n                    // make sure we got room for the bar on the dancing floor\n                    var delta = s.bars.align == \"left\" ? 0 : -s.bars.barWidth/2;\n                    if (s.bars.horizontal) {\n                        ymin += delta;\n                        ymax += delta + s.bars.barWidth;\n                    }\n                    else {\n                        xmin += delta;\n                        xmax += delta + s.bars.barWidth;\n                    }\n                }\n\n                updateAxis(s.xaxis, xmin, xmax);\n                updateAxis(s.yaxis, ymin, ymax);\n            }\n\n            $.each(allAxes(), function (_, axis) {\n                if (axis.datamin == topSentry)\n                    axis.datamin = null;\n                if (axis.datamax == bottomSentry)\n                    axis.datamax = null;\n            });\n        }\n\n        function makeCanvas(skipPositioning, cls) {\n            var c = document.createElement('canvas');\n            c.className = cls;\n            c.width = canvasWidth;\n            c.height = canvasHeight;\n\n            if (!skipPositioning)\n                $(c).css({ position: 'absolute', left: 0, top: 0 });\n\n            $(c).appendTo(placeholder);\n\n            if (!c.getContext) // excanvas hack\n                c = window.G_vmlCanvasManager.initElement(c);\n\n            // used for resetting in case we get replotted\n            c.getContext(\"2d\").save();\n\n            return c;\n        }\n\n        function getCanvasDimensions() {\n            canvasWidth = placeholder.width();\n            canvasHeight = placeholder.height();\n\n            if (canvasWidth <= 0 || canvasHeight <= 0)\n                throw \"Invalid dimensions for plot, width = \" + canvasWidth + \", height = \" + canvasHeight;\n        }\n\n        function resizeCanvas(c) {\n            // resizing should reset the state (excanvas seems to be\n            // buggy though)\n            if (c.width != canvasWidth)\n                c.width = canvasWidth;\n\n            if (c.height != canvasHeight)\n                c.height = canvasHeight;\n\n            // so try to get back to the initial state (even if it's\n            // gone now, this should be safe according to the spec)\n            var cctx = c.getContext(\"2d\");\n            cctx.restore();\n\n            // and save again\n            cctx.save();\n        }\n\n        function setupCanvases() {\n            var reused,\n                existingCanvas = placeholder.children(\"canvas.base\"),\n                existingOverlay = placeholder.children(\"canvas.overlay\");\n\n            if (existingCanvas.length == 0 || existingOverlay == 0) {\n                // init everything\n\n                placeholder.html(\"\"); // make sure placeholder is clear\n\n                placeholder.css({ padding: 0 }); // padding messes up the positioning\n\n                if (placeholder.css(\"position\") == 'static')\n                    placeholder.css(\"position\", \"relative\"); // for positioning labels and overlay\n\n                getCanvasDimensions();\n\n                canvas = makeCanvas(true, \"base\");\n                overlay = makeCanvas(false, \"overlay\"); // overlay canvas for interactive features\n\n                reused = false;\n            }\n            else {\n                // reuse existing elements\n\n                canvas = existingCanvas.get(0);\n                overlay = existingOverlay.get(0);\n\n                reused = true;\n            }\n\n            ctx = canvas.getContext(\"2d\");\n            octx = overlay.getContext(\"2d\");\n\n            // we include the canvas in the event holder too, because IE 7\n            // sometimes has trouble with the stacking order\n            eventHolder = $([overlay, canvas]);\n\n            if (reused) {\n                // run shutdown in the old plot object\n                placeholder.data(\"plot\").shutdown();\n\n                // reset reused canvases\n                plot.resize();\n\n                // make sure overlay pixels are cleared (canvas is cleared when we redraw)\n                octx.clearRect(0, 0, canvasWidth, canvasHeight);\n\n                // then whack any remaining obvious garbage left\n                eventHolder.unbind();\n                placeholder.children().not([canvas, overlay]).remove();\n            }\n\n            // save in case we get replotted\n            placeholder.data(\"plot\", plot);\n        }\n\n        function bindEvents() {\n            // bind events\n            if (options.grid.hoverable) {\n                eventHolder.mousemove(onMouseMove);\n                eventHolder.mouseleave(onMouseLeave);\n            }\n\n            if (options.grid.clickable)\n                eventHolder.click(onClick);\n\n            executeHooks(hooks.bindEvents, [eventHolder]);\n        }\n\n        function shutdown() {\n            if (redrawTimeout)\n                clearTimeout(redrawTimeout);\n\n            eventHolder.unbind(\"mousemove\", onMouseMove);\n            eventHolder.unbind(\"mouseleave\", onMouseLeave);\n            eventHolder.unbind(\"click\", onClick);\n\n            executeHooks(hooks.shutdown, [eventHolder]);\n        }\n\n        function setTransformationHelpers(axis) {\n            // set helper functions on the axis, assumes plot area\n            // has been computed already\n\n            function identity(x) { return x; }\n\n            var s, m, t = axis.options.transform || identity,\n                it = axis.options.inverseTransform;\n\n            // precompute how much the axis is scaling a point\n            // in canvas space\n            if (axis.direction == \"x\") {\n                s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));\n                m = Math.min(t(axis.max), t(axis.min));\n            }\n            else {\n                s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));\n                s = -s;\n                m = Math.max(t(axis.max), t(axis.min));\n            }\n\n            // data point to canvas coordinate\n            if (t == identity) // slight optimization\n                axis.p2c = function (p) { return (p - m) * s; };\n            else\n                axis.p2c = function (p) { return (t(p) - m) * s; };\n            // canvas coordinate to data point\n            if (!it)\n                axis.c2p = function (c) { return m + c / s; };\n            else\n                axis.c2p = function (c) { return it(m + c / s); };\n        }\n\n        function measureTickLabels(axis) {\n            var opts = axis.options, i, ticks = axis.ticks || [], labels = [],\n                l, w = opts.labelWidth, h = opts.labelHeight, dummyDiv;\n\n            function makeDummyDiv(labels, width) {\n                return $('<div style=\"position:absolute;top:-10000px;' + width + 'font-size:smaller\">' +\n                         '<div class=\"' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis\">'\n                         + labels.join(\"\") + '</div></div>')\n                    .appendTo(placeholder);\n            }\n\n            if (axis.direction == \"x\") {\n                // to avoid measuring the widths of the labels (it's slow), we\n                // construct fixed-size boxes and put the labels inside\n                // them, we don't need the exact figures and the\n                // fixed-size box content is easy to center\n                if (w == null)\n                    w = Math.floor(canvasWidth / (ticks.length > 0 ? ticks.length : 1));\n\n                // measure x label heights\n                if (h == null) {\n                    labels = [];\n                    for (i = 0; i < ticks.length; ++i) {\n                        l = ticks[i].label;\n                        if (l)\n                            labels.push('<div class=\"tickLabel\" style=\"float:left;width:' + w + 'px\">' + l + '</div>');\n                    }\n\n                    if (labels.length > 0) {\n                        // stick them all in the same div and measure\n                        // collective height\n                        labels.push('<div style=\"clear:left\"></div>');\n                        dummyDiv = makeDummyDiv(labels, \"width:10000px;\");\n                        h = dummyDiv.height();\n                        dummyDiv.remove();\n                    }\n                }\n            }\n            else if (w == null || h == null) {\n                // calculate y label dimensions\n                for (i = 0; i < ticks.length; ++i) {\n                    l = ticks[i].label;\n                    if (l)\n                        labels.push('<div class=\"tickLabel\">' + l + '</div>');\n                }\n\n                if (labels.length > 0) {\n                    dummyDiv = makeDummyDiv(labels, \"\");\n                    if (w == null)\n                        w = dummyDiv.children().width();\n                    if (h == null)\n                        h = dummyDiv.find(\"div.tickLabel\").height();\n                    dummyDiv.remove();\n                }\n            }\n\n            if (w == null)\n                w = 0;\n            if (h == null)\n                h = 0;\n\n            axis.labelWidth = w;\n            axis.labelHeight = h;\n        }\n\n        function allocateAxisBoxFirstPhase(axis) {\n            // find the bounding box of the axis by looking at label\n            // widths/heights and ticks, make room by diminishing the\n            // plotOffset\n\n            var lw = axis.labelWidth,\n                lh = axis.labelHeight,\n                pos = axis.options.position,\n                tickLength = axis.options.tickLength,\n                axismargin = options.grid.axisMargin,\n                padding = options.grid.labelMargin,\n                all = axis.direction == \"x\" ? xaxes : yaxes,\n                index;\n\n            // determine axis margin\n            var samePosition = $.grep(all, function (a) {\n                return a && a.options.position == pos && a.reserveSpace;\n            });\n            if ($.inArray(axis, samePosition) == samePosition.length - 1)\n                axismargin = 0; // outermost\n\n            // determine tick length - if we're innermost, we can use \"full\"\n            if (tickLength == null)\n                tickLength = \"full\";\n\n            var sameDirection = $.grep(all, function (a) {\n                return a && a.reserveSpace;\n            });\n\n            var innermost = $.inArray(axis, sameDirection) == 0;\n            if (!innermost && tickLength == \"full\")\n                tickLength = 5;\n\n            if (!isNaN(+tickLength))\n                padding += +tickLength;\n\n            // compute box\n            if (axis.direction == \"x\") {\n                lh += padding;\n\n                if (pos == \"bottom\") {\n                    plotOffset.bottom += lh + axismargin;\n                    axis.box = { top: canvasHeight - plotOffset.bottom, height: lh };\n                }\n                else {\n                    axis.box = { top: plotOffset.top + axismargin, height: lh };\n                    plotOffset.top += lh + axismargin;\n                }\n            }\n            else {\n                lw += padding;\n\n                if (pos == \"left\") {\n                    axis.box = { left: plotOffset.left + axismargin, width: lw };\n                    plotOffset.left += lw + axismargin;\n                }\n                else {\n                    plotOffset.right += lw + axismargin;\n                    axis.box = { left: canvasWidth - plotOffset.right, width: lw };\n                }\n            }\n\n             // save for future reference\n            axis.position = pos;\n            axis.tickLength = tickLength;\n            axis.box.padding = padding;\n            axis.innermost = innermost;\n        }\n\n        function allocateAxisBoxSecondPhase(axis) {\n            // set remaining bounding box coordinates\n            if (axis.direction == \"x\") {\n                axis.box.left = plotOffset.left;\n                axis.box.width = plotWidth;\n            }\n            else {\n                axis.box.top = plotOffset.top;\n                axis.box.height = plotHeight;\n            }\n        }\n\n        function setupGrid() {\n            var i, axes = allAxes();\n\n            // first calculate the plot and axis box dimensions\n\n            $.each(axes, function (_, axis) {\n                axis.show = axis.options.show;\n                if (axis.show == null)\n                    axis.show = axis.used; // by default an axis is visible if it's got data\n\n                axis.reserveSpace = axis.show || axis.options.reserveSpace;\n\n                setRange(axis);\n            });\n\n            allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });\n\n            plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = 0;\n            if (options.grid.show) {\n                $.each(allocatedAxes, function (_, axis) {\n                    // make the ticks\n                    setupTickGeneration(axis);\n                    setTicks(axis);\n                    snapRangeToTicks(axis, axis.ticks);\n\n                    // find labelWidth/Height for axis\n                    measureTickLabels(axis);\n                });\n\n                // with all dimensions in house, we can compute the\n                // axis boxes, start from the outside (reverse order)\n                for (i = allocatedAxes.length - 1; i >= 0; --i)\n                    allocateAxisBoxFirstPhase(allocatedAxes[i]);\n\n                // make sure we've got enough space for things that\n                // might stick out\n                var minMargin = options.grid.minBorderMargin;\n                if (minMargin == null) {\n                    minMargin = 0;\n                    for (i = 0; i < series.length; ++i)\n                        minMargin = Math.max(minMargin, series[i].points.radius + series[i].points.lineWidth/2);\n                }\n\n                for (var a in plotOffset) {\n                    plotOffset[a] += options.grid.borderWidth;\n                    plotOffset[a] = Math.max(minMargin, plotOffset[a]);\n                }\n            }\n\n            plotWidth = canvasWidth - plotOffset.left - plotOffset.right;\n            plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;\n\n            // now we got the proper plotWidth/Height, we can compute the scaling\n            $.each(axes, function (_, axis) {\n                setTransformationHelpers(axis);\n            });\n\n            if (options.grid.show) {\n                $.each(allocatedAxes, function (_, axis) {\n                    allocateAxisBoxSecondPhase(axis);\n                });\n\n                insertAxisLabels();\n            }\n\n            insertLegend();\n        }\n\n        function setRange(axis) {\n            var opts = axis.options,\n                min = +(opts.min != null ? opts.min : axis.datamin),\n                max = +(opts.max != null ? opts.max : axis.datamax),\n                delta = max - min;\n\n            if (delta == 0.0) {\n                // degenerate case\n                var widen = max == 0 ? 1 : 0.01;\n\n                if (opts.min == null)\n                    min -= widen;\n                // always widen max if we couldn't widen min to ensure we\n                // don't fall into min == max which doesn't work\n                if (opts.max == null || opts.min != null)\n                    max += widen;\n            }\n            else {\n                // consider autoscaling\n                var margin = opts.autoscaleMargin;\n                if (margin != null) {\n                    if (opts.min == null) {\n                        min -= delta * margin;\n                        // make sure we don't go below zero if all values\n                        // are positive\n                        if (min < 0 && axis.datamin != null && axis.datamin >= 0)\n                            min = 0;\n                    }\n                    if (opts.max == null) {\n                        max += delta * margin;\n                        if (max > 0 && axis.datamax != null && axis.datamax <= 0)\n                            max = 0;\n                    }\n                }\n            }\n            axis.min = min;\n            axis.max = max;\n        }\n\n        function setupTickGeneration(axis) {\n            var opts = axis.options;\n\n            // estimate number of ticks\n            var noTicks;\n            if (typeof opts.ticks == \"number\" && opts.ticks > 0)\n                noTicks = opts.ticks;\n            else\n                // heuristic based on the model a*sqrt(x) fitted to\n                // some data points that seemed reasonable\n                noTicks = 0.3 * Math.sqrt(axis.direction == \"x\" ? canvasWidth : canvasHeight);\n\n            var delta = (axis.max - axis.min) / noTicks,\n                size, generator, unit, formatter, i, magn, norm;\n\n            if (opts.mode == \"time\") {\n                // pretty handling of time\n\n                // map of app. size of time units in milliseconds\n                var timeUnitSize = {\n                    \"second\": 1000,\n                    \"minute\": 60 * 1000,\n                    \"hour\": 60 * 60 * 1000,\n                    \"day\": 24 * 60 * 60 * 1000,\n                    \"month\": 30 * 24 * 60 * 60 * 1000,\n                    \"year\": 365.2425 * 24 * 60 * 60 * 1000\n                };\n\n\n                // the allowed tick sizes, after 1 year we use\n                // an integer algorithm\n                var spec = [\n                    [1, \"second\"], [2, \"second\"], [5, \"second\"], [10, \"second\"],\n                    [30, \"second\"],\n                    [1, \"minute\"], [2, \"minute\"], [5, \"minute\"], [10, \"minute\"],\n                    [30, \"minute\"],\n                    [1, \"hour\"], [2, \"hour\"], [4, \"hour\"],\n                    [8, \"hour\"], [12, \"hour\"],\n                    [1, \"day\"], [2, \"day\"], [3, \"day\"],\n                    [0.25, \"month\"], [0.5, \"month\"], [1, \"month\"],\n                    [2, \"month\"], [3, \"month\"], [6, \"month\"],\n                    [1, \"year\"]\n                ];\n\n                var minSize = 0;\n                if (opts.minTickSize != null) {\n                    if (typeof opts.tickSize == \"number\")\n                        minSize = opts.tickSize;\n                    else\n                        minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];\n                }\n\n                for (var i = 0; i < spec.length - 1; ++i)\n                    if (delta < (spec[i][0] * timeUnitSize[spec[i][1]]\n                                 + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2\n                       && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize)\n                        break;\n                size = spec[i][0];\n                unit = spec[i][1];\n\n                // special-case the possibility of several years\n                if (unit == \"year\") {\n                    magn = Math.pow(10, Math.floor(Math.log(delta / timeUnitSize.year) / Math.LN10));\n                    norm = (delta / timeUnitSize.year) / magn;\n                    if (norm < 1.5)\n                        size = 1;\n                    else if (norm < 3)\n                        size = 2;\n                    else if (norm < 7.5)\n                        size = 5;\n                    else\n                        size = 10;\n\n                    size *= magn;\n                }\n\n                axis.tickSize = opts.tickSize || [size, unit];\n\n                generator = function(axis) {\n                    var ticks = [],\n                        tickSize = axis.tickSize[0], unit = axis.tickSize[1],\n                        d = new Date(axis.min);\n\n                    var step = tickSize * timeUnitSize[unit];\n\n                    if (unit == \"second\")\n                        d.setUTCSeconds(floorInBase(d.getUTCSeconds(), tickSize));\n                    if (unit == \"minute\")\n                        d.setUTCMinutes(floorInBase(d.getUTCMinutes(), tickSize));\n                    if (unit == \"hour\")\n                        d.setUTCHours(floorInBase(d.getUTCHours(), tickSize));\n                    if (unit == \"month\")\n                        d.setUTCMonth(floorInBase(d.getUTCMonth(), tickSize));\n                    if (unit == \"year\")\n                        d.setUTCFullYear(floorInBase(d.getUTCFullYear(), tickSize));\n\n                    // reset smaller components\n                    d.setUTCMilliseconds(0);\n                    if (step >= timeUnitSize.minute)\n                        d.setUTCSeconds(0);\n                    if (step >= timeUnitSize.hour)\n                        d.setUTCMinutes(0);\n                    if (step >= timeUnitSize.day)\n                        d.setUTCHours(0);\n                    if (step >= timeUnitSize.day * 4)\n                        d.setUTCDate(1);\n                    if (step >= timeUnitSize.year)\n                        d.setUTCMonth(0);\n\n\n                    var carry = 0, v = Number.NaN, prev;\n                    do {\n                        prev = v;\n                        v = d.getTime();\n                        ticks.push(v);\n                        if (unit == \"month\") {\n                            if (tickSize < 1) {\n                                // a bit complicated - we'll divide the month\n                                // up but we need to take care of fractions\n                                // so we don't end up in the middle of a day\n                                d.setUTCDate(1);\n                                var start = d.getTime();\n                                d.setUTCMonth(d.getUTCMonth() + 1);\n                                var end = d.getTime();\n                                d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);\n                                carry = d.getUTCHours();\n                                d.setUTCHours(0);\n                            }\n                            else\n                                d.setUTCMonth(d.getUTCMonth() + tickSize);\n                        }\n                        else if (unit == \"year\") {\n                            d.setUTCFullYear(d.getUTCFullYear() + tickSize);\n                        }\n                        else\n                            d.setTime(v + step);\n                    } while (v < axis.max && v != prev);\n\n                    return ticks;\n                };\n\n                formatter = function (v, axis) {\n                    var d = new Date(v);\n\n                    // first check global format\n                    if (opts.timeformat != null)\n                        return $.plot.formatDate(d, opts.timeformat, opts.monthNames);\n\n                    var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];\n                    var span = axis.max - axis.min;\n                    var suffix = (opts.twelveHourClock) ? \" %p\" : \"\";\n\n                    if (t < timeUnitSize.minute)\n                        fmt = \"%h:%M:%S\" + suffix;\n                    else if (t < timeUnitSize.day) {\n                        if (span < 2 * timeUnitSize.day)\n                            fmt = \"%h:%M\" + suffix;\n                        else\n                            fmt = \"%b %d %h:%M\" + suffix;\n                    }\n                    else if (t < timeUnitSize.month)\n                        fmt = \"%b %d\";\n                    else if (t < timeUnitSize.year) {\n                        if (span < timeUnitSize.year)\n                            fmt = \"%b\";\n                        else\n                            fmt = \"%b %y\";\n                    }\n                    else\n                        fmt = \"%y\";\n\n                    return $.plot.formatDate(d, fmt, opts.monthNames);\n                };\n            }\n            else {\n                // pretty rounding of base-10 numbers\n                var maxDec = opts.tickDecimals;\n                var dec = -Math.floor(Math.log(delta) / Math.LN10);\n                if (maxDec != null && dec > maxDec)\n                    dec = maxDec;\n\n                magn = Math.pow(10, -dec);\n                norm = delta / magn; // norm is between 1.0 and 10.0\n\n                if (norm < 1.5)\n                    size = 1;\n                else if (norm < 3) {\n                    size = 2;\n                    // special case for 2.5, requires an extra decimal\n                    if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {\n                        size = 2.5;\n                        ++dec;\n                    }\n                }\n                else if (norm < 7.5)\n                    size = 5;\n                else\n                    size = 10;\n\n                size *= magn;\n\n                if (opts.minTickSize != null && size < opts.minTickSize)\n                    size = opts.minTickSize;\n\n                axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);\n                axis.tickSize = opts.tickSize || size;\n\n                generator = function (axis) {\n                    var ticks = [];\n\n                    // spew out all possible ticks\n                    var start = floorInBase(axis.min, axis.tickSize),\n                        i = 0, v = Number.NaN, prev;\n                    do {\n                        prev = v;\n                        v = start + i * axis.tickSize;\n                        ticks.push(v);\n                        ++i;\n                    } while (v < axis.max && v != prev);\n                    return ticks;\n                };\n\n                formatter = function (v, axis) {\n                    return v.toFixed(axis.tickDecimals);\n                };\n            }\n\n            if (opts.alignTicksWithAxis != null) {\n                var otherAxis = (axis.direction == \"x\" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];\n                if (otherAxis && otherAxis.used && otherAxis != axis) {\n                    // consider snapping min/max to outermost nice ticks\n                    var niceTicks = generator(axis);\n                    if (niceTicks.length > 0) {\n                        if (opts.min == null)\n                            axis.min = Math.min(axis.min, niceTicks[0]);\n                        if (opts.max == null && niceTicks.length > 1)\n                            axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);\n                    }\n\n                    generator = function (axis) {\n                        // copy ticks, scaled to this axis\n                        var ticks = [], v, i;\n                        for (i = 0; i < otherAxis.ticks.length; ++i) {\n                            v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);\n                            v = axis.min + v * (axis.max - axis.min);\n                            ticks.push(v);\n                        }\n                        return ticks;\n                    };\n\n                    // we might need an extra decimal since forced\n                    // ticks don't necessarily fit naturally\n                    if (axis.mode != \"time\" && opts.tickDecimals == null) {\n                        var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1),\n                            ts = generator(axis);\n\n                        // only proceed if the tick interval rounded\n                        // with an extra decimal doesn't give us a\n                        // zero at end\n                        if (!(ts.length > 1 && /\\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))\n                            axis.tickDecimals = extraDec;\n                    }\n                }\n            }\n\n            axis.tickGenerator = generator;\n            if ($.isFunction(opts.tickFormatter))\n                axis.tickFormatter = function (v, axis) { return \"\" + opts.tickFormatter(v, axis); };\n            else\n                axis.tickFormatter = formatter;\n        }\n\n        function setTicks(axis) {\n            var oticks = axis.options.ticks, ticks = [];\n            if (oticks == null || (typeof oticks == \"number\" && oticks > 0))\n                ticks = axis.tickGenerator(axis);\n            else if (oticks) {\n                if ($.isFunction(oticks))\n                    // generate the ticks\n                    ticks = oticks({ min: axis.min, max: axis.max });\n                else\n                    ticks = oticks;\n            }\n\n            // clean up/labelify the supplied ticks, copy them over\n            var i, v;\n            axis.ticks = [];\n            for (i = 0; i < ticks.length; ++i) {\n                var label = null;\n                var t = ticks[i];\n                if (typeof t == \"object\") {\n                    v = +t[0];\n                    if (t.length > 1)\n                        label = t[1];\n                }\n                else\n                    v = +t;\n                if (label == null)\n                    label = axis.tickFormatter(v, axis);\n                if (!isNaN(v))\n                    axis.ticks.push({ v: v, label: label });\n            }\n        }\n\n        function snapRangeToTicks(axis, ticks) {\n            if (axis.options.autoscaleMargin && ticks.length > 0) {\n                // snap to ticks\n                if (axis.options.min == null)\n                    axis.min = Math.min(axis.min, ticks[0].v);\n                if (axis.options.max == null && ticks.length > 1)\n                    axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);\n            }\n        }\n\n        function draw() {\n            ctx.clearRect(0, 0, canvasWidth, canvasHeight);\n\n            var grid = options.grid;\n\n            // draw background, if any\n            if (grid.show && grid.backgroundColor)\n                drawBackground();\n\n            if (grid.show && !grid.aboveData)\n                drawGrid();\n\n            for (var i = 0; i < series.length; ++i) {\n                executeHooks(hooks.drawSeries, [ctx, series[i]]);\n                drawSeries(series[i]);\n            }\n\n            executeHooks(hooks.draw, [ctx]);\n\n            if (grid.show && grid.aboveData)\n                drawGrid();\n        }\n\n        function extractRange(ranges, coord) {\n            var axis, from, to, key, axes = allAxes();\n\n            for (i = 0; i < axes.length; ++i) {\n                axis = axes[i];\n                if (axis.direction == coord) {\n                    key = coord + axis.n + \"axis\";\n                    if (!ranges[key] && axis.n == 1)\n                        key = coord + \"axis\"; // support x1axis as xaxis\n                    if (ranges[key]) {\n                        from = ranges[key].from;\n                        to = ranges[key].to;\n                        break;\n                    }\n                }\n            }\n\n            // backwards-compat stuff - to be removed in future\n            if (!ranges[key]) {\n                axis = coord == \"x\" ? xaxes[0] : yaxes[0];\n                from = ranges[coord + \"1\"];\n                to = ranges[coord + \"2\"];\n            }\n\n            // auto-reverse as an added bonus\n            if (from != null && to != null && from > to) {\n                var tmp = from;\n                from = to;\n                to = tmp;\n            }\n\n            return { from: from, to: to, axis: axis };\n        }\n\n        function drawBackground() {\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, \"rgba(255, 255, 255, 0)\");\n            ctx.fillRect(0, 0, plotWidth, plotHeight);\n            ctx.restore();\n        }\n\n        function drawGrid() {\n            var i;\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            // draw markings\n            var markings = options.grid.markings;\n            if (markings) {\n                if ($.isFunction(markings)) {\n                    var axes = plot.getAxes();\n                    // xmin etc. is backwards compatibility, to be\n                    // removed in the future\n                    axes.xmin = axes.xaxis.min;\n                    axes.xmax = axes.xaxis.max;\n                    axes.ymin = axes.yaxis.min;\n                    axes.ymax = axes.yaxis.max;\n\n                    markings = markings(axes);\n                }\n\n                for (i = 0; i < markings.length; ++i) {\n                    var m = markings[i],\n                        xrange = extractRange(m, \"x\"),\n                        yrange = extractRange(m, \"y\");\n\n                    // fill in missing\n                    if (xrange.from == null)\n                        xrange.from = xrange.axis.min;\n                    if (xrange.to == null)\n                        xrange.to = xrange.axis.max;\n                    if (yrange.from == null)\n                        yrange.from = yrange.axis.min;\n                    if (yrange.to == null)\n                        yrange.to = yrange.axis.max;\n\n                    // clip\n                    if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||\n                        yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)\n                        continue;\n\n                    xrange.from = Math.max(xrange.from, xrange.axis.min);\n                    xrange.to = Math.min(xrange.to, xrange.axis.max);\n                    yrange.from = Math.max(yrange.from, yrange.axis.min);\n                    yrange.to = Math.min(yrange.to, yrange.axis.max);\n\n                    if (xrange.from == xrange.to && yrange.from == yrange.to)\n                        continue;\n\n                    // then draw\n                    xrange.from = xrange.axis.p2c(xrange.from);\n                    xrange.to = xrange.axis.p2c(xrange.to);\n                    yrange.from = yrange.axis.p2c(yrange.from);\n                    yrange.to = yrange.axis.p2c(yrange.to);\n\n                    if (xrange.from == xrange.to || yrange.from == yrange.to) {\n                        // draw line\n                        ctx.beginPath();\n                        ctx.strokeStyle = m.color || options.grid.markingsColor;\n                        ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;\n                        ctx.moveTo(xrange.from, yrange.from);\n                        ctx.lineTo(xrange.to, yrange.to);\n                        ctx.stroke();\n                    }\n                    else {\n                        // fill area\n                        ctx.fillStyle = m.color || options.grid.markingsColor;\n                        ctx.fillRect(xrange.from, yrange.to,\n                                     xrange.to - xrange.from,\n                                     yrange.from - yrange.to);\n                    }\n                }\n            }\n\n            // draw the ticks\n            var axes = allAxes(), bw = options.grid.borderWidth;\n\n            for (var j = 0; j < axes.length; ++j) {\n                var axis = axes[j], box = axis.box,\n                    t = axis.tickLength, x, y, xoff, yoff;\n                if (!axis.show || axis.ticks.length == 0)\n                    continue\n\n                ctx.strokeStyle = axis.options.tickColor || $.color.parse(axis.options.color).scale('a', 0.22).toString();\n                ctx.lineWidth = 1;\n\n                // find the edges\n                if (axis.direction == \"x\") {\n                    x = 0;\n                    if (t == \"full\")\n                        y = (axis.position == \"top\" ? 0 : plotHeight);\n                    else\n                        y = box.top - plotOffset.top + (axis.position == \"top\" ? box.height : 0);\n                }\n                else {\n                    y = 0;\n                    if (t == \"full\")\n                        x = (axis.position == \"left\" ? 0 : plotWidth);\n                    else\n                        x = box.left - plotOffset.left + (axis.position == \"left\" ? box.width : 0);\n                }\n\n                // draw tick bar\n                if (!axis.innermost) {\n                    ctx.beginPath();\n                    xoff = yoff = 0;\n                    if (axis.direction == \"x\")\n                        xoff = plotWidth;\n                    else\n                        yoff = plotHeight;\n\n                    if (ctx.lineWidth == 1) {\n                        x = Math.floor(x) + 0.5;\n                        y = Math.floor(y) + 0.5;\n                    }\n\n                    ctx.moveTo(x, y);\n                    ctx.lineTo(x + xoff, y + yoff);\n                    ctx.stroke();\n                }\n\n                // draw ticks\n                ctx.beginPath();\n                for (i = 0; i < axis.ticks.length; ++i) {\n                    var v = axis.ticks[i].v;\n\n                    xoff = yoff = 0;\n\n                    if (v < axis.min || v > axis.max\n                        // skip those lying on the axes if we got a border\n                        || (t == \"full\" && bw > 0\n                            && (v == axis.min || v == axis.max)))\n                        continue;\n\n                    if (axis.direction == \"x\") {\n                        x = axis.p2c(v);\n                        yoff = t == \"full\" ? -plotHeight : t;\n\n                        if (axis.position == \"top\")\n                            yoff = -yoff;\n                    }\n                    else {\n                        y = axis.p2c(v);\n                        xoff = t == \"full\" ? -plotWidth : t;\n\n                        if (axis.position == \"left\")\n                            xoff = -xoff;\n                    }\n\n                    if (ctx.lineWidth == 1) {\n                        if (axis.direction == \"x\")\n                            x = Math.floor(x) + 0.5;\n                        else\n                            y = Math.floor(y) + 0.5;\n                    }\n\n                    ctx.moveTo(x, y);\n                    ctx.lineTo(x + xoff, y + yoff);\n                }\n\n                ctx.stroke();\n            }\n\n\n            // draw border\n            if (bw) {\n                ctx.lineWidth = bw;\n                ctx.strokeStyle = options.grid.borderColor;\n                ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);\n            }\n\n            ctx.restore();\n        }\n\n        function insertAxisLabels() {\n            placeholder.find(\".tickLabels\").remove();\n\n            var html = ['<div class=\"tickLabels\" style=\"font-size:smaller\">'];\n\n            var axes = allAxes();\n            for (var j = 0; j < axes.length; ++j) {\n                var axis = axes[j], box = axis.box;\n                if (!axis.show)\n                    continue;\n                //debug: html.push('<div style=\"position:absolute;opacity:0.10;background-color:red;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width +  'px;height:' + box.height + 'px\"></div>')\n                html.push('<div class=\"' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis\" style=\"color:' + axis.options.color + '\">');\n                for (var i = 0; i < axis.ticks.length; ++i) {\n                    var tick = axis.ticks[i];\n                    if (!tick.label || tick.v < axis.min || tick.v > axis.max)\n                        continue;\n\n                    var pos = {}, align;\n\n                    if (axis.direction == \"x\") {\n                        align = \"center\";\n                        pos.left = Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2);\n                        if (axis.position == \"bottom\")\n                            pos.top = box.top + box.padding;\n                        else\n                            pos.bottom = canvasHeight - (box.top + box.height - box.padding);\n                    }\n                    else {\n                        pos.top = Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2);\n                        if (axis.position == \"left\") {\n                            pos.right = canvasWidth - (box.left + box.width - box.padding)\n                            align = \"right\";\n                        }\n                        else {\n                            pos.left = box.left + box.padding;\n                            align = \"left\";\n                        }\n                    }\n\n                    pos.width = axis.labelWidth;\n\n                    var style = [\"position:absolute\", \"text-align:\" + align ];\n                    for (var a in pos)\n                        style.push(a + \":\" + pos[a] + \"px\")\n\n                    html.push('<div class=\"tickLabel\" style=\"' + style.join(';') + '\">' + tick.label + '</div>');\n                }\n                html.push('</div>');\n            }\n\n            html.push('</div>');\n\n            placeholder.append(html.join(\"\"));\n        }\n\n        function drawSeries(series) {\n            if (series.lines.show)\n                drawSeriesLines(series);\n            if (series.bars.show)\n                drawSeriesBars(series);\n            if (series.points.show)\n                drawSeriesPoints(series);\n        }\n\n        function drawSeriesLines(series) {\n            function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {\n                var points = datapoints.points,\n                    ps = datapoints.pointsize,\n                    prevx = null, prevy = null;\n\n                ctx.beginPath();\n                for (var i = ps; i < points.length; i += ps) {\n                    var x1 = points[i - ps], y1 = points[i - ps + 1],\n                        x2 = points[i], y2 = points[i + 1];\n\n                    if (x1 == null || x2 == null)\n                        continue;\n\n                    // clip with ymin\n                    if (y1 <= y2 && y1 < axisy.min) {\n                        if (y2 < axisy.min)\n                            continue;   // line segment is outside\n                        // compute new intersection point\n                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.min;\n                    }\n                    else if (y2 <= y1 && y2 < axisy.min) {\n                        if (y1 < axisy.min)\n                            continue;\n                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.min;\n                    }\n\n                    // clip with ymax\n                    if (y1 >= y2 && y1 > axisy.max) {\n                        if (y2 > axisy.max)\n                            continue;\n                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.max;\n                    }\n                    else if (y2 >= y1 && y2 > axisy.max) {\n                        if (y1 > axisy.max)\n                            continue;\n                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.max;\n                    }\n\n                    // clip with xmin\n                    if (x1 <= x2 && x1 < axisx.min) {\n                        if (x2 < axisx.min)\n                            continue;\n                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.min;\n                    }\n                    else if (x2 <= x1 && x2 < axisx.min) {\n                        if (x1 < axisx.min)\n                            continue;\n                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.min;\n                    }\n\n                    // clip with xmax\n                    if (x1 >= x2 && x1 > axisx.max) {\n                        if (x2 > axisx.max)\n                            continue;\n                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.max;\n                    }\n                    else if (x2 >= x1 && x2 > axisx.max) {\n                        if (x1 > axisx.max)\n                            continue;\n                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.max;\n                    }\n\n                    if (x1 != prevx || y1 != prevy)\n                        ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);\n\n                    prevx = x2;\n                    prevy = y2;\n                    ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);\n                }\n                ctx.stroke();\n            }\n\n            function plotLineArea(datapoints, axisx, axisy) {\n                var points = datapoints.points,\n                    ps = datapoints.pointsize,\n                    bottom = Math.min(Math.max(0, axisy.min), axisy.max),\n                    i = 0, top, areaOpen = false,\n                    ypos = 1, segmentStart = 0, segmentEnd = 0;\n\n                // we process each segment in two turns, first forward\n                // direction to sketch out top, then once we hit the\n                // end we go backwards to sketch the bottom\n                while (true) {\n                    if (ps > 0 && i > points.length + ps)\n                        break;\n\n                    i += ps; // ps is negative if going backwards\n\n                    var x1 = points[i - ps],\n                        y1 = points[i - ps + ypos],\n                        x2 = points[i], y2 = points[i + ypos];\n\n                    if (areaOpen) {\n                        if (ps > 0 && x1 != null && x2 == null) {\n                            // at turning point\n                            segmentEnd = i;\n                            ps = -ps;\n                            ypos = 2;\n                            continue;\n                        }\n\n                        if (ps < 0 && i == segmentStart + ps) {\n                            // done with the reverse sweep\n                            ctx.fill();\n                            areaOpen = false;\n                            ps = -ps;\n                            ypos = 1;\n                            i = segmentStart = segmentEnd + ps;\n                            continue;\n                        }\n                    }\n\n                    if (x1 == null || x2 == null)\n                        continue;\n\n                    // clip x values\n\n                    // clip with xmin\n                    if (x1 <= x2 && x1 < axisx.min) {\n                        if (x2 < axisx.min)\n                            continue;\n                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.min;\n                    }\n                    else if (x2 <= x1 && x2 < axisx.min) {\n                        if (x1 < axisx.min)\n                            continue;\n                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.min;\n                    }\n\n                    // clip with xmax\n                    if (x1 >= x2 && x1 > axisx.max) {\n                        if (x2 > axisx.max)\n                            continue;\n                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.max;\n                    }\n                    else if (x2 >= x1 && x2 > axisx.max) {\n                        if (x1 > axisx.max)\n                            continue;\n                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.max;\n                    }\n\n                    if (!areaOpen) {\n                        // open area\n                        ctx.beginPath();\n                        ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));\n                        areaOpen = true;\n                    }\n\n                    // now first check the case where both is outside\n                    if (y1 >= axisy.max && y2 >= axisy.max) {\n                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));\n                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));\n                        continue;\n                    }\n                    else if (y1 <= axisy.min && y2 <= axisy.min) {\n                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));\n                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));\n                        continue;\n                    }\n\n                    // else it's a bit more complicated, there might\n                    // be a flat maxed out rectangle first, then a\n                    // triangular cutout or reverse; to find these\n                    // keep track of the current x values\n                    var x1old = x1, x2old = x2;\n\n                    // clip the y values, without shortcutting, we\n                    // go through all cases in turn\n\n                    // clip with ymin\n                    if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {\n                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.min;\n                    }\n                    else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {\n                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.min;\n                    }\n\n                    // clip with ymax\n                    if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {\n                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.max;\n                    }\n                    else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {\n                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.max;\n                    }\n\n                    // if the x value was changed we got a rectangle\n                    // to fill\n                    if (x1 != x1old) {\n                        ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));\n                        // it goes to (x1, y1), but we fill that below\n                    }\n\n                    // fill triangular section, this sometimes result\n                    // in redundant points if (x1, y1) hasn't changed\n                    // from previous line to, but we just ignore that\n                    ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));\n                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));\n\n                    // fill the other rectangle if it's there\n                    if (x2 != x2old) {\n                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));\n                        ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));\n                    }\n                }\n            }\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n            ctx.lineJoin = \"round\";\n\n            var lw = series.lines.lineWidth,\n                sw = series.shadowSize;\n            // FIXME: consider another form of shadow when filling is turned on\n            if (lw > 0 && sw > 0) {\n                // draw shadow as a thick and thin line with transparency\n                ctx.lineWidth = sw;\n                ctx.strokeStyle = \"rgba(0,0,0,0.1)\";\n                // position shadow at angle from the mid of line\n                var angle = Math.PI/18;\n                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);\n                ctx.lineWidth = sw/2;\n                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);\n            }\n\n            ctx.lineWidth = lw;\n            ctx.strokeStyle = series.color;\n            var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);\n            if (fillStyle) {\n                ctx.fillStyle = fillStyle;\n                plotLineArea(series.datapoints, series.xaxis, series.yaxis);\n            }\n\n            if (lw > 0)\n                plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);\n            ctx.restore();\n        }\n\n        function drawSeriesPoints(series) {\n            function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {\n                var points = datapoints.points, ps = datapoints.pointsize;\n\n                for (var i = 0; i < points.length; i += ps) {\n                    var x = points[i], y = points[i + 1];\n                    if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)\n                        continue;\n\n                    ctx.beginPath();\n                    x = axisx.p2c(x);\n                    y = axisy.p2c(y) + offset;\n                    if (symbol == \"circle\")\n                        ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);\n                    else\n                        symbol(ctx, x, y, radius, shadow);\n                    ctx.closePath();\n\n                    if (fillStyle) {\n                        ctx.fillStyle = fillStyle;\n                        ctx.fill();\n                    }\n                    ctx.stroke();\n                }\n            }\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            var lw = series.points.lineWidth,\n                sw = series.shadowSize,\n                radius = series.points.radius,\n                symbol = series.points.symbol;\n            if (lw > 0 && sw > 0) {\n                // draw shadow in two steps\n                var w = sw / 2;\n                ctx.lineWidth = w;\n                ctx.strokeStyle = \"rgba(0,0,0,0.1)\";\n                plotPoints(series.datapoints, radius, null, w + w/2, true,\n                           series.xaxis, series.yaxis, symbol);\n\n                ctx.strokeStyle = \"rgba(0,0,0,0.2)\";\n                plotPoints(series.datapoints, radius, null, w/2, true,\n                           series.xaxis, series.yaxis, symbol);\n            }\n\n            ctx.lineWidth = lw;\n            ctx.strokeStyle = series.color;\n            plotPoints(series.datapoints, radius,\n                       getFillStyle(series.points, series.color), 0, false,\n                       series.xaxis, series.yaxis, symbol);\n            ctx.restore();\n        }\n\n        function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {\n            var left, right, bottom, top,\n                drawLeft, drawRight, drawTop, drawBottom,\n                tmp;\n\n            // in horizontal mode, we start the bar from the left\n            // instead of from the bottom so it appears to be\n            // horizontal rather than vertical\n            if (horizontal) {\n                drawBottom = drawRight = drawTop = true;\n                drawLeft = false;\n                left = b;\n                right = x;\n                top = y + barLeft;\n                bottom = y + barRight;\n\n                // account for negative bars\n                if (right < left) {\n                    tmp = right;\n                    right = left;\n                    left = tmp;\n                    drawLeft = true;\n                    drawRight = false;\n                }\n            }\n            else {\n                drawLeft = drawRight = drawTop = true;\n                drawBottom = false;\n                left = x + barLeft;\n                right = x + barRight;\n                bottom = b;\n                top = y;\n\n                // account for negative bars\n                if (top < bottom) {\n                    tmp = top;\n                    top = bottom;\n                    bottom = tmp;\n                    drawBottom = true;\n                    drawTop = false;\n                }\n            }\n\n            // clip\n            if (right < axisx.min || left > axisx.max ||\n                top < axisy.min || bottom > axisy.max)\n                return;\n\n            if (left < axisx.min) {\n                left = axisx.min;\n                drawLeft = false;\n            }\n\n            if (right > axisx.max) {\n                right = axisx.max;\n                drawRight = false;\n            }\n\n            if (bottom < axisy.min) {\n                bottom = axisy.min;\n                drawBottom = false;\n            }\n\n            if (top > axisy.max) {\n                top = axisy.max;\n                drawTop = false;\n            }\n\n            left = axisx.p2c(left);\n            bottom = axisy.p2c(bottom);\n            right = axisx.p2c(right);\n            top = axisy.p2c(top);\n\n            // fill the bar\n            if (fillStyleCallback) {\n                c.beginPath();\n                c.moveTo(left, bottom);\n                c.lineTo(left, top);\n                c.lineTo(right, top);\n                c.lineTo(right, bottom);\n                c.fillStyle = fillStyleCallback(bottom, top);\n                c.fill();\n            }\n\n            // draw outline\n            if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {\n                c.beginPath();\n\n                // FIXME: inline moveTo is buggy with excanvas\n                c.moveTo(left, bottom + offset);\n                if (drawLeft)\n                    c.lineTo(left, top + offset);\n                else\n                    c.moveTo(left, top + offset);\n                if (drawTop)\n                    c.lineTo(right, top + offset);\n                else\n                    c.moveTo(right, top + offset);\n                if (drawRight)\n                    c.lineTo(right, bottom + offset);\n                else\n                    c.moveTo(right, bottom + offset);\n                if (drawBottom)\n                    c.lineTo(left, bottom + offset);\n                else\n                    c.moveTo(left, bottom + offset);\n                c.stroke();\n            }\n        }\n\n        function drawSeriesBars(series) {\n            function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) {\n                var points = datapoints.points, ps = datapoints.pointsize;\n\n                for (var i = 0; i < points.length; i += ps) {\n                    if (points[i] == null)\n                        continue;\n                    drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);\n                }\n            }\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            // FIXME: figure out a way to add shadows (for instance along the right edge)\n            ctx.lineWidth = series.bars.lineWidth;\n            ctx.strokeStyle = series.color;\n            var barLeft = series.bars.align == \"left\" ? 0 : -series.bars.barWidth/2;\n            var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;\n            plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);\n            ctx.restore();\n        }\n\n        function getFillStyle(filloptions, seriesColor, bottom, top) {\n            var fill = filloptions.fill;\n            if (!fill)\n                return null;\n\n            if (filloptions.fillColor)\n                return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);\n\n            var c = $.color.parse(seriesColor);\n            c.a = typeof fill == \"number\" ? fill : 0.4;\n            c.normalize();\n            return c.toString();\n        }\n\n        function insertLegend() {\n            placeholder.find(\".legend\").remove();\n\n            if (!options.legend.show)\n                return;\n\n            var fragments = [], rowStarted = false,\n                lf = options.legend.labelFormatter, s, label;\n            for (var i = 0; i < series.length; ++i) {\n                s = series[i];\n                label = s.label;\n                if (!label)\n                    continue;\n\n                if (i % options.legend.noColumns == 0) {\n                    if (rowStarted)\n                        fragments.push('</tr>');\n                    fragments.push('<tr>');\n                    rowStarted = true;\n                }\n\n                if (lf)\n                    label = lf(label, s);\n\n                fragments.push(\n                    '<td class=\"legendColorBox\"><div style=\"border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px\"><div style=\"width:4px;height:0;border:5px solid ' + s.color + ';overflow:hidden\"></div></div></td>' +\n                    '<td class=\"legendLabel\">' + label + '</td>');\n            }\n            if (rowStarted)\n                fragments.push('</tr>');\n\n            if (fragments.length == 0)\n                return;\n\n            var table = '<table style=\"font-size:smaller;color:' + options.grid.color + '\">' + fragments.join(\"\") + '</table>';\n            if (options.legend.container != null)\n                $(options.legend.container).html(table);\n            else {\n                var pos = \"\",\n                    p = options.legend.position,\n                    m = options.legend.margin;\n                if (m[0] == null)\n                    m = [m, m];\n                if (p.charAt(0) == \"n\")\n                    pos += 'top:' + (m[1] + plotOffset.top) + 'px;';\n                else if (p.charAt(0) == \"s\")\n                    pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';\n                if (p.charAt(1) == \"e\")\n                    pos += 'right:' + (m[0] + plotOffset.right) + 'px;';\n                else if (p.charAt(1) == \"w\")\n                    pos += 'left:' + (m[0] + plotOffset.left) + 'px;';\n                var legend = $('<div class=\"legend\">' + table.replace('style=\"', 'style=\"position:absolute;' + pos +';') + '</div>').appendTo(placeholder);\n                if (options.legend.backgroundOpacity != 0.0) {\n                    // put in the transparent background\n                    // separately to avoid blended labels and\n                    // label boxes\n                    var c = options.legend.backgroundColor;\n                    if (c == null) {\n                        c = options.grid.backgroundColor;\n                        if (c && typeof c == \"string\")\n                            c = $.color.parse(c);\n                        else\n                            c = $.color.extract(legend, 'background-color');\n                        c.a = 1;\n                        c = c.toString();\n                    }\n                    var div = legend.children();\n                    $('<div style=\"position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';\"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);\n                }\n            }\n        }\n\n\n        // interactive features\n\n        var highlights = [],\n            redrawTimeout = null;\n\n        // returns the data item the mouse is over, or null if none is found\n        function findNearbyItem(mouseX, mouseY, seriesFilter) {\n            var maxDistance = options.grid.mouseActiveRadius,\n                smallestDistance = maxDistance * maxDistance + 1,\n                item = null, foundPoint = false, i, j;\n\n            for (i = series.length - 1; i >= 0; --i) {\n                if (!seriesFilter(series[i]))\n                    continue;\n\n                var s = series[i],\n                    axisx = s.xaxis,\n                    axisy = s.yaxis,\n                    points = s.datapoints.points,\n                    ps = s.datapoints.pointsize,\n                    mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster\n                    my = axisy.c2p(mouseY),\n                    maxx = maxDistance / axisx.scale,\n                    maxy = maxDistance / axisy.scale;\n\n                // with inverse transforms, we can't use the maxx/maxy\n                // optimization, sadly\n                if (axisx.options.inverseTransform)\n                    maxx = Number.MAX_VALUE;\n                if (axisy.options.inverseTransform)\n                    maxy = Number.MAX_VALUE;\n\n                if (s.lines.show || s.points.show) {\n                    for (j = 0; j < points.length; j += ps) {\n                        var x = points[j], y = points[j + 1];\n                        if (x == null)\n                            continue;\n\n                        // For points and lines, the cursor must be within a\n                        // certain distance to the data point\n                        if (x - mx > maxx || x - mx < -maxx ||\n                            y - my > maxy || y - my < -maxy)\n                            continue;\n\n                        // We have to calculate distances in pixels, not in\n                        // data units, because the scales of the axes may be different\n                        var dx = Math.abs(axisx.p2c(x) - mouseX),\n                            dy = Math.abs(axisy.p2c(y) - mouseY),\n                            dist = dx * dx + dy * dy; // we save the sqrt\n\n                        // use <= to ensure last point takes precedence\n                        // (last generally means on top of)\n                        if (dist < smallestDistance) {\n                            smallestDistance = dist;\n                            item = [i, j / ps];\n                        }\n                    }\n                }\n\n                if (s.bars.show && !item) { // no other point can be nearby\n                    var barLeft = s.bars.align == \"left\" ? 0 : -s.bars.barWidth/2,\n                        barRight = barLeft + s.bars.barWidth;\n\n                    for (j = 0; j < points.length; j += ps) {\n                        var x = points[j], y = points[j + 1], b = points[j + 2];\n                        if (x == null)\n                            continue;\n\n                        // for a bar graph, the cursor must be inside the bar\n                        if (series[i].bars.horizontal ?\n                            (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&\n                             my >= y + barLeft && my <= y + barRight) :\n                            (mx >= x + barLeft && mx <= x + barRight &&\n                             my >= Math.min(b, y) && my <= Math.max(b, y)))\n                                item = [i, j / ps];\n                    }\n                }\n            }\n\n            if (item) {\n                i = item[0];\n                j = item[1];\n                ps = series[i].datapoints.pointsize;\n\n                return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),\n                         dataIndex: j,\n                         series: series[i],\n                         seriesIndex: i };\n            }\n\n            return null;\n        }\n\n        function onMouseMove(e) {\n            if (options.grid.hoverable)\n                triggerClickHoverEvent(\"plothover\", e,\n                                       function (s) { return s[\"hoverable\"] != false; });\n        }\n\n        function onMouseLeave(e) {\n            if (options.grid.hoverable)\n                triggerClickHoverEvent(\"plothover\", e,\n                                       function (s) { return false; });\n        }\n\n        function onClick(e) {\n            triggerClickHoverEvent(\"plotclick\", e,\n                                   function (s) { return s[\"clickable\"] != false; });\n        }\n\n        // trigger click or hover event (they send the same parameters\n        // so we share their code)\n        function triggerClickHoverEvent(eventname, event, seriesFilter) {\n            var offset = eventHolder.offset(),\n                canvasX = event.pageX - offset.left - plotOffset.left,\n                canvasY = event.pageY - offset.top - plotOffset.top,\n            pos = canvasToAxisCoords({ left: canvasX, top: canvasY });\n\n            pos.pageX = event.pageX;\n            pos.pageY = event.pageY;\n\n            var item = findNearbyItem(canvasX, canvasY, seriesFilter);\n\n            if (item) {\n                // fill in mouse pos for any listeners out there\n                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left);\n                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top);\n            }\n\n            if (options.grid.autoHighlight) {\n                // clear auto-highlights\n                for (var i = 0; i < highlights.length; ++i) {\n                    var h = highlights[i];\n                    if (h.auto == eventname &&\n                        !(item && h.series == item.series &&\n                          h.point[0] == item.datapoint[0] &&\n                          h.point[1] == item.datapoint[1]))\n                        unhighlight(h.series, h.point);\n                }\n\n                if (item)\n                    highlight(item.series, item.datapoint, eventname);\n            }\n\n            placeholder.trigger(eventname, [ pos, item ]);\n        }\n\n        function triggerRedrawOverlay() {\n            if (!redrawTimeout)\n                redrawTimeout = setTimeout(drawOverlay, 30);\n        }\n\n        function drawOverlay() {\n            redrawTimeout = null;\n\n            // draw highlights\n            octx.save();\n            octx.clearRect(0, 0, canvasWidth, canvasHeight);\n            octx.translate(plotOffset.left, plotOffset.top);\n\n            var i, hi;\n            for (i = 0; i < highlights.length; ++i) {\n                hi = highlights[i];\n\n                if (hi.series.bars.show)\n                    drawBarHighlight(hi.series, hi.point);\n                else\n                    drawPointHighlight(hi.series, hi.point);\n            }\n            octx.restore();\n\n            executeHooks(hooks.drawOverlay, [octx]);\n        }\n\n        function highlight(s, point, auto) {\n            if (typeof s == \"number\")\n                s = series[s];\n\n            if (typeof point == \"number\") {\n                var ps = s.datapoints.pointsize;\n                point = s.datapoints.points.slice(ps * point, ps * (point + 1));\n            }\n\n            var i = indexOfHighlight(s, point);\n            if (i == -1) {\n                highlights.push({ series: s, point: point, auto: auto });\n\n                triggerRedrawOverlay();\n            }\n            else if (!auto)\n                highlights[i].auto = false;\n        }\n\n        function unhighlight(s, point) {\n            if (s == null && point == null) {\n                highlights = [];\n                triggerRedrawOverlay();\n            }\n\n            if (typeof s == \"number\")\n                s = series[s];\n\n            if (typeof point == \"number\")\n                point = s.data[point];\n\n            var i = indexOfHighlight(s, point);\n            if (i != -1) {\n                highlights.splice(i, 1);\n\n                triggerRedrawOverlay();\n            }\n        }\n\n        function indexOfHighlight(s, p) {\n            for (var i = 0; i < highlights.length; ++i) {\n                var h = highlights[i];\n                if (h.series == s && h.point[0] == p[0]\n                    && h.point[1] == p[1])\n                    return i;\n            }\n            return -1;\n        }\n\n        function drawPointHighlight(series, point) {\n            var x = point[0], y = point[1],\n                axisx = series.xaxis, axisy = series.yaxis;\n\n            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)\n                return;\n\n            var pointRadius = series.points.radius + series.points.lineWidth / 2;\n            octx.lineWidth = pointRadius;\n            octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();\n            var radius = 1.5 * pointRadius,\n                x = axisx.p2c(x),\n                y = axisy.p2c(y);\n\n            octx.beginPath();\n            if (series.points.symbol == \"circle\")\n                octx.arc(x, y, radius, 0, 2 * Math.PI, false);\n            else\n                series.points.symbol(octx, x, y, radius, false);\n            octx.closePath();\n            octx.stroke();\n        }\n\n        function drawBarHighlight(series, point) {\n            octx.lineWidth = series.bars.lineWidth;\n            octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();\n            var fillStyle = $.color.parse(series.color).scale('a', 0.5).toString();\n            var barLeft = series.bars.align == \"left\" ? 0 : -series.bars.barWidth/2;\n            drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,\n                    0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);\n        }\n\n        function getColorOrGradient(spec, bottom, top, defaultColor) {\n            if (typeof spec == \"string\")\n                return spec;\n            else {\n                // assume this is a gradient spec; IE currently only\n                // supports a simple vertical gradient properly, so that's\n                // what we support too\n                var gradient = ctx.createLinearGradient(0, top, 0, bottom);\n\n                for (var i = 0, l = spec.colors.length; i < l; ++i) {\n                    var c = spec.colors[i];\n                    if (typeof c != \"string\") {\n                        var co = $.color.parse(defaultColor);\n                        if (c.brightness != null)\n                            co = co.scale('rgb', c.brightness)\n                        if (c.opacity != null)\n                            co.a *= c.opacity;\n                        c = co.toString();\n                    }\n                    gradient.addColorStop(i / (l - 1), c);\n                }\n\n                return gradient;\n            }\n        }\n    }\n\n    $.plot = function(placeholder, data, options) {\n        //var t0 = new Date();\n        var plot = new Plot($(placeholder), data, options, $.plot.plugins);\n        //(window.console ? console.log : alert)(\"time used (msecs): \" + ((new Date()).getTime() - t0.getTime()));\n        return plot;\n    };\n\n    $.plot.version = \"0.7\";\n\n    $.plot.plugins = [];\n\n    // returns a string with the date d formatted according to fmt\n    $.plot.formatDate = function(d, fmt, monthNames) {\n        var leftPad = function(n) {\n            n = \"\" + n;\n            return n.length == 1 ? \"0\" + n : n;\n        };\n\n        var r = [];\n        var escape = false, padNext = false;\n        var hours = d.getUTCHours();\n        var isAM = hours < 12;\n        if (monthNames == null)\n            monthNames = [\"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\"];\n\n        if (fmt.search(/%p|%P/) != -1) {\n            if (hours > 12) {\n                hours = hours - 12;\n            } else if (hours == 0) {\n                hours = 12;\n            }\n        }\n        for (var i = 0; i < fmt.length; ++i) {\n            var c = fmt.charAt(i);\n\n            if (escape) {\n                switch (c) {\n                case 'h': c = \"\" + hours; break;\n                case 'H': c = leftPad(hours); break;\n                case 'M': c = leftPad(d.getUTCMinutes()); break;\n                case 'S': c = leftPad(d.getUTCSeconds()); break;\n                case 'd': c = \"\" + d.getUTCDate(); break;\n                case 'm': c = \"\" + (d.getUTCMonth() + 1); break;\n                case 'y': c = \"\" + d.getUTCFullYear(); break;\n                case 'b': c = \"\" + monthNames[d.getUTCMonth()]; break;\n                case 'p': c = (isAM) ? (\"\" + \"am\") : (\"\" + \"pm\"); break;\n                case 'P': c = (isAM) ? (\"\" + \"AM\") : (\"\" + \"PM\"); break;\n                case '0': c = \"\"; padNext = true; break;\n                }\n                if (c && padNext) {\n                    c = leftPad(c);\n                    padNext = false;\n                }\n                r.push(c);\n                if (!padNext)\n                    escape = false;\n            }\n            else {\n                if (c == \"%\")\n                    escape = true;\n                else\n                    r.push(c);\n            }\n        }\n        return r.join(\"\");\n    };\n\n    // round to nearby lower multiple of base\n    function floorInBase(n, base) {\n        return base * Math.floor(n / base);\n    }\n\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/flot/jquery.flot.pie.js",
    "content": "/*\nFlot plugin for rendering pie charts. The plugin assumes the data is\ncoming is as a single data value for each series, and each of those\nvalues is a positive value or zero (negative numbers don't make\nany sense and will cause strange effects). The data values do\nNOT need to be passed in as percentage values because it\ninternally calculates the total and percentages.\n\n* Created by Brian Medendorp, June 2009\n* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars\n\n* Changes:\n\t2009-10-22: lineJoin set to round\n\t2009-10-23: IE full circle fix, donut\n\t2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera\n\t2009-11-17: Added IE hover capability submitted by Anthony Aragues\n\t2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)\n\n\nAvailable options are:\nseries: {\n\tpie: {\n\t\tshow: true/false\n\t\tradius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'\n\t\tinnerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect\n\t\tstartAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result\n\t\ttilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)\n\t\toffset: {\n\t\t\ttop: integer value to move the pie up or down\n\t\t\tleft: integer value to move the pie left or right, or 'auto'\n\t\t},\n\t\tstroke: {\n\t\t\tcolor: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')\n\t\t\twidth: integer pixel width of the stroke\n\t\t},\n\t\tlabel: {\n\t\t\tshow: true/false, or 'auto'\n\t\t\tformatter:  a user-defined function that modifies the text/style of the label text\n\t\t\tradius: 0-1 for percentage of fullsize, or a specified pixel length\n\t\t\tbackground: {\n\t\t\t\tcolor: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')\n\t\t\t\topacity: 0-1\n\t\t\t},\n\t\t\tthreshold: 0-1 for the percentage value at which to hide labels (if they're too small)\n\t\t},\n\t\tcombine: {\n\t\t\tthreshold: 0-1 for the percentage value at which to combine slices (if they're too small)\n\t\t\tcolor: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined\n\t\t\tlabel: any text value of what the combined slice should be labeled\n\t\t}\n\t\thighlight: {\n\t\t\topacity: 0-1\n\t\t}\n\t}\n}\n\nMore detail and specific examples can be found in the included HTML file.\n\n*/\n\n(function ($)\n{\n\tfunction init(plot) // this is the \"body\" of the plugin\n\t{\n\t\tvar canvas = null;\n\t\tvar target = null;\n\t\tvar maxRadius = null;\n\t\tvar centerLeft = null;\n\t\tvar centerTop = null;\n\t\tvar total = 0;\n\t\tvar redraw = true;\n\t\tvar redrawAttempts = 10;\n\t\tvar shrink = 0.95;\n\t\tvar legendWidth = 0;\n\t\tvar processed = false;\n\t\tvar raw = false;\n\n\t\t// interactive variables\n\t\tvar highlights = [];\n\n\t\t// add hook to determine if pie plugin in enabled, and then perform necessary operations\n\t\tplot.hooks.processOptions.push(checkPieEnabled);\n\t\tplot.hooks.bindEvents.push(bindEvents);\n\n\t\t// check to see if the pie plugin is enabled\n\t\tfunction checkPieEnabled(plot, options)\n\t\t{\n\t\t\tif (options.series.pie.show)\n\t\t\t{\n\t\t\t\t//disable grid\n\t\t\t\toptions.grid.show = false;\n\n\t\t\t\t// set labels.show\n\t\t\t\tif (options.series.pie.label.show=='auto')\n\t\t\t\t\tif (options.legend.show)\n\t\t\t\t\t\toptions.series.pie.label.show = false;\n\t\t\t\t\telse\n\t\t\t\t\t\toptions.series.pie.label.show = true;\n\n\t\t\t\t// set radius\n\t\t\t\tif (options.series.pie.radius=='auto')\n\t\t\t\t\tif (options.series.pie.label.show)\n\t\t\t\t\t\toptions.series.pie.radius = 3/4;\n\t\t\t\t\telse\n\t\t\t\t\t\toptions.series.pie.radius = 1;\n\n\t\t\t\t// ensure sane tilt\n\t\t\t\tif (options.series.pie.tilt>1)\n\t\t\t\t\toptions.series.pie.tilt=1;\n\t\t\t\tif (options.series.pie.tilt<0)\n\t\t\t\t\toptions.series.pie.tilt=0;\n\n\t\t\t\t// add processData hook to do transformations on the data\n\t\t\t\tplot.hooks.processDatapoints.push(processDatapoints);\n\t\t\t\tplot.hooks.drawOverlay.push(drawOverlay);\n\n\t\t\t\t// add draw hook\n\t\t\t\tplot.hooks.draw.push(draw);\n\t\t\t}\n\t\t}\n\n\t\t// bind hoverable events\n\t\tfunction bindEvents(plot, eventHolder)\n\t\t{\n\t\t\tvar options = plot.getOptions();\n\n\t\t\tif (options.series.pie.show && options.grid.hoverable)\n\t\t\t\teventHolder.unbind('mousemove').mousemove(onMouseMove);\n\n\t\t\tif (options.series.pie.show && options.grid.clickable)\n\t\t\t\teventHolder.unbind('click').click(onClick);\n\t\t}\n\n\n\t\t// debugging function that prints out an object\n\t\tfunction alertObject(obj)\n\t\t{\n\t\t\tvar msg = '';\n\t\t\tfunction traverse(obj, depth)\n\t\t\t{\n\t\t\t\tif (!depth)\n\t\t\t\t\tdepth = 0;\n\t\t\t\tfor (var i = 0; i < obj.length; ++i)\n\t\t\t\t{\n\t\t\t\t\tfor (var j=0; j<depth; j++)\n\t\t\t\t\t\tmsg += '\\t';\n\n\t\t\t\t\tif( typeof obj[i] == \"object\")\n\t\t\t\t\t{\t// its an object\n\t\t\t\t\t\tmsg += ''+i+':\\n';\n\t\t\t\t\t\ttraverse(obj[i], depth+1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\t// its a value\n\t\t\t\t\t\tmsg += ''+i+': '+obj[i]+'\\n';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttraverse(obj);\n\t\t\talert(msg);\n\t\t}\n\n\t\tfunction calcTotal(data)\n\t\t{\n\t\t\tfor (var i = 0; i < data.length; ++i)\n\t\t\t{\n\t\t\t\tvar item = parseFloat(data[i].data[0][1]);\n\t\t\t\tif (item)\n\t\t\t\t\ttotal += item;\n\t\t\t}\n\t\t}\n\n\t\tfunction processDatapoints(plot, series, data, datapoints)\n\t\t{\n\t\t\tif (!processed)\n\t\t\t{\n\t\t\t\tprocessed = true;\n\n\t\t\t\tcanvas = plot.getCanvas();\n\t\t\t\ttarget = $(canvas).parent();\n\t\t\t\toptions = plot.getOptions();\n\n\t\t\t\tplot.setData(combine(plot.getData()));\n\t\t\t}\n\t\t}\n\n\t\tfunction setupPie()\n\t\t{\n\t\t\tlegendWidth = target.children().filter('.legend').children().width();\n\n\t\t\t// calculate maximum radius and center point\n\t\t\tmaxRadius =  Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;\n\t\t\tcenterTop = (canvas.height/2)+options.series.pie.offset.top;\n\t\t\tcenterLeft = (canvas.width/2);\n\n\t\t\tif (options.series.pie.offset.left=='auto')\n\t\t\t\tif (options.legend.position.match('w'))\n\t\t\t\t\tcenterLeft += legendWidth/2;\n\t\t\t\telse\n\t\t\t\t\tcenterLeft -= legendWidth/2;\n\t\t\telse\n\t\t\t\tcenterLeft += options.series.pie.offset.left;\n\n\t\t\tif (centerLeft<maxRadius)\n\t\t\t\tcenterLeft = maxRadius;\n\t\t\telse if (centerLeft>canvas.width-maxRadius)\n\t\t\t\tcenterLeft = canvas.width-maxRadius;\n\t\t}\n\n\t\tfunction fixData(data)\n\t\t{\n\t\t\tfor (var i = 0; i < data.length; ++i)\n\t\t\t{\n\t\t\t\tif (typeof(data[i].data)=='number')\n\t\t\t\t\tdata[i].data = [[1,data[i].data]];\n\t\t\t\telse if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')\n\t\t\t\t{\n\t\t\t\t\tif (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')\n\t\t\t\t\t\tdata[i].label = data[i].data.label; // fix weirdness coming from flot\n\t\t\t\t\tdata[i].data = [[1,0]];\n\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn data;\n\t\t}\n\n\t\tfunction combine(data)\n\t\t{\n\t\t\tdata = fixData(data);\n\t\t\tcalcTotal(data);\n\t\t\tvar combined = 0;\n\t\t\tvar numCombined = 0;\n\t\t\tvar color = options.series.pie.combine.color;\n\n\t\t\tvar newdata = [];\n\t\t\tfor (var i = 0; i < data.length; ++i)\n\t\t\t{\n\t\t\t\t// make sure its a number\n\t\t\t\tdata[i].data[0][1] = parseFloat(data[i].data[0][1]);\n\t\t\t\tif (!data[i].data[0][1])\n\t\t\t\t\tdata[i].data[0][1] = 0;\n\n\t\t\t\tif (data[i].data[0][1]/total<=options.series.pie.combine.threshold)\n\t\t\t\t{\n\t\t\t\t\tcombined += data[i].data[0][1];\n\t\t\t\t\tnumCombined++;\n\t\t\t\t\tif (!color)\n\t\t\t\t\t\tcolor = data[i].color;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnewdata.push({\n\t\t\t\t\t\tdata: [[1,data[i].data[0][1]]],\n\t\t\t\t\t\tcolor: data[i].color,\n\t\t\t\t\t\tlabel: data[i].label,\n\t\t\t\t\t\tangle: (data[i].data[0][1]*(Math.PI*2))/total,\n\t\t\t\t\t\tpercent: (data[i].data[0][1]/total*100)\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (numCombined>0)\n\t\t\t\tnewdata.push({\n\t\t\t\t\tdata: [[1,combined]],\n\t\t\t\t\tcolor: color,\n\t\t\t\t\tlabel: options.series.pie.combine.label,\n\t\t\t\t\tangle: (combined*(Math.PI*2))/total,\n\t\t\t\t\tpercent: (combined/total*100)\n\t\t\t\t});\n\t\t\treturn newdata;\n\t\t}\n\n\t\tfunction draw(plot, newCtx)\n\t\t{\n\t\t\tif (!target) return; // if no series were passed\n\t\t\tctx = newCtx;\n\n\t\t\tsetupPie();\n\t\t\tvar slices = plot.getData();\n\n\t\t\tvar attempts = 0;\n\t\t\twhile (redraw && attempts<redrawAttempts)\n\t\t\t{\n\t\t\t\tredraw = false;\n\t\t\t\tif (attempts>0)\n\t\t\t\t\tmaxRadius *= shrink;\n\t\t\t\tattempts += 1;\n\t\t\t\tclear();\n\t\t\t\tif (options.series.pie.tilt<=0.8)\n\t\t\t\t\tdrawShadow();\n\t\t\t\tdrawPie();\n\t\t\t}\n\t\t\tif (attempts >= redrawAttempts) {\n\t\t\t\tclear();\n\t\t\t\ttarget.prepend('<div class=\"error\">Could not draw pie with labels contained inside canvas</div>');\n\t\t\t}\n\n\t\t\tif ( plot.setSeries && plot.insertLegend )\n\t\t\t{\n\t\t\t\tplot.setSeries(slices);\n\t\t\t\tplot.insertLegend();\n\t\t\t}\n\n\t\t\t// we're actually done at this point, just defining internal functions at this point\n\n\t\t\tfunction clear()\n\t\t\t{\n\t\t\t\tctx.clearRect(0,0,canvas.width,canvas.height);\n\t\t\t\ttarget.children().filter('.pieLabel, .pieLabelBackground').remove();\n\t\t\t}\n\n\t\t\tfunction drawShadow()\n\t\t\t{\n\t\t\t\tvar shadowLeft = 5;\n\t\t\t\tvar shadowTop = 15;\n\t\t\t\tvar edge = 10;\n\t\t\t\tvar alpha = 0.02;\n\n\t\t\t\t// set radius\n\t\t\t\tif (options.series.pie.radius>1)\n\t\t\t\t\tvar radius = options.series.pie.radius;\n\t\t\t\telse\n\t\t\t\t\tvar radius = maxRadius * options.series.pie.radius;\n\n\t\t\t\tif (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)\n\t\t\t\t\treturn;\t// shadow would be outside canvas, so don't draw it\n\n\t\t\t\tctx.save();\n\t\t\t\tctx.translate(shadowLeft,shadowTop);\n\t\t\t\tctx.globalAlpha = alpha;\n\t\t\t\tctx.fillStyle = '#000';\n\n\t\t\t\t// center and rotate to starting position\n\t\t\t\tctx.translate(centerLeft,centerTop);\n\t\t\t\tctx.scale(1, options.series.pie.tilt);\n\n\t\t\t\t//radius -= edge;\n\t\t\t\tfor (var i=1; i<=edge; i++)\n\t\t\t\t{\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.arc(0,0,radius,0,Math.PI*2,false);\n\t\t\t\t\tctx.fill();\n\t\t\t\t\tradius -= i;\n\t\t\t\t}\n\n\t\t\t\tctx.restore();\n\t\t\t}\n\n\t\t\tfunction drawPie()\n\t\t\t{\n\t\t\t\tstartAngle = Math.PI*options.series.pie.startAngle;\n\n\t\t\t\t// set radius\n\t\t\t\tif (options.series.pie.radius>1)\n\t\t\t\t\tvar radius = options.series.pie.radius;\n\t\t\t\telse\n\t\t\t\t\tvar radius = maxRadius * options.series.pie.radius;\n\n\t\t\t\t// center and rotate to starting position\n\t\t\t\tctx.save();\n\t\t\t\tctx.translate(centerLeft,centerTop);\n\t\t\t\tctx.scale(1, options.series.pie.tilt);\n\t\t\t\t//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera\n\n\t\t\t\t// draw slices\n\t\t\t\tctx.save();\n\t\t\t\tvar currentAngle = startAngle;\n\t\t\t\tfor (var i = 0; i < slices.length; ++i)\n\t\t\t\t{\n\t\t\t\t\tslices[i].startAngle = currentAngle;\n\t\t\t\t\tdrawSlice(slices[i].angle, slices[i].color, true);\n\t\t\t\t}\n\t\t\t\tctx.restore();\n\n\t\t\t\t// draw slice outlines\n\t\t\t\tctx.save();\n\t\t\t\tctx.lineWidth = options.series.pie.stroke.width;\n\t\t\t\tcurrentAngle = startAngle;\n\t\t\t\tfor (var i = 0; i < slices.length; ++i)\n\t\t\t\t\tdrawSlice(slices[i].angle, options.series.pie.stroke.color, false);\n\t\t\t\tctx.restore();\n\n\t\t\t\t// draw donut hole\n\t\t\t\tdrawDonutHole(ctx);\n\n\t\t\t\t// draw labels\n\t\t\t\tif (options.series.pie.label.show)\n\t\t\t\t\tdrawLabels();\n\n\t\t\t\t// restore to original state\n\t\t\t\tctx.restore();\n\n\t\t\t\tfunction drawSlice(angle, color, fill)\n\t\t\t\t{\n\t\t\t\t\tif (angle<=0)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tif (fill)\n\t\t\t\t\t\tctx.fillStyle = color;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.strokeStyle = color;\n\t\t\t\t\t\tctx.lineJoin = 'round';\n\t\t\t\t\t}\n\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tif (Math.abs(angle - Math.PI*2) > 0.000000001)\n\t\t\t\t\t\tctx.moveTo(0,0); // Center of the pie\n\t\t\t\t\telse if ($.browser.msie)\n\t\t\t\t\t\tangle -= 0.0001;\n\t\t\t\t\t//ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera\n\t\t\t\t\tctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);\n\t\t\t\t\tctx.closePath();\n\t\t\t\t\t//ctx.rotate(angle); // This doesn't work properly in Opera\n\t\t\t\t\tcurrentAngle += angle;\n\n\t\t\t\t\tif (fill)\n\t\t\t\t\t\tctx.fill();\n\t\t\t\t\telse\n\t\t\t\t\t\tctx.stroke();\n\t\t\t\t}\n\n\t\t\t\tfunction drawLabels()\n\t\t\t\t{\n\t\t\t\t\tvar currentAngle = startAngle;\n\n\t\t\t\t\t// set radius\n\t\t\t\t\tif (options.series.pie.label.radius>1)\n\t\t\t\t\t\tvar radius = options.series.pie.label.radius;\n\t\t\t\t\telse\n\t\t\t\t\t\tvar radius = maxRadius * options.series.pie.label.radius;\n\n\t\t\t\t\tfor (var i = 0; i < slices.length; ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (slices[i].percent >= options.series.pie.label.threshold*100)\n\t\t\t\t\t\t\tdrawLabel(slices[i], currentAngle, i);\n\t\t\t\t\t\tcurrentAngle += slices[i].angle;\n\t\t\t\t\t}\n\n\t\t\t\t\tfunction drawLabel(slice, startAngle, index)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (slice.data[0][1]==0)\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t// format label text\n\t\t\t\t\t\tvar lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;\n\t\t\t\t\t\tif (lf)\n\t\t\t\t\t\t\ttext = lf(slice.label, slice);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\ttext = slice.label;\n\t\t\t\t\t\tif (plf)\n\t\t\t\t\t\t\ttext = plf(text, slice);\n\n\t\t\t\t\t\tvar halfAngle = ((startAngle+slice.angle) + startAngle)/2;\n\t\t\t\t\t\tvar x = centerLeft + Math.round(Math.cos(halfAngle) * radius);\n\t\t\t\t\t\tvar y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;\n\n\t\t\t\t\t\tvar html = '<span class=\"pieLabel\" id=\"pieLabel'+index+'\" style=\"position:absolute;top:' + y + 'px;left:' + x + 'px;\">' + text + \"</span>\";\n\t\t\t\t\t\ttarget.append(html);\n\t\t\t\t\t\tvar label = target.children('#pieLabel'+index);\n\t\t\t\t\t\tvar labelTop = (y - label.height()/2);\n\t\t\t\t\t\tvar labelLeft = (x - label.width()/2);\n\t\t\t\t\t\tlabel.css('top', labelTop);\n\t\t\t\t\t\tlabel.css('left', labelLeft);\n\n\t\t\t\t\t\t// check to make sure that the label is not outside the canvas\n\t\t\t\t\t\tif (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)\n\t\t\t\t\t\t\tredraw = true;\n\n\t\t\t\t\t\tif (options.series.pie.label.background.opacity != 0) {\n\t\t\t\t\t\t\t// put in the transparent background separately to avoid blended labels and label boxes\n\t\t\t\t\t\t\tvar c = options.series.pie.label.background.color;\n\t\t\t\t\t\t\tif (c == null) {\n\t\t\t\t\t\t\t\tc = slice.color;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tvar pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';\n\t\t\t\t\t\t\t$('<div class=\"pieLabelBackground\" style=\"position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';\"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);\n\t\t\t\t\t\t}\n\t\t\t\t\t} // end individual label function\n\t\t\t\t} // end drawLabels function\n\t\t\t} // end drawPie function\n\t\t} // end draw function\n\n\t\t// Placed here because it needs to be accessed from multiple locations\n\t\tfunction drawDonutHole(layer)\n\t\t{\n\t\t\t// draw donut hole\n\t\t\tif(options.series.pie.innerRadius > 0)\n\t\t\t{\n\t\t\t\t// subtract the center\n\t\t\t\tlayer.save();\n\t\t\t\tinnerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;\n\t\t\t\tlayer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color\n\t\t\t\tlayer.beginPath();\n\t\t\t\tlayer.fillStyle = options.series.pie.stroke.color;\n\t\t\t\tlayer.arc(0,0,innerRadius,0,Math.PI*2,false);\n\t\t\t\tlayer.fill();\n\t\t\t\tlayer.closePath();\n\t\t\t\tlayer.restore();\n\n\t\t\t\t// add inner stroke\n\t\t\t\tlayer.save();\n\t\t\t\tlayer.beginPath();\n\t\t\t\tlayer.strokeStyle = options.series.pie.stroke.color;\n\t\t\t\tlayer.arc(0,0,innerRadius,0,Math.PI*2,false);\n\t\t\t\tlayer.stroke();\n\t\t\t\tlayer.closePath();\n\t\t\t\tlayer.restore();\n\t\t\t\t// TODO: add extra shadow inside hole (with a mask) if the pie is tilted.\n\t\t\t}\n\t\t}\n\n\t\t//-- Additional Interactive related functions --\n\n\t\tfunction isPointInPoly(poly, pt)\n\t\t{\n\t\t\tfor(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)\n\t\t\t\t((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))\n\t\t\t\t&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])\n\t\t\t\t&& (c = !c);\n\t\t\treturn c;\n\t\t}\n\n\t\tfunction findNearbySlice(mouseX, mouseY)\n\t\t{\n\t\t\tvar slices = plot.getData(),\n\t\t\t\toptions = plot.getOptions(),\n\t\t\t\tradius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;\n\n\t\t\tfor (var i = 0; i < slices.length; ++i)\n\t\t\t{\n\t\t\t\tvar s = slices[i];\n\n\t\t\t\tif(s.pie.show)\n\t\t\t\t{\n\t\t\t\t\tctx.save();\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.moveTo(0,0); // Center of the pie\n\t\t\t\t\t//ctx.scale(1, options.series.pie.tilt);\t// this actually seems to break everything when here.\n\t\t\t\t\tctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);\n\t\t\t\t\tctx.closePath();\n\t\t\t\t\tx = mouseX-centerLeft;\n\t\t\t\t\ty = mouseY-centerTop;\n\t\t\t\t\tif(ctx.isPointInPath)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//alert('found slice!');\n\t\t\t\t\t\t\tctx.restore();\n\t\t\t\t\t\t\treturn {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// excanvas for IE doesn;t support isPointInPath, this is a workaround.\n\t\t\t\t\t\tp1X = (radius * Math.cos(s.startAngle));\n\t\t\t\t\t\tp1Y = (radius * Math.sin(s.startAngle));\n\t\t\t\t\t\tp2X = (radius * Math.cos(s.startAngle+(s.angle/4)));\n\t\t\t\t\t\tp2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));\n\t\t\t\t\t\tp3X = (radius * Math.cos(s.startAngle+(s.angle/2)));\n\t\t\t\t\t\tp3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));\n\t\t\t\t\t\tp4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));\n\t\t\t\t\t\tp4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));\n\t\t\t\t\t\tp5X = (radius * Math.cos(s.startAngle+s.angle));\n\t\t\t\t\t\tp5Y = (radius * Math.sin(s.startAngle+s.angle));\n\t\t\t\t\t\tarrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];\n\t\t\t\t\t\tarrPoint = [x,y];\n\t\t\t\t\t\t// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?\n\t\t\t\t\t\tif(isPointInPoly(arrPoly, arrPoint))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tctx.restore();\n\t\t\t\t\t\t\treturn {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tctx.restore();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tfunction onMouseMove(e)\n\t\t{\n\t\t\ttriggerClickHoverEvent('plothover', e);\n\t\t}\n\n        function onClick(e)\n\t\t{\n\t\t\ttriggerClickHoverEvent('plotclick', e);\n        }\n\n\t\t// trigger click or hover event (they send the same parameters so we share their code)\n\t\tfunction triggerClickHoverEvent(eventname, e)\n\t\t{\n\t\t\tvar offset = plot.offset(),\n\t\t\t\tcanvasX = parseInt(e.pageX - offset.left),\n\t\t\t\tcanvasY =  parseInt(e.pageY - offset.top),\n\t\t\t\titem = findNearbySlice(canvasX, canvasY);\n\n\t\t\tif (options.grid.autoHighlight)\n\t\t\t{\n\t\t\t\t// clear auto-highlights\n\t\t\t\tfor (var i = 0; i < highlights.length; ++i)\n\t\t\t\t{\n\t\t\t\t\tvar h = highlights[i];\n\t\t\t\t\tif (h.auto == eventname && !(item && h.series == item.series))\n\t\t\t\t\t\tunhighlight(h.series);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// highlight the slice\n\t\t\tif (item)\n\t\t\t    highlight(item.series, eventname);\n\n\t\t\t// trigger any hover bind events\n\t\t\tvar pos = { pageX: e.pageX, pageY: e.pageY };\n\t\t\ttarget.trigger(eventname, [ pos, item ]);\n\t\t}\n\n\t\tfunction highlight(s, auto)\n\t\t{\n\t\t\tif (typeof s == \"number\")\n\t\t\t\ts = series[s];\n\n\t\t\tvar i = indexOfHighlight(s);\n\t\t\tif (i == -1)\n\t\t\t{\n\t\t\t\thighlights.push({ series: s, auto: auto });\n\t\t\t\tplot.triggerRedrawOverlay();\n\t\t\t}\n\t\t\telse if (!auto)\n\t\t\t\thighlights[i].auto = false;\n\t\t}\n\n\t\tfunction unhighlight(s)\n\t\t{\n\t\t\tif (s == null)\n\t\t\t{\n\t\t\t\thighlights = [];\n\t\t\t\tplot.triggerRedrawOverlay();\n\t\t\t}\n\n\t\t\tif (typeof s == \"number\")\n\t\t\t\ts = series[s];\n\n\t\t\tvar i = indexOfHighlight(s);\n\t\t\tif (i != -1)\n\t\t\t{\n\t\t\t\thighlights.splice(i, 1);\n\t\t\t\tplot.triggerRedrawOverlay();\n\t\t\t}\n\t\t}\n\n\t\tfunction indexOfHighlight(s)\n\t\t{\n\t\t\tfor (var i = 0; i < highlights.length; ++i)\n\t\t\t{\n\t\t\t\tvar h = highlights[i];\n\t\t\t\tif (h.series == s)\n\t\t\t\t\treturn i;\n\t\t\t}\n\t\t\treturn -1;\n\t\t}\n\n\t\tfunction drawOverlay(plot, octx)\n\t\t{\n\t\t\t//alert(options.series.pie.radius);\n\t\t\tvar options = plot.getOptions();\n\t\t\t//alert(options.series.pie.radius);\n\n\t\t\tvar radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;\n\n\t\t\toctx.save();\n\t\t\toctx.translate(centerLeft, centerTop);\n\t\t\toctx.scale(1, options.series.pie.tilt);\n\n\t\t\tfor (i = 0; i < highlights.length; ++i)\n\t\t\t\tdrawHighlight(highlights[i].series);\n\n\t\t\tdrawDonutHole(octx);\n\n\t\t\toctx.restore();\n\n\t\t\tfunction drawHighlight(series)\n\t\t\t{\n\t\t\t\tif (series.angle < 0) return;\n\n\t\t\t\t//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();\n\t\t\t\toctx.fillStyle = \"rgba(255, 255, 255, \"+options.series.pie.highlight.opacity+\")\"; // this is temporary until we have access to parseColor\n\n\t\t\t\toctx.beginPath();\n\t\t\t\tif (Math.abs(series.angle - Math.PI*2) > 0.000000001)\n\t\t\t\t\toctx.moveTo(0,0); // Center of the pie\n\t\t\t\toctx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);\n\t\t\t\toctx.closePath();\n\t\t\t\toctx.fill();\n\t\t\t}\n\n\t\t}\n\n\t} // end init (plugin body)\n\n\t// define pie specific options and their default values\n\tvar options = {\n\t\tseries: {\n\t\t\tpie: {\n\t\t\t\tshow: false,\n\t\t\t\tradius: 'auto',\t// actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)\n\t\t\t\tinnerRadius:0, /* for donut */\n\t\t\t\tstartAngle: 3/2,\n\t\t\t\ttilt: 1,\n\t\t\t\toffset: {\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: 'auto'\n\t\t\t\t},\n\t\t\t\tstroke: {\n\t\t\t\t\tcolor: '#FFF',\n\t\t\t\t\twidth: 1\n\t\t\t\t},\n\t\t\t\tlabel: {\n\t\t\t\t\tshow: 'auto',\n\t\t\t\t\tformatter: function(label, slice){\n\t\t\t\t\t\treturn '<div style=\"font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';\">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';\n\t\t\t\t\t},\t// formatter function\n\t\t\t\t\tradius: 1,\t// radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)\n\t\t\t\t\tbackground: {\n\t\t\t\t\t\tcolor: null,\n\t\t\t\t\t\topacity: 0\n\t\t\t\t\t},\n\t\t\t\t\tthreshold: 0\t// percentage at which to hide the label (i.e. the slice is too narrow)\n\t\t\t\t},\n\t\t\t\tcombine: {\n\t\t\t\t\tthreshold: -1,\t// percentage at which to combine little slices into one larger slice\n\t\t\t\t\tcolor: null,\t// color to give the new slice (auto-generated if null)\n\t\t\t\t\tlabel: 'Other'\t// label to give the new slice\n\t\t\t\t},\n\t\t\t\thighlight: {\n\t\t\t\t\t//color: '#FFF',\t\t// will add this functionality once parseColor is available\n\t\t\t\t\topacity: 0.5\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t$.plot.plugins.push({\n\t\tinit: init,\n\t\toptions: options,\n\t\tname: \"pie\",\n\t\tversion: \"1.0\"\n\t});\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/flot/jquery.flot.resize.js",
    "content": "/* Flot plugin for automatically redrawing plots as the placeholder resizes.\n\nCopyright (c) 2007-2013 IOLA and Ole Laursen.\nLicensed under the MIT license.\n\nIt works by listening for changes on the placeholder div (through the jQuery\nresize event plugin) - if the size changes, it will redraw the plot.\n\nThere are no options. If you need to disable the plugin for some plots, you\ncan just fix the size of their placeholders.\n\n*/\n\n/* Inline dependency:\n * jQuery resize event - v1.1 - 3/14/2010\n * http://benalman.com/projects/jquery-resize-plugin/\n *\n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n\n(function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k=\"setTimeout\",j=\"resize\",d=j+\"-special-event\",b=\"delay\",f=\"throttleWindow\";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);\n\n(function ($) {\n    var options = { }; // no options\n\n    function init(plot) {\n        function onResize() {\n            var placeholder = plot.getPlaceholder();\n\n            // somebody might have hidden us and we can't plot\n            // when we don't have the dimensions\n            if (placeholder.width() == 0 || placeholder.height() == 0)\n                return;\n\n            plot.resize();\n            plot.setupGrid();\n            plot.draw();\n        }\n\n        function bindEvents(plot, eventHolder) {\n            plot.getPlaceholder().resize(onResize);\n        }\n\n        function shutdown(plot, eventHolder) {\n            plot.getPlaceholder().unbind(\"resize\", onResize);\n        }\n\n        plot.hooks.bindEvents.push(bindEvents);\n        plot.hooks.shutdown.push(shutdown);\n    }\n\n    $.plot.plugins.push({\n        init: init,\n        options: options,\n        name: 'resize',\n        version: '1.0'\n    });\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/flot/jquery.flot.spline.js",
    "content": "/**\n * Flot plugin that provides spline interpolation for line graphs\n * author: Alex Bardas < alex.bardas@gmail.com >\n * modified by: Avi Kohn https://github.com/AMKohn\n * based on the spline interpolation described at:\n *\t\t http://scaledinnovation.com/analytics/splines/aboutSplines.html\n *\n * Example usage: (add in plot options series object)\n *\t\tfor linespline:\n *\t\t\tseries: {\n *\t\t\t\t...\n *\t\t\t\tlines: {\n *\t\t\t\t\tshow: false\n *\t\t\t\t},\n *\t\t\t\tsplines: {\n *\t\t\t\t\tshow: true,\n *\t\t\t\t\ttension: x, (float between 0 and 1, defaults to 0.5),\n *\t\t\t\t\tlineWidth: y (number, defaults to 2),\n *\t\t\t\t\tfill: z (float between 0 .. 1 or false, as in flot documentation)\n *\t\t\t\t},\n *\t\t\t\t...\n *\t\t\t}\n *\t\tareaspline:\n *\t\t\tseries: {\n *\t\t\t\t...\n *\t\t\t\tlines: {\n *\t\t\t\t\tshow: true,\n *\t\t\t\t\tlineWidth: 0, (line drawing will not execute)\n *\t\t\t\t\tfill: x, (float between 0 .. 1, as in flot documentation)\n *\t\t\t\t\t...\n *\t\t\t\t},\n *\t\t\t\tsplines: {\n *\t\t\t\t\tshow: true,\n *\t\t\t\t\ttension: 0.5 (float between 0 and 1)\n *\t\t\t\t},\n *\t\t\t\t...\n *\t\t\t}\n *\n */\n\n(function($) {\n    'use strict'\n\n    /**\n     * @param {Number} x0, y0, x1, y1: coordinates of the end (knot) points of the segment\n     * @param {Number} x2, y2: the next knot (not connected, but needed to calculate p2)\n     * @param {Number} tension: control how far the control points spread\n     * @return {Array}: p1 -> control point, from x1 back toward x0\n     * \t\t\t\t\tp2 -> the next control point, returned to become the next segment's p1\n     *\n     * @api private\n     */\n    function getControlPoints(x0, y0, x1, y1, x2, y2, tension) {\n\n        var pow = Math.pow,\n            sqrt = Math.sqrt,\n            d01, d12, fa, fb, p1x, p1y, p2x, p2y;\n\n        //  Scaling factors: distances from this knot to the previous and following knots.\n        d01 = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));\n        d12 = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));\n\n        fa = tension * d01 / (d01 + d12);\n        fb = tension - fa;\n\n        p1x = x1 + fa * (x0 - x2);\n        p1y = y1 + fa * (y0 - y2);\n\n        p2x = x1 - fb * (x0 - x2);\n        p2y = y1 - fb * (y0 - y2);\n\n        return [p1x, p1y, p2x, p2y];\n    }\n\n    var line = [];\n\n    function drawLine(points, ctx, height, fill, seriesColor) {\n        var c = $.color.parse(seriesColor);\n\n        c.a = typeof fill == \"number\" ? fill : .3;\n        c.normalize();\n        c = c.toString();\n\n        ctx.beginPath();\n        ctx.moveTo(points[0][0], points[0][1]);\n\n        var plength = points.length;\n\n        for (var i = 0; i < plength; i++) {\n            ctx[points[i][3]].apply(ctx, points[i][2]);\n        }\n\n        ctx.stroke();\n\n        ctx.lineWidth = 0;\n        ctx.lineTo(points[plength - 1][0], height);\n        ctx.lineTo(points[0][0], height);\n\n        ctx.closePath();\n\n        if (fill !== false) {\n            ctx.fillStyle = c;\n            ctx.fill();\n        }\n    }\n\n    /**\n     * @param {Object} ctx: canvas context\n     * @param {String} type: accepted strings: 'bezier' or 'quadratic' (defaults to quadratic)\n     * @param {Array} points: 2 points for which to draw the interpolation\n     * @param {Array} cpoints: control points for those segment points\n     *\n     * @api private\n     */\n    function queue(ctx, type, points, cpoints) {\n        if (type === void 0 || (type !== 'bezier' && type !== 'quadratic')) {\n            type = 'quadratic';\n        }\n        type = type + 'CurveTo';\n\n        if (line.length == 0) line.push([points[0], points[1], cpoints.concat(points.slice(2)), type]);\n        else if (type == \"quadraticCurveTo\" && points.length == 2) {\n            cpoints = cpoints.slice(0, 2).concat(points);\n\n            line.push([points[0], points[1], cpoints, type]);\n        }\n        else line.push([points[2], points[3], cpoints.concat(points.slice(2)), type]);\n    }\n\n    /**\n     * @param {Object} plot\n     * @param {Object} ctx: canvas context\n     * @param {Object} series\n     *\n     * @api private\n     */\n\n    function drawSpline(plot, ctx, series) {\n        // Not interested if spline is not requested\n        if (series.splines.show !== true) {\n            return;\n        }\n\n        var cp = [],\n        // array of control points\n            tension = series.splines.tension || 0.5,\n            idx, x, y, points = series.datapoints.points,\n            ps = series.datapoints.pointsize,\n            plotOffset = plot.getPlotOffset(),\n            len = points.length,\n            pts = [];\n\n        line = [];\n\n        // Cannot display a linespline/areaspline if there are less than 3 points\n        if (len / ps < 4) {\n            $.extend(series.lines, series.splines);\n            return;\n        }\n\n        for (idx = 0; idx < len; idx += ps) {\n            x = points[idx];\n            y = points[idx + 1];\n            if (x == null || x < series.xaxis.min || x > series.xaxis.max || y < series.yaxis.min || y > series.yaxis.max) {\n                continue;\n            }\n\n            pts.push(series.xaxis.p2c(x) + plotOffset.left, series.yaxis.p2c(y) + plotOffset.top);\n        }\n\n        len = pts.length;\n\n        // Draw an open curve, not connected at the ends\n        for (idx = 0; idx < len - 2; idx += 2) {\n            cp = cp.concat(getControlPoints.apply(this, pts.slice(idx, idx + 6).concat([tension])));\n        }\n\n        ctx.save();\n        ctx.strokeStyle = series.color;\n        ctx.lineWidth = series.splines.lineWidth;\n\n        queue(ctx, 'quadratic', pts.slice(0, 4), cp.slice(0, 2));\n\n        for (idx = 2; idx < len - 3; idx += 2) {\n            queue(ctx, 'bezier', pts.slice(idx, idx + 4), cp.slice(2 * idx - 2, 2 * idx + 2));\n        }\n\n        queue(ctx, 'quadratic', pts.slice(len - 2, len), [cp[2 * len - 10], cp[2 * len - 9], pts[len - 4], pts[len - 3]]);\n\n        drawLine(line, ctx, plot.height() + 10, series.splines.fill, series.color);\n\n        ctx.restore();\n    }\n\n    $.plot.plugins.push({\n        init: function(plot) {\n            plot.hooks.drawSeries.push(drawSpline);\n        },\n        options: {\n            series: {\n                splines: {\n                    show: false,\n                    lineWidth: 2,\n                    tension: 0.5,\n                    fill: false\n                }\n            }\n        },\n        name: 'spline',\n        version: '0.8.2'\n    });\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/flot/jquery.flot.symbol.js",
    "content": "/* Flot plugin that adds some extra symbols for plotting points.\n\n Copyright (c) 2007-2014 IOLA and Ole Laursen.\n Licensed under the MIT license.\n\n The symbols are accessed as strings through the standard symbol options:\n\n series: {\n points: {\n symbol: \"square\" // or \"diamond\", \"triangle\", \"cross\"\n }\n }\n\n */\n\n(function ($) {\n    function processRawData(plot, series, datapoints) {\n        // we normalize the area of each symbol so it is approximately the\n        // same as a circle of the given radius\n\n        var handlers = {\n            square: function (ctx, x, y, radius, shadow) {\n                // pi * r^2 = (2s)^2  =>  s = r * sqrt(pi)/2\n                var size = radius * Math.sqrt(Math.PI) / 2;\n                ctx.rect(x - size, y - size, size + size, size + size);\n            },\n            diamond: function (ctx, x, y, radius, shadow) {\n                // pi * r^2 = 2s^2  =>  s = r * sqrt(pi/2)\n                var size = radius * Math.sqrt(Math.PI / 2);\n                ctx.moveTo(x - size, y);\n                ctx.lineTo(x, y - size);\n                ctx.lineTo(x + size, y);\n                ctx.lineTo(x, y + size);\n                ctx.lineTo(x - size, y);\n            },\n            triangle: function (ctx, x, y, radius, shadow) {\n                // pi * r^2 = 1/2 * s^2 * sin (pi / 3)  =>  s = r * sqrt(2 * pi / sin(pi / 3))\n                var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3));\n                var height = size * Math.sin(Math.PI / 3);\n                ctx.moveTo(x - size/2, y + height/2);\n                ctx.lineTo(x + size/2, y + height/2);\n                if (!shadow) {\n                    ctx.lineTo(x, y - height/2);\n                    ctx.lineTo(x - size/2, y + height/2);\n                }\n            },\n            cross: function (ctx, x, y, radius, shadow) {\n                // pi * r^2 = (2s)^2  =>  s = r * sqrt(pi)/2\n                var size = radius * Math.sqrt(Math.PI) / 2;\n                ctx.moveTo(x - size, y - size);\n                ctx.lineTo(x + size, y + size);\n                ctx.moveTo(x - size, y + size);\n                ctx.lineTo(x + size, y - size);\n            }\n        };\n\n        var s = series.points.symbol;\n        if (handlers[s])\n            series.points.symbol = handlers[s];\n    }\n\n    function init(plot) {\n        plot.hooks.processDatapoints.push(processRawData);\n    }\n\n    $.plot.plugins.push({\n        init: init,\n        name: 'symbols',\n        version: '1.0'\n    });\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/fullscreen/jquery.fullscreen.js",
    "content": "/**\r\n * 基于jQuery FullScreen修改\r\n * 新增支持IE全屏显示\r\n * Copyright (c) 2019 ruoyi\r\n */\r\n(function(jQuery) {\r\n    \r\n    /**\r\n     * Sets or gets the fullscreen state.\r\n     * \r\n     * @param {boolean=} state\r\n     *            True to enable fullscreen mode, false to disable it. If not\r\n     *            specified then the current fullscreen state is returned.\r\n     * @return {boolean|Element|jQuery|null}\r\n     *            When querying the fullscreen state then the current fullscreen\r\n     *            element (or true if browser doesn't support it) is returned\r\n     *            when browser is currently in full screen mode. False is returned\r\n     *            if browser is not in full screen mode. Null is returned if \r\n     *            browser doesn't support fullscreen mode at all. When setting \r\n     *            the fullscreen state then the current jQuery selection is \r\n     *            returned for chaining.\r\n     * @this {jQuery}\r\n     */\r\n    function fullScreen(state)\r\n    {\r\n        var e, func, doc;\r\n        \r\n        // Do nothing when nothing was selected\r\n        if (!this.length) return this;\r\n        \r\n        // We only use the first selected element because it doesn't make sense\r\n        // to fullscreen multiple elements.\r\n        e = (/** @type {Element} */ this[0]);\r\n        \r\n        // Find the real element and the document (Depends on whether the\r\n        // document itself or a HTML element was selected)\r\n        if (e.ownerDocument)\r\n        {\r\n            doc = e.ownerDocument;\r\n        }\r\n        else\r\n        {\r\n            doc = e;\r\n            e = doc.documentElement;\r\n        }\r\n        \r\n        // When no state was specified then return the current state.\r\n        if (state == null)\r\n        {\r\n            // When fullscreen mode is not supported then return null\r\n            if (!((/** @type {?Function} */ doc[\"exitFullscreen\"])\r\n                || (/** @type {?Function} */ doc[\"webkitExitFullscreen\"])\r\n                || (/** @type {?Function} */ doc[\"webkitCancelFullScreen\"])\r\n                || (/** @type {?Function} */ doc[\"msExitFullscreen\"])\r\n                || (/** @type {?Function} */ doc[\"mozCancelFullScreen\"])))\r\n            {\r\n                return null;\r\n            }\r\n            \r\n            // Check fullscreen state\r\n            state = !!doc[\"fullscreenElement\"]\r\n                || !!doc[\"msFullscreenElement\"]\r\n                || !!doc[\"webkitIsFullScreen\"]\r\n                || !!doc[\"mozFullScreen\"];\r\n            if (!state) return state;\r\n            \r\n            // Return current fullscreen element or \"true\" if browser doesn't\r\n            // support this\r\n            return (/** @type {?Element} */ doc[\"fullscreenElement\"])\r\n                || (/** @type {?Element} */ doc[\"webkitFullscreenElement\"])\r\n                || (/** @type {?Element} */ doc[\"webkitCurrentFullScreenElement\"])\r\n                || (/** @type {?Element} */ doc[\"msFullscreenElement\"])\r\n                || (/** @type {?Element} */ doc[\"mozFullScreenElement\"])\r\n                || state;\r\n        }\r\n        \r\n        // When state was specified then enter or exit fullscreen mode.\r\n        if (state)\r\n        {\r\n            // Enter fullscreen\r\n            func = (/** @type {?Function} */ e[\"requestFullscreen\"])\r\n                || (/** @type {?Function} */ e[\"webkitRequestFullscreen\"])\r\n                || (/** @type {?Function} */ e[\"webkitRequestFullScreen\"])\r\n                || (/** @type {?Function} */ e[\"msRequestFullscreen\"])\r\n                || (/** @type {?Function} */ e[\"mozRequestFullScreen\"]);\r\n            if (func) \r\n            {\r\n                func.call(e);\r\n            }\r\n            return this;\r\n        }\r\n        else\r\n        {\r\n            // Exit fullscreen\r\n            func = (/** @type {?Function} */ doc[\"exitFullscreen\"])\r\n                || (/** @type {?Function} */ doc[\"webkitExitFullscreen\"])\r\n                || (/** @type {?Function} */ doc[\"webkitCancelFullScreen\"])\r\n                || (/** @type {?Function} */ doc[\"msExitFullscreen\"])\r\n                || (/** @type {?Function} */ doc[\"mozCancelFullScreen\"]);\r\n            if (func) func.call(doc);\r\n            return this;\r\n        }\r\n    }\r\n    \r\n    /**\r\n     * Toggles the fullscreen mode.\r\n     * \r\n     * @return {!jQuery}\r\n     *            The jQuery selection for chaining.\r\n     * @this {jQuery}\r\n     */\r\n    function toggleFullScreen()\r\n    {\r\n        return (/** @type {!jQuery} */ fullScreen.call(this, \r\n            !fullScreen.call(this)));\r\n    }\r\n    \r\n    /**\r\n     * Handles the browser-specific fullscreenchange event and triggers\r\n     * a jquery event for it.\r\n     *\r\n     * @param {?Event} event\r\n     *            The fullscreenchange event.\r\n     */\r\n    function fullScreenChangeHandler(event)\r\n    {\r\n        jQuery(document).trigger(new jQuery.Event(\"fullscreenchange\"));\r\n    }\r\n    \r\n    /**\r\n     * Handles the browser-specific fullscreenerror event and triggers\r\n     * a jquery event for it.\r\n     *\r\n     * @param {?Event} event\r\n     *            The fullscreenerror event.\r\n     */\r\n    function fullScreenErrorHandler(event)\r\n    {\r\n        jQuery(document).trigger(new jQuery.Event(\"fullscreenerror\"));\r\n    }\r\n    \r\n    /**\r\n     * Installs the fullscreenchange event handler.\r\n     */\r\n    function installFullScreenHandlers()\r\n    {\r\n        var e, change, error;\r\n        \r\n        // Determine event name\r\n        e = document;\r\n        if (e[\"webkitCancelFullScreen\"])\r\n        {\r\n            change = \"webkitfullscreenchange\";\r\n            error = \"webkitfullscreenerror\";\r\n        }\r\n        else if (e[\"msExitFullscreen\"])\r\n        {\r\n            change = \"MSFullscreenChange\";\r\n            error = \"MSFullscreenError\";\r\n        }\r\n        else if (e[\"mozCancelFullScreen\"])\r\n        {\r\n            change = \"mozfullscreenchange\";\r\n            error = \"mozfullscreenerror\";\r\n        }\r\n        else \r\n        {\r\n            change = \"fullscreenchange\";\r\n            error = \"fullscreenerror\";\r\n        }\r\n    \r\n        // Install the event handlers\r\n        jQuery(document).bind(change, fullScreenChangeHandler);\r\n        jQuery(document).bind(error, fullScreenErrorHandler);\r\n    }\r\n    \r\n    jQuery.fn[\"fullScreen\"] = fullScreen;\r\n    jQuery.fn[\"toggleFullScreen\"] = toggleFullScreen;\r\n    installFullScreenHandlers();\r\n    \r\n    })(jQuery);\r\n    "
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/iCheck/custom.css",
    "content": "/* iCheck plugin Square skin, green\r\n----------------------------------- */\r\n.icheckbox_square-green,\r\n.iradio_square-green {\r\n    display: inline-block;\r\n    *display: inline;\r\n    vertical-align: middle;\r\n    margin: 0;\r\n    padding: 0;\r\n    width: 22px;\r\n    height: 22px;\r\n    background: url(green.png) no-repeat;\r\n    border: none;\r\n    cursor: pointer;\r\n}\r\n\r\n.icheckbox_square-green-login{\r\n    display: inline-block;\r\n    *display: inline;\r\n    vertical-align: middle;\r\n    margin: 0;\r\n    padding: 0;\r\n    width: 22px;\r\n    height: 22px;\r\n    background: url(green-login.png) no-repeat;\r\n    border: none;\r\n    cursor: pointer;\r\n}\r\n\r\n.icheckbox_square-green,.icheckbox_square-green-login {\r\n    background-position: 0 0;\r\n}\r\n.icheckbox_square-green.hover,.icheckbox_square-green-login.hover {\r\n    background-position: -24px 0;\r\n}\r\n.icheckbox_square-green.checked,.icheckbox_square-green-login.checked {\r\n    background-position: -48px 0;\r\n}\r\n.icheckbox_square-green.disabled,.icheckbox_square-green.disabled-login {\r\n    background-position: -72px 0;\r\n    cursor: default;\r\n}\r\n.icheckbox_square-green.checked.disabled,.icheckbox_square-green-login.checked.disabled {\r\n    background-position: -96px 0;\r\n}\r\n\r\n.iradio_square-green {\r\n    background-position: -120px 0;\r\n}\r\n.iradio_square-green.hover {\r\n    background-position: -144px 0;\r\n}\r\n.iradio_square-green.checked {\r\n    background-position: -168px 0;\r\n}\r\n.iradio_square-green.disabled {\r\n    background-position: -192px 0;\r\n    cursor: default;\r\n}\r\n.iradio_square-green.checked.disabled {\r\n    background-position: -216px 0;\r\n}\r\n\r\n/* HiDPI support */\r\n@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {\r\n    .icheckbox_square-green,.icheckbox_square-green-login,\r\n    .iradio_square-green {\r\n        background-image: url(green%402x.png);\r\n        -webkit-background-size: 240px 24px;\r\n        background-size: 240px 24px;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jasny/jasny-bootstrap.css",
    "content": "/*!\n * Jasny Bootstrap v3.1.3 (http://jasny.github.io/bootstrap)\n * Copyright 2012-2014 Arnold Daniels\n * Licensed under Apache-2.0 (https://github.com/jasny/bootstrap/blob/master/LICENSE)\n */\n\n.container-smooth {\n  max-width: 1170px;\n}\n@media (min-width: 1px) {\n  .container-smooth {\n    width: auto;\n  }\n}\n.btn-labeled {\n  padding-top: 0;\n  padding-bottom: 0;\n}\n.btn-label {\n  position: relative;\n  left: -12px;\n  display: inline-block;\n  padding: 6px 12px;\n  background: transparent;\n  background: rgba(0, 0, 0, .15);\n  border-radius: 3px 0 0 3px;\n}\n.btn-label.btn-label-right {\n  right: -12px;\n  left: auto;\n  border-radius: 0 3px 3px 0;\n}\n.btn-lg .btn-label {\n  left: -16px;\n  padding: 10px 16px;\n  border-radius: 5px 0 0 5px;\n}\n.btn-lg .btn-label.btn-label-right {\n  right: -16px;\n  left: auto;\n  border-radius: 0 5px 5px 0;\n}\n.btn-sm .btn-label {\n  left: -10px;\n  padding: 5px 10px;\n  border-radius: 2px 0 0 2px;\n}\n.btn-sm .btn-label.btn-label-right {\n  right: -10px;\n  left: auto;\n  border-radius: 0 2px 2px 0;\n}\n.btn-xs .btn-label {\n  left: -5px;\n  padding: 1px 5px;\n  border-radius: 2px 0 0 2px;\n}\n.btn-xs .btn-label.btn-label-right {\n  right: -5px;\n  left: auto;\n  border-radius: 0 2px 2px 0;\n}\n.nav-tabs-bottom {\n  border-top: 1px solid #ddd;\n  border-bottom: 0;\n}\n.nav-tabs-bottom > li {\n  margin-top: -1px;\n  margin-bottom: 0;\n}\n.nav-tabs-bottom > li > a {\n  border-radius: 0 0 4px 4px;\n}\n.nav-tabs-bottom > li > a:hover,\n.nav-tabs-bottom > li > a:focus,\n.nav-tabs-bottom > li.active > a,\n.nav-tabs-bottom > li.active > a:hover,\n.nav-tabs-bottom > li.active > a:focus {\n  border: 1px solid #ddd;\n  border-top-color: transparent;\n}\n.nav-tabs-left {\n  border-right: 1px solid #ddd;\n  border-bottom: 0;\n}\n.nav-tabs-left > li {\n  float: none;\n  margin-right: -1px;\n  margin-bottom: 0;\n}\n.nav-tabs-left > li > a {\n  margin-right: 0;\n  margin-bottom: 2px;\n  border-radius: 4px 0 0 4px;\n}\n.nav-tabs-left > li > a:hover,\n.nav-tabs-left > li > a:focus,\n.nav-tabs-left > li.active > a,\n.nav-tabs-left > li.active > a:hover,\n.nav-tabs-left > li.active > a:focus {\n  border: 1px solid #ddd;\n  border-right-color: transparent;\n}\n.row > .nav-tabs-left {\n  position: relative;\n  z-index: 1;\n  padding-right: 0;\n  padding-left: 15px;\n  margin-right: -1px;\n}\n.row > .nav-tabs-left + .tab-content {\n  border-left: 1px solid #ddd;\n}\n.nav-tabs-right {\n  border-bottom: 0;\n  border-left: 1px solid #ddd;\n}\n.nav-tabs-right > li {\n  float: none;\n  margin-bottom: 0;\n  margin-left: -1px;\n}\n.nav-tabs-right > li > a {\n  margin-bottom: 2px;\n  margin-left: 0;\n  border-radius: 0 4px 4px 0;\n}\n.nav-tabs-right > li > a:hover,\n.nav-tabs-right > li > a:focus,\n.nav-tabs-right > li.active > a,\n.nav-tabs-right > li.active > a:hover,\n.nav-tabs-right > li.active > a:focus {\n  border: 1px solid #ddd;\n  border-left-color: transparent;\n}\n.row > .nav-tabs-right {\n  padding-right: 15px;\n  padding-left: 0;\n}\n.navmenu,\n.navbar-offcanvas {\n  width: 300px;\n  height: auto;\n  border-style: solid;\n  border-width: 1px;\n  border-radius: 4px;\n}\n.navmenu-fixed-left,\n.navmenu-fixed-right,\n.navbar-offcanvas {\n  position: fixed;\n  top: 0;\n  bottom: 0;\n  z-index: 1030;\n  overflow-y: auto;\n  border-radius: 0;\n}\n.navmenu-fixed-left,\n.navbar-offcanvas.navmenu-fixed-left {\n  right: auto;\n  left: 0;\n  border-width: 0 1px 0 0;\n}\n.navmenu-fixed-right,\n.navbar-offcanvas {\n  right: 0;\n  left: auto;\n  border-width: 0 0 0 1px;\n}\n.navmenu-nav {\n  margin-bottom: 10px;\n}\n.navmenu-nav.dropdown-menu {\n  position: static;\n  float: none;\n  padding-top: 0;\n  margin: 0;\n  border: none;\n  border-radius: 0;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.navbar-offcanvas .navbar-nav {\n  margin: 0;\n}\n@media (min-width: 768px) {\n  .navbar-offcanvas {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n  .navbar-offcanvas.offcanvas {\n    position: static;\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-offcanvas .navbar-nav.navbar-left:first-child {\n    margin-left: -15px;\n  }\n  .navbar-offcanvas .navbar-nav.navbar-right:last-child {\n    margin-right: -15px;\n  }\n  .navbar-offcanvas .navmenu-brand {\n    display: none;\n  }\n}\n.navmenu-brand {\n  display: block;\n  padding: 10px 15px;\n  margin: 10px 0;\n  font-size: 18px;\n  line-height: 20px;\n}\n.navmenu-brand:hover,\n.navmenu-brand:focus {\n  text-decoration: none;\n}\n.navmenu-default,\n.navbar-default .navbar-offcanvas {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navmenu-default .navmenu-brand,\n.navbar-default .navbar-offcanvas .navmenu-brand {\n  color: #777;\n}\n.navmenu-default .navmenu-brand:hover,\n.navbar-default .navbar-offcanvas .navmenu-brand:hover,\n.navmenu-default .navmenu-brand:focus,\n.navbar-default .navbar-offcanvas .navmenu-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navmenu-default .navmenu-text,\n.navbar-default .navbar-offcanvas .navmenu-text {\n  color: #777;\n}\n.navmenu-default .navmenu-nav > .dropdown > a:hover .caret,\n.navbar-default .navbar-offcanvas .navmenu-nav > .dropdown > a:hover .caret,\n.navmenu-default .navmenu-nav > .dropdown > a:focus .caret,\n.navbar-default .navbar-offcanvas .navmenu-nav > .dropdown > a:focus .caret {\n  border-top-color: #333;\n  border-bottom-color: #333;\n}\n.navmenu-default .navmenu-nav > .open > a,\n.navbar-default .navbar-offcanvas .navmenu-nav > .open > a,\n.navmenu-default .navmenu-nav > .open > a:hover,\n.navbar-default .navbar-offcanvas .navmenu-nav > .open > a:hover,\n.navmenu-default .navmenu-nav > .open > a:focus,\n.navbar-default .navbar-offcanvas .navmenu-nav > .open > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navmenu-default .navmenu-nav > .open > a .caret,\n.navbar-default .navbar-offcanvas .navmenu-nav > .open > a .caret,\n.navmenu-default .navmenu-nav > .open > a:hover .caret,\n.navbar-default .navbar-offcanvas .navmenu-nav > .open > a:hover .caret,\n.navmenu-default .navmenu-nav > .open > a:focus .caret,\n.navbar-default .navbar-offcanvas .navmenu-nav > .open > a:focus .caret {\n  border-top-color: #555;\n  border-bottom-color: #555;\n}\n.navmenu-default .navmenu-nav > .dropdown > a .caret,\n.navbar-default .navbar-offcanvas .navmenu-nav > .dropdown > a .caret {\n  border-top-color: #777;\n  border-bottom-color: #777;\n}\n.navmenu-default .navmenu-nav.dropdown-menu,\n.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu {\n  background-color: #e7e7e7;\n}\n.navmenu-default .navmenu-nav.dropdown-menu > .divider,\n.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu > .divider {\n  background-color: #f8f8f8;\n}\n.navmenu-default .navmenu-nav.dropdown-menu > .active > a,\n.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu > .active > a,\n.navmenu-default .navmenu-nav.dropdown-menu > .active > a:hover,\n.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu > .active > a:hover,\n.navmenu-default .navmenu-nav.dropdown-menu > .active > a:focus,\n.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu > .active > a:focus {\n  background-color: #d7d7d7;\n}\n.navmenu-default .navmenu-nav > li > a,\n.navbar-default .navbar-offcanvas .navmenu-nav > li > a {\n  color: #777;\n}\n.navmenu-default .navmenu-nav > li > a:hover,\n.navbar-default .navbar-offcanvas .navmenu-nav > li > a:hover,\n.navmenu-default .navmenu-nav > li > a:focus,\n.navbar-default .navbar-offcanvas .navmenu-nav > li > a:focus {\n  color: #333;\n  background-color: transparent;\n}\n.navmenu-default .navmenu-nav > .active > a,\n.navbar-default .navbar-offcanvas .navmenu-nav > .active > a,\n.navmenu-default .navmenu-nav > .active > a:hover,\n.navbar-default .navbar-offcanvas .navmenu-nav > .active > a:hover,\n.navmenu-default .navmenu-nav > .active > a:focus,\n.navbar-default .navbar-offcanvas .navmenu-nav > .active > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navmenu-default .navmenu-nav > .disabled > a,\n.navbar-default .navbar-offcanvas .navmenu-nav > .disabled > a,\n.navmenu-default .navmenu-nav > .disabled > a:hover,\n.navbar-default .navbar-offcanvas .navmenu-nav > .disabled > a:hover,\n.navmenu-default .navmenu-nav > .disabled > a:focus,\n.navbar-default .navbar-offcanvas .navmenu-nav > .disabled > a:focus {\n  color: #ccc;\n  background-color: transparent;\n}\n.navmenu-inverse,\n.navbar-inverse .navbar-offcanvas {\n  background-color: #222;\n  border-color: #080808;\n}\n.navmenu-inverse .navmenu-brand,\n.navbar-inverse .navbar-offcanvas .navmenu-brand {\n  color: #999;\n}\n.navmenu-inverse .navmenu-brand:hover,\n.navbar-inverse .navbar-offcanvas .navmenu-brand:hover,\n.navmenu-inverse .navmenu-brand:focus,\n.navbar-inverse .navbar-offcanvas .navmenu-brand:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navmenu-inverse .navmenu-text,\n.navbar-inverse .navbar-offcanvas .navmenu-text {\n  color: #999;\n}\n.navmenu-inverse .navmenu-nav > .dropdown > a:hover .caret,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .dropdown > a:hover .caret,\n.navmenu-inverse .navmenu-nav > .dropdown > a:focus .caret,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .dropdown > a:focus .caret {\n  border-top-color: #fff;\n  border-bottom-color: #fff;\n}\n.navmenu-inverse .navmenu-nav > .open > a,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .open > a,\n.navmenu-inverse .navmenu-nav > .open > a:hover,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .open > a:hover,\n.navmenu-inverse .navmenu-nav > .open > a:focus,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .open > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n.navmenu-inverse .navmenu-nav > .open > a .caret,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .open > a .caret,\n.navmenu-inverse .navmenu-nav > .open > a:hover .caret,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .open > a:hover .caret,\n.navmenu-inverse .navmenu-nav > .open > a:focus .caret,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .open > a:focus .caret {\n  border-top-color: #fff;\n  border-bottom-color: #fff;\n}\n.navmenu-inverse .navmenu-nav > .dropdown > a .caret,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .dropdown > a .caret {\n  border-top-color: #999;\n  border-bottom-color: #999;\n}\n.navmenu-inverse .navmenu-nav.dropdown-menu,\n.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu {\n  background-color: #080808;\n}\n.navmenu-inverse .navmenu-nav.dropdown-menu > .divider,\n.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu > .divider {\n  background-color: #222;\n}\n.navmenu-inverse .navmenu-nav.dropdown-menu > .active > a,\n.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu > .active > a,\n.navmenu-inverse .navmenu-nav.dropdown-menu > .active > a:hover,\n.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu > .active > a:hover,\n.navmenu-inverse .navmenu-nav.dropdown-menu > .active > a:focus,\n.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu > .active > a:focus {\n  background-color: #000;\n}\n.navmenu-inverse .navmenu-nav > li > a,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > li > a {\n  color: #999;\n}\n.navmenu-inverse .navmenu-nav > li > a:hover,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > li > a:hover,\n.navmenu-inverse .navmenu-nav > li > a:focus,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > li > a:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navmenu-inverse .navmenu-nav > .active > a,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .active > a,\n.navmenu-inverse .navmenu-nav > .active > a:hover,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .active > a:hover,\n.navmenu-inverse .navmenu-nav > .active > a:focus,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .active > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n.navmenu-inverse .navmenu-nav > .disabled > a,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .disabled > a,\n.navmenu-inverse .navmenu-nav > .disabled > a:hover,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .disabled > a:hover,\n.navmenu-inverse .navmenu-nav > .disabled > a:focus,\n.navbar-inverse .navbar-offcanvas .navmenu-nav > .disabled > a:focus {\n  color: #444;\n  background-color: transparent;\n}\n.alert-fixed-top,\n.alert-fixed-bottom {\n  position: fixed;\n  left: 0;\n  z-index: 1035;\n  width: 100%;\n  margin: 0;\n  border-radius: 0;\n}\n@media (min-width: 992px) {\n  .alert-fixed-top,\n  .alert-fixed-bottom {\n    left: 50%;\n    width: 992px;\n    margin-left: -496px;\n  }\n}\n.alert-fixed-top {\n  top: 0;\n  border-width: 0 0 1px 0;\n}\n@media (min-width: 992px) {\n  .alert-fixed-top {\n    border-width: 0 1px 1px 1px;\n    border-bottom-right-radius: 4px;\n    border-bottom-left-radius: 4px;\n  }\n}\n.alert-fixed-bottom {\n  bottom: 0;\n  border-width: 1px 0 0 0;\n}\n@media (min-width: 992px) {\n  .alert-fixed-bottom {\n    border-width: 1px 1px 0 1px;\n    border-top-left-radius: 4px;\n    border-top-right-radius: 4px;\n  }\n}\n.offcanvas {\n  display: none;\n}\n.offcanvas.in {\n  display: block;\n}\n@media (max-width: 767px) {\n  .offcanvas-xs {\n    display: none;\n  }\n  .offcanvas-xs.in {\n    display: block;\n  }\n}\n@media (max-width: 991px) {\n  .offcanvas-sm {\n    display: none;\n  }\n  .offcanvas-sm.in {\n    display: block;\n  }\n}\n@media (max-width: 1199px) {\n  .offcanvas-md {\n    display: none;\n  }\n  .offcanvas-md.in {\n    display: block;\n  }\n}\n.offcanvas-lg {\n  display: none;\n}\n.offcanvas-lg.in {\n  display: block;\n}\n.canvas-sliding {\n  -webkit-transition: top .35s, left .35s, bottom .35s, right .35s;\n          transition: top .35s, left .35s, bottom .35s, right .35s;\n}\n.offcanvas-clone {\n  position: absolute !important;\n  top: auto !important;\n  right: 0 !important;\n  bottom: 0 !important;\n  left: auto !important;\n  width: 0 !important;\n  height: 0 !important;\n  padding: 0 !important;\n  margin: 0 !important;\n  overflow: hidden !important;\n  border: none !important;\n  opacity: 0 !important;\n}\n.table.rowlink td:not(.rowlink-skip),\n.table .rowlink td:not(.rowlink-skip) {\n  cursor: pointer;\n}\n.table.rowlink td:not(.rowlink-skip) a,\n.table .rowlink td:not(.rowlink-skip) a {\n  font: inherit;\n  color: inherit;\n  text-decoration: inherit;\n}\n.table-hover.rowlink tr:hover td,\n.table-hover .rowlink tr:hover td {\n  background-color: #cfcfcf;\n}\n.btn-file {\n  position: relative;\n  overflow: hidden;\n  vertical-align: middle;\n}\n.btn-file > input {\n  position: absolute;\n  top: 0;\n  right: 0;\n  width: 100%;\n  height: 100%;\n  margin: 0;\n  font-size: 23px;\n  cursor: pointer;\n  filter: alpha(opacity=0);\n  opacity: 0;\n\n  direction: ltr;\n}\n.fileinput {\n  display: inline-block;\n  margin-bottom: 9px;\n}\n.fileinput .form-control {\n  display: inline-block;\n  padding-top: 7px;\n  padding-bottom: 5px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  cursor: text;\n}\n.fileinput .thumbnail {\n  display: inline-block;\n  margin-bottom: 5px;\n  overflow: hidden;\n  text-align: center;\n  vertical-align: middle;\n}\n.fileinput .thumbnail > img {\n  max-height: 100%;\n}\n.fileinput .btn {\n  vertical-align: middle;\n}\n.fileinput-exists .fileinput-new,\n.fileinput-new .fileinput-exists {\n  display: none;\n}\n.fileinput-inline .fileinput-controls {\n  display: inline;\n}\n.fileinput-filename {\n  display: inline-block;\n  overflow: hidden;\n  vertical-align: middle;\n}\n.form-control .fileinput-filename {\n  vertical-align: bottom;\n}\n.fileinput.input-group {\n  display: table;\n}\n.fileinput.input-group > * {\n  position: relative;\n  z-index: 2;\n}\n.fileinput.input-group > .btn-file {\n  z-index: 1;\n}\n.fileinput-new.input-group .btn-file,\n.fileinput-new .input-group .btn-file {\n  border-radius: 0 4px 4px 0;\n}\n.fileinput-new.input-group .btn-file.btn-xs,\n.fileinput-new .input-group .btn-file.btn-xs,\n.fileinput-new.input-group .btn-file.btn-sm,\n.fileinput-new .input-group .btn-file.btn-sm {\n  border-radius: 0 3px 3px 0;\n}\n.fileinput-new.input-group .btn-file.btn-lg,\n.fileinput-new .input-group .btn-file.btn-lg {\n  border-radius: 0 6px 6px 0;\n}\n.form-group.has-warning .fileinput .fileinput-preview {\n  color: #8a6d3b;\n}\n.form-group.has-warning .fileinput .thumbnail {\n  border-color: #faebcc;\n}\n.form-group.has-error .fileinput .fileinput-preview {\n  color: #a94442;\n}\n.form-group.has-error .fileinput .thumbnail {\n  border-color: #ebccd1;\n}\n.form-group.has-success .fileinput .fileinput-preview {\n  color: #3c763d;\n}\n.form-group.has-success .fileinput .thumbnail {\n  border-color: #d6e9c6;\n}\n.input-group-addon:not(:first-child) {\n  border-left: 0;\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jasny/jasny-bootstrap.js",
    "content": "/*!\n * Jasny Bootstrap v4.0.0 (http://jasny.github.io/bootstrap)\n * Copyright 2012-2014 Arnold Daniels\n * Licensed under Apache-2.0 (https://github.com/jasny/bootstrap/blob/master/LICENSE)\n */\n\n+function ($) { \"use strict\";\n\n  var isIE = window.navigator.appName == 'Microsoft Internet Explorer'\n\n  // FILEUPLOAD PUBLIC CLASS DEFINITION\n  // =================================\n\n  var Fileinput = function (element, options) {\n    this.$element = $(element)\n\n    this.options = $.extend({}, Fileinput.DEFAULTS, options)\n    this.$input = this.$element.find(':file')\n    if (this.$input.length === 0) return\n\n    this.name = this.$input.attr('name') || options.name\n\n    this.$hidden = this.$element.find('input[type=hidden][name=\"' + this.name + '\"]')\n    if (this.$hidden.length === 0) {\n      this.$hidden = $('<input type=\"hidden\">').insertBefore(this.$input)\n    }\n\n    this.$preview = this.$element.find('.fileinput-preview')\n    var height = this.$preview.css('height')\n    if (this.$preview.css('display') !== 'inline' && height !== '0px' && height !== 'none') {\n      this.$preview.css('line-height', height)\n    }\n\n    this.original = {\n      exists: this.$element.hasClass('fileinput-exists'),\n      preview: this.$preview.html(),\n      hiddenVal: this.$hidden.val()\n    }\n\n    this.listen()\n    this.reset()\n  }\n\n  Fileinput.DEFAULTS = {\n    clearName: true\n  }\n\n  Fileinput.prototype.listen = function() {\n    this.$input.on('change.bs.fileinput', $.proxy(this.change, this))\n    $(this.$input[0].form).on('reset.bs.fileinput', $.proxy(this.reset, this))\n\n    this.$element.find('[data-trigger=\"fileinput\"]').on('click.bs.fileinput', $.proxy(this.trigger, this))\n    this.$element.find('[data-dismiss=\"fileinput\"]').on('click.bs.fileinput', $.proxy(this.clear, this))\n  },\n\n  Fileinput.prototype.verifySizes = function(files) {\n    if (typeof this.options.maxSize === 'undefined') return true\n\n    var max = parseFloat(this.options.maxSize)\n    if (max !== this.options.maxSize) return true\n\n    for (var i = 0; i < files.length; i++) {\n      var size = typeof files[i].size !== 'undefined' ? files[i].size : null\n      if (size === null) continue\n\n      size = size / 1000 / 1000 /* convert from bytes to MB */\n      if (size > max) return false\n    }\n\n    return true\n  }\n\n  Fileinput.prototype.change = function(e) {\n    var files = e.target.files === undefined ? (e.target && e.target.value ? [{ name: e.target.value.replace(/^.+\\\\/, '')}] : []) : e.target.files\n\n    e.stopPropagation()\n\n    if (files.length === 0) {\n      this.clear()\n      this.$element.trigger('clear.bs.fileinput')\n      return\n    }\n\n    if (!this.verifySizes(files)) {\n      this.$element.trigger('max_size.bs.fileinput')\n\n      this.clear()\n      this.$element.trigger('clear.bs.fileinput')\n      return\n    }\n\n    this.$hidden.val('')\n    this.$hidden.attr('name', '')\n    this.$input.attr('name', this.name)\n\n    var file = files[0]\n\n    if (this.$preview.length > 0 && (typeof file.type !== \"undefined\" ? file.type.match(/^image\\/(gif|png|jpeg|svg\\+xml)$/) : file.name.match(/\\.(gif|png|jpe?g|svg)$/i)) && typeof FileReader !== \"undefined\") {\n      var Fileinput = this\n      var reader = new FileReader()\n      var preview = this.$preview\n      var element = this.$element\n\n      reader.onload = function(re) {\n        var $img = $('<img>')\n        $img[0].src = re.target.result\n        files[0].result = re.target.result\n\n        element.find('.fileinput-filename').text(file.name)\n\n        // if parent has max-height, using `(max-)height: 100%` on child doesn't take padding and border into account\n        if (preview.css('max-height') != 'none') {\n          var mh = parseInt(preview.css('max-height'), 10) || 0\n          var pt = parseInt(preview.css('padding-top'), 10) || 0\n          var pb = parseInt(preview.css('padding-bottom'), 10) || 0\n          var bt = parseInt(preview.css('border-top'), 10) || 0\n          var bb = parseInt(preview.css('border-bottom'), 10) || 0\n\n          $img.css('max-height', mh - pt - pb - bt - bb)\n        }\n\n        preview.html($img)\n        if (Fileinput.options.exif) {\n          //Fix image tranformation if this is possible\n          Fileinput.setImageTransform($img, file);\n        }\n        element.addClass('fileinput-exists').removeClass('fileinput-new')\n\n        element.trigger('change.bs.fileinput', files)\n      }\n\n      reader.readAsDataURL(file)\n    } else {\n      var text = file.name\n      var $nameView = this.$element.find('.fileinput-filename')\n\n      if (files.length > 1) {\n        text = $.map(files, function(file) {\n          return file.name;\n        }).join(', ')\n      }\n\n      $nameView.text(text)\n      this.$preview.text(file.name)\n      this.$element.addClass('fileinput-exists').removeClass('fileinput-new')\n      this.$element.trigger('change.bs.fileinput')\n    }\n  },\n\n  Fileinput.prototype.setImageTransform = function($img, file) {\n      var Fileinput = this;\n      var reader = new FileReader();\n      reader.onload = function(me) {\n        var transform = false;\n        var view = new DataView(reader.result);\n        var exif = Fileinput.getImageExif(view);\n        if (exif) {\n            Fileinput.resetOrientation($img, exif);\n        }\n      }\n\n      reader.readAsArrayBuffer(file);\n  }\n\n  Fileinput.prototype.getImageExif = function(view) {\n    if (view.getUint16(0, false) != 0xFFD8) {\n      return -2;\n    }\n    var length = view.byteLength, offset = 2;\n    while (offset < length) {\n      var marker = view.getUint16(offset, false);\n          offset += 2;\n      if (marker == 0xFFE1) {\n        if (view.getUint32(offset += 2, false) != 0x45786966) {\n          return -1;\n        }\n        var little = view.getUint16(offset += 6, false) == 0x4949;\n            offset += view.getUint32(offset + 4, little);\n        var tags = view.getUint16(offset, little);\n            offset += 2;\n        for (var i = 0; i < tags; i++)   {\n          if (view.getUint16(offset + (i * 12), little) == 0x0112) {\n            return view.getUint16(offset + (i * 12) + 8, little);\n          }\n        }\n      }\n      else if ((marker & 0xFF00) != 0xFF00){\n         break;\n      } else {\n        offset += view.getUint16(offset, false);\n      }\n    }\n\n    return -1;\n  }\n\n  Fileinput.prototype.resetOrientation = function($img, transform) {\n  var img = new Image();\n\n  img.onload = function() {\n    var width = img.width,\n        height = img.height,\n        canvas = document.createElement('canvas'),\n        ctx = canvas.getContext(\"2d\");\n\n    // set proper canvas dimensions before transform & export\n    if ([5,6,7,8].indexOf(transform) > -1) {\n      canvas.width = height;\n      canvas.height = width;\n    } else {\n      canvas.width = width;\n      canvas.height = height;\n    }\n\n    // transform context before drawing image\n    switch (transform) {\n      case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;\n      case 3: ctx.transform(-1, 0, 0, -1, width, height ); break;\n      case 4: ctx.transform(1, 0, 0, -1, 0, height ); break;\n      case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;\n      case 6: ctx.transform(0, 1, -1, 0, height , 0); break;\n      case 7: ctx.transform(0, -1, -1, 0, height , width); break;\n      case 8: ctx.transform(0, -1, 1, 0, 0, width); break;\n      default: ctx.transform(1, 0, 0, 1, 0, 0);\n    }\n\n    // draw image\n    ctx.drawImage(img, 0, 0);\n\n    // export base64\n    $img.attr('src', canvas.toDataURL());\n  };\n\n  img.src = $img.attr('src');\n};\n\n  Fileinput.prototype.clear = function(e) {\n    if (e) e.preventDefault()\n\n    this.$hidden.val('')\n    this.$hidden.attr('name', this.name)\n    if (this.options.clearName) this.$input.attr('name', '')\n\n    //ie8+ doesn't support changing the value of input with type=file so clone instead\n    if (isIE) {\n      var inputClone = this.$input.clone(true);\n      this.$input.after(inputClone);\n      this.$input.remove();\n      this.$input = inputClone;\n    } else {\n      this.$input.val('')\n    }\n\n    this.$preview.html('')\n    this.$element.find('.fileinput-filename').text('')\n    this.$element.addClass('fileinput-new').removeClass('fileinput-exists')\n\n    if (e !== undefined) {\n      this.$input.trigger('change')\n      this.$element.trigger('clear.bs.fileinput')\n    }\n  },\n\n  Fileinput.prototype.reset = function() {\n    this.clear()\n\n    this.$hidden.val(this.original.hiddenVal)\n    this.$preview.html(this.original.preview)\n    this.$element.find('.fileinput-filename').text('')\n\n    if (this.original.exists) this.$element.addClass('fileinput-exists').removeClass('fileinput-new')\n     else this.$element.addClass('fileinput-new').removeClass('fileinput-exists')\n\n    this.$element.trigger('reseted.bs.fileinput')\n  },\n\n  Fileinput.prototype.trigger = function(e) {\n    this.$input.trigger('click')\n    e.preventDefault()\n  }\n\n\n  // FILEUPLOAD PLUGIN DEFINITION\n  // ===========================\n\n  var old = $.fn.fileinput\n\n  $.fn.fileinput = function (options) {\n    return this.each(function () {\n      var $this = $(this),\n          data = $this.data('bs.fileinput')\n      if (!data) $this.data('bs.fileinput', (data = new Fileinput(this, options)))\n      if (typeof options == 'string') data[options]()\n    })\n  }\n\n  $.fn.fileinput.Constructor = Fileinput\n\n\n  // FILEINPUT NO CONFLICT\n  // ====================\n\n  $.fn.fileinput.noConflict = function () {\n    $.fn.fileinput = old\n    return this\n  }\n\n\n  // FILEUPLOAD DATA-API\n  // ==================\n\n  $(document).on('click.fileinput.data-api', '[data-provides=\"fileinput\"]', function (e) {\n    var $this = $(this)\n    if ($this.data('bs.fileinput')) return\n    $this.fileinput($this.data())\n\n    var $target = $(e.target).closest('[data-dismiss=\"fileinput\"],[data-trigger=\"fileinput\"]');\n    if ($target.length > 0) {\n      e.preventDefault()\n      $target.trigger('click.bs.fileinput')\n    }\n  })\n\n}(window.jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-layout/jquery.layout-latest.css",
    "content": ".ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-layout-pane{overflow:auto}.ui-layout-content{padding:10px;position:relative;overflow:auto;width:100%;border:0}.layout-child-container,.layout-content-container{padding:0;overflow:hidden}.layout-child-container{border:0}.layout-scroll{overflow:auto}.layout-hide{display:none}.ui-layout-resizer{background:#fafafa;border:1px solid #eee;border-width:0}.ui-layout-resizer-open-hover,.ui-layout-resizer-dragging{background:#fafafa}.ui-layout-resizer-dragging{border:1px solid #eee}.ui-layout-resizer-north-dragging,.ui-layout-resizer-south-dragging{border-width:1px 0}.ui-layout-resizer-west-dragging,.ui-layout-resizer-east-dragging{border-width:0 1px}.ui-layout-resizer-dragging-limit{background:#e1a4a4}.ui-layout-resizer-closed-hover{background:#ebd5aa}.ui-layout-resizer-north-sliding-hover{border-bottom-width:1px}.ui-layout-resizer-south-sliding-hover{border-top-width:1px}.ui-layout-resizer-west-sliding-hover{border-right-width:1px}.ui-layout-resizer-east-sliding-hover{border-left-width:1px}.ui-layout-toggler{border:1px solid #eee;background-color:#eee}.ui-layout-resizer-hover .ui-layout-toggler{opacity:1.00;filter:alpha(opacity=100)}.ui-layout-toggler-hover,.ui-layout-resizer-hover .ui-layout-toggler-hover{background-color:#FC6;opacity:1.00;filter:alpha(opacity=100)}.ui-layout-toggler-north,.ui-layout-toggler-south{border-width:0 1px}.ui-layout-toggler-west,.ui-layout-toggler-east{border-width:1px 0}.ui-layout-resizer-sliding .ui-layout-toggler{display:none}.ui-layout-toggler .ui-content{color:#666;font-size:12px;font-weight:bold;line-height:8px;width:100%;padding-bottom:.35ex}.ui-layout-toggler .ui-content .fa{line-height:8px}.ui-layout-toggler-north-closed .fa:before,.ui-layout-toggler-south-open .fa:before{content:\"\\f0d7\"}.ui-layout-toggler-south-closed .fa:before,.ui-layout-toggler-north-open .fa:before{content:\"\\f0d8\"}.ui-layout-toggler-west-closed .fa:before,.ui-layout-toggler-east-open .fa:before{content:\"\\f0da\"}.ui-layout-toggler-east-closed .fa:before,.ui-layout-toggler-west-open .fa:before{content:\"\\f0d9\"}.ui-layout-mask{border:none!important;padding:0!important;margin:0!important;overflow:hidden!important;position:absolute!important;opacity:0!important;filter:Alpha(Opacity=\"0\")!important}.ui-layout-mask-inside-pane{top:0!important;left:0!important;width:100%!important;height:100%!important}@media print{html{height:auto!important;overflow:visible!important}body.ui-layout-container{position:static!important;top:auto!important;bottom:auto!important;left:auto!important;right:auto!important;_width:auto!important;_height:auto!important}.ui-layout-resizer,.ui-layout-toggler{display:none!important}.ui-layout-pane{border:none!important;background:transparent!important;position:relative!important;top:auto!important;bottom:auto!important;left:auto!important;right:auto!important;width:auto!important;height:auto!important;overflow:visible!important}}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-layout/jquery.layout-latest.js",
    "content": "(function($){var min=Math.min,max=Math.max,round=Math.floor,isStr=function(v){return $.type(v)===\"string\"},runPluginCallbacks=function(Instance,a_fn){if($.isArray(a_fn)){for(var i=0,c=a_fn.length;i<c;i++){var fn=a_fn[i];try{if(isStr(fn)){fn=eval(fn)}if($.isFunction(fn)){g(fn)(Instance)}}catch(ex){}}}function g(f){return f}};$.layout={version:\"1.4.4\",revision:1.0404,browser:{},effects:{slide:{all:{duration:\"fast\"},north:{direction:\"up\"},south:{direction:\"down\"},east:{direction:\"right\"},west:{direction:\"left\"}},drop:{all:{duration:\"slow\"},north:{direction:\"up\"},south:{direction:\"down\"},east:{direction:\"right\"},west:{direction:\"left\"}},scale:{all:{duration:\"fast\"}},blind:{},clip:{},explode:{},fade:{},fold:{},puff:{},size:{all:{easing:\"swing\"}}},config:{optionRootKeys:\"effects,panes,north,south,west,east,center\".split(\",\"),allPanes:\"north,south,west,east,center\".split(\",\"),borderPanes:\"north,south,west,east\".split(\",\"),oppositeEdge:{north:\"south\",south:\"north\",east:\"west\",west:\"east\"},offscreenCSS:{left:\"-99999px\",right:\"auto\"},offscreenReset:\"offscreenReset\",hidden:{visibility:\"hidden\"},visible:{visibility:\"visible\"},resizers:{cssReq:{position:\"absolute\",padding:0,margin:0,fontSize:\"1px\",textAlign:\"left\",overflow:\"hidden\"},cssDemo:{background:\"#DDD\",border:\"none\"}},togglers:{cssReq:{position:\"absolute\",display:\"block\",padding:0,margin:0,overflow:\"hidden\",textAlign:\"center\",fontSize:\"1px\",cursor:\"pointer\",zIndex:1},cssDemo:{background:\"#AAA\"}},content:{cssReq:{position:\"relative\"},cssDemo:{overflow:\"auto\",padding:\"10px\"},cssDemoPane:{overflow:\"hidden\",padding:0}},panes:{cssReq:{position:\"absolute\",margin:0},cssDemo:{padding:\"10px\",background:\"#FFF\",border:\"1px solid #BBB\",overflow:\"auto\"}},north:{side:\"top\",sizeType:\"Height\",dir:\"horz\",cssReq:{top:0,bottom:\"auto\",left:0,right:0,width:\"auto\"}},south:{side:\"bottom\",sizeType:\"Height\",dir:\"horz\",cssReq:{top:\"auto\",bottom:0,left:0,right:0,width:\"auto\"}},east:{side:\"right\",sizeType:\"Width\",dir:\"vert\",cssReq:{left:\"auto\",right:0,top:\"auto\",bottom:\"auto\",height:\"auto\"}},west:{side:\"left\",sizeType:\"Width\",dir:\"vert\",cssReq:{left:0,right:\"auto\",top:\"auto\",bottom:\"auto\",height:\"auto\"}},center:{dir:\"center\",cssReq:{left:\"auto\",right:\"auto\",top:\"auto\",bottom:\"auto\",height:\"auto\",width:\"auto\"}}},callbacks:{},getParentPaneElem:function(el){var $el=$(el),layout=$el.data(\"layout\")||$el.data(\"parentLayout\");if(layout){var $cont=layout.container;if($cont.data(\"layoutPane\")){return $cont}var $pane=$cont.closest(\".\"+$.layout.defaults.panes.paneClass);if($pane.data(\"layoutPane\")){return $pane}}return null},getParentPaneInstance:function(el){var $pane=$.layout.getParentPaneElem(el);return $pane?$pane.data(\"layoutPane\"):null},getParentLayoutInstance:function(el){var $pane=$.layout.getParentPaneElem(el);return $pane?$pane.data(\"parentLayout\"):null},getEventObject:function(evt){return typeof evt===\"object\"&&evt.stopPropagation?evt:null},parsePaneName:function(evt_or_pane){var evt=$.layout.getEventObject(evt_or_pane),pane=evt_or_pane;if(evt){evt.stopPropagation();pane=$(this).data(\"layoutEdge\")}if(pane&&!/^(west|east|north|south|center)$/.test(pane)){$.layout.msg('LAYOUT ERROR - Invalid pane-name: \"'+pane+'\"');pane=\"error\"}return pane},plugins:{draggable:!!$.fn.draggable,effects:{core:!!$.effects,slide:$.effects&&($.effects.slide||($.effects.effect&&$.effects.effect.slide))}},onCreate:[],onLoad:[],onReady:[],onDestroy:[],onUnload:[],afterOpen:[],afterClose:[],scrollbarWidth:function(){return window.scrollbarWidth||$.layout.getScrollbarSize(\"width\")},scrollbarHeight:function(){return window.scrollbarHeight||$.layout.getScrollbarSize(\"height\")},getScrollbarSize:function(dim){var $c=$('<div style=\"position: absolute; top: -10000px; left: -10000px; width: 100px; height: 100px; border: 0; overflow: scroll;\"></div>').appendTo(\"body\"),d={width:$c.outerWidth-$c[0].clientWidth,height:100-$c[0].clientHeight};$c.remove();window.scrollbarWidth=d.width;window.scrollbarHeight=d.height;return dim.match(/^(width|height)$/)?d[dim]:d},disableTextSelection:function(){var $d=$(document),s=\"textSelectionDisabled\",x=\"textSelectionInitialized\";if($.fn.disableSelection){if(!$d.data(x)){$d.on(\"mouseup\",$.layout.enableTextSelection).data(x,true)}if(!$d.data(s)){$d.disableSelection().data(s,true)}}},enableTextSelection:function(){var $d=$(document),s=\"textSelectionDisabled\";if($.fn.enableSelection&&$d.data(s)){$d.enableSelection().data(s,false)}},showInvisibly:function($E,force){if($E&&$E.length&&(force||$E.css(\"display\")===\"none\")){var s=$E[0].style,CSS={display:s.display||\"\",visibility:s.visibility||\"\"};$E.css({display:\"block\",visibility:\"hidden\"});return CSS}return{}},getElementDimensions:function($E,inset){var d={css:{},inset:{}},x=d.css,i={bottom:0},N=$.layout.cssNum,R=Math.round,off=$E.offset(),b,p,ei;d.offsetLeft=off.left;d.offsetTop=off.top;if(!inset){inset={}}$.each(\"Left,Right,Top,Bottom\".split(\",\"),function(idx,e){b=x[\"border\"+e]=$.layout.borderWidth($E,e);p=x[\"padding\"+e]=$.layout.cssNum($E,\"padding\"+e);ei=e.toLowerCase();d.inset[ei]=inset[ei]>=0?inset[ei]:p;i[ei]=d.inset[ei]+b});x.width=R($E.width());x.height=R($E.height());x.top=N($E,\"top\",true);x.bottom=N($E,\"bottom\",true);x.left=N($E,\"left\",true);x.right=N($E,\"right\",true);d.outerWidth=R($E.outerWidth());d.outerHeight=R($E.outerHeight());d.innerWidth=max(0,d.outerWidth-i.left-i.right);d.innerHeight=max(0,d.outerHeight-i.top-i.bottom);d.layoutWidth=R($E.innerWidth());d.layoutHeight=R($E.innerHeight());return d},getElementStyles:function($E,list){var CSS={},style=$E[0].style,props=list.split(\",\"),sides=\"Top,Bottom,Left,Right\".split(\",\"),attrs=\"Color,Style,Width\".split(\",\"),p,s,a,i,j,k;for(i=0;i<props.length;i++){p=props[i];if(p.match(/(border|padding|margin)$/)){for(j=0;j<4;j++){s=sides[j];if(p===\"border\"){for(k=0;k<3;k++){a=attrs[k];CSS[p+s+a]=style[p+s+a]}}else{CSS[p+s]=style[p+s]}}}else{CSS[p]=style[p]}}return CSS},cssWidth:function($E,outerWidth){if(outerWidth<=0){return 0}var lb=$.layout.browser,bs=!lb.boxModel?\"border-box\":lb.boxSizing?$E.css(\"boxSizing\"):\"content-box\",b=$.layout.borderWidth,n=$.layout.cssNum,W=outerWidth;if(bs!==\"border-box\"){W-=(b($E,\"Left\")+b($E,\"Right\"))}if(bs===\"content-box\"){W-=(n($E,\"paddingLeft\")+n($E,\"paddingRight\"))}return max(0,W)},cssHeight:function($E,outerHeight){if(outerHeight<=0){return 0}var lb=$.layout.browser,bs=!lb.boxModel?\"border-box\":lb.boxSizing?$E.css(\"boxSizing\"):\"content-box\",b=$.layout.borderWidth,n=$.layout.cssNum,H=outerHeight;if(bs!==\"border-box\"){H-=(b($E,\"Top\")+b($E,\"Bottom\"))}if(bs===\"content-box\"){H-=(n($E,\"paddingTop\")+n($E,\"paddingBottom\"))}return max(0,H)},cssNum:function($E,prop,allowAuto){if(!$E.jquery){$E=$($E)}var CSS=$.layout.showInvisibly($E),p=$.css($E[0],prop,true),v=allowAuto&&p==\"auto\"?p:Math.round(parseFloat(p)||0);$E.css(CSS);return v},borderWidth:function(el,side){if(el.jquery){el=el[0]}var b=\"border\"+side.substr(0,1).toUpperCase()+side.substr(1);return $.css(el,b+\"Style\",true)===\"none\"?0:Math.round(parseFloat($.css(el,b+\"Width\",true))||0)},isMouseOverElem:function(evt,el){var $E=$(el||this),d=$E.offset(),T=d.top,L=d.left,R=L+$E.outerWidth(),B=T+$E.outerHeight(),x=evt.pageX,y=evt.pageY;return($.layout.browser.msie&&x<0&&y<0)||((x>=L&&x<=R)&&(y>=T&&y<=B))},msg:function(info,popup,debugTitle,debugOpts){if($.isPlainObject(info)&&window.debugData){if(typeof popup===\"string\"){debugOpts=debugTitle;debugTitle=popup}else{if(typeof debugTitle===\"object\"){debugOpts=debugTitle;debugTitle=null}}var t=debugTitle||\"log( <object> )\",o=$.extend({sort:false,returnHTML:false,display:false},debugOpts);if(popup===true||o.display){debugData(info,t,o)}else{if(window.console){console.log(debugData(info,t,o))}}}else{if(popup){alert(info)}else{if(window.console){console.log(info)}else{var id=\"#layoutLogger\",$l=$(id);if(!$l.length){$l=createLog()}$l.children(\"ul\").append('<li style=\"padding: 4px 10px; margin: 0; border-top: 1px solid #CCC;\">'+info.replace(/\\</g,\"&lt;\").replace(/\\>/g,\"&gt;\")+\"</li>\")}}}function createLog(){var pos=$.support.fixedPosition?\"fixed\":\"absolute\",$e=$('<div id=\"layoutLogger\" style=\"position: '+pos+'; top: 5px; z-index: 999999; max-width: 25%; overflow: hidden; border: 1px solid #000; border-radius: 5px; background: #FBFBFB; box-shadow: 0 2px 10px rgba(0,0,0,0.3);\">'+'<div style=\"font-size: 13px; font-weight: bold; padding: 5px 10px; background: #F6F6F6; border-radius: 5px 5px 0 0; cursor: move;\">'+'<span style=\"float: right; padding-left: 7px; cursor: pointer;\" title=\"Remove Console\" onclick=\"$(this).closest(\\'#layoutLogger\\').remove()\">X</span>Layout console.log</div>'+'<ul style=\"font-size: 13px; font-weight: none; list-style: none; margin: 0; padding: 0 0 2px;\"></ul>'+\"</div>\").appendTo(\"body\");$e.css(\"left\",$(window).width()-$e.outerWidth()-5);if($.ui.draggable){$e.draggable({handle:\":first-child\"})}return $e}}};(function(){var u=navigator.userAgent.toLowerCase(),m=/(chrome)[ \\/]([\\w.]+)/.exec(u)||/(webkit)[ \\/]([\\w.]+)/.exec(u)||/(opera)(?:.*version|)[ \\/]([\\w.]+)/.exec(u)||/(msie) ([\\w.]+)/.exec(u)||u.indexOf(\"compatible\")<0&&/(mozilla)(?:.*? rv:([\\w.]+)|)/.exec(u)||[],b=m[1]||\"\",v=m[2]||0,ie=b===\"msie\",cm=document.compatMode,$s=$.support,bs=$s.boxSizing!==undefined?$s.boxSizing:$s.boxSizingReliable,bm=!ie||!cm||cm===\"CSS1Compat\"||$s.boxModel||false,lb=$.layout.browser={version:v,safari:b===\"webkit\",webkit:b===\"chrome\",msie:ie,isIE6:ie&&v==6,boxModel:bm,boxSizing:!!(typeof bs===\"function\"?bs():bs)};if(b){lb[b]=true}if(!bm&&!cm){$(function(){lb.boxModel=$s.boxModel})}})();$.layout.defaults={name:\"\",containerClass:\"ui-layout-container\",inset:null,scrollToBookmarkOnLoad:true,resizeWithWindow:true,resizeWithWindowDelay:50,resizeWithWindowMaxDelay:0,maskPanesEarly:false,onresizeall_start:null,onresizeall_end:null,onload_start:null,onload_end:null,onunload_start:null,onunload_end:null,initPanes:true,showErrorMessages:true,showDebugMessages:false,zIndex:null,zIndexes:{pane_normal:0,content_mask:1,resizer_normal:2,pane_sliding:100,pane_animate:1000,resizer_drag:10000},errors:{pane:\"pane\",selector:\"selector\",addButtonError:\"Error Adding Button\\nInvalid \",containerMissing:\"UI Layout Initialization Error\\nThe specified layout-container does not exist.\",centerPaneMissing:\"UI Layout Initialization Error\\nThe center-pane element does not exist.\\nThe center-pane is a required element.\",noContainerHeight:\"UI Layout Initialization Warning\\nThe layout-container \\\"CONTAINER\\\" has no height.\\nTherefore the layout is 0-height and hence 'invisible'!\",callbackError:\"UI Layout Callback Error\\nThe EVENT callback is not a valid function.\"},panes:{applyDemoStyles:false,closable:true,resizable:true,slidable:true,initClosed:false,initHidden:false,contentSelector:\".ui-layout-content\",contentIgnoreSelector:\".ui-layout-ignore\",findNestedContent:true,paneClass:\"ui-layout-pane\",resizerClass:\"ui-layout-resizer\",togglerClass:\"ui-layout-toggler\",buttonClass:\"ui-layout-button\",minSize:0,maxSize:0,spacing_open:8,spacing_closed:8,togglerLength_open:50,togglerLength_closed:50,togglerAlign_open:\"center\",togglerAlign_closed:\"center\",togglerContent_open:'<i class=\"fa\"></i>',togglerContent_closed:'<i class=\"fa\"></i>',resizerDblClickToggle:true,autoResize:true,autoReopen:true,resizerDragOpacity:1,maskContents:false,maskObjects:false,maskZindex:null,resizingGrid:false,livePaneResizing:false,liveContentResizing:false,liveResizingTolerance:1,sliderCursor:\"pointer\",slideTrigger_open:\"mouseenter\",slideTrigger_close:\"mouseleave\",slideDelay_open:100,slideDelay_close:500,hideTogglerOnSlide:false,preventQuickSlideClose:$.layout.browser.webkit,preventPrematureSlideClose:false,tips:{Open:\"展开\",Close:\"折叠\",Resize:\"调整大小/双击折叠\",Slide:\"鼠标停留自动展开\",Pin:\"Pin\",Unpin:\"Un-Pin\",noRoomToOpen:\"Not enough room to show this panel.\",minSizeWarning:\"Panel has reached its minimum size\",maxSizeWarning:\"Panel has reached its maximum size\"},showOverflowOnHover:false,enableCursorHotkey:true,customHotkeyModifier:\"SHIFT\",fxName:\"slide\",fxSpeed:null,fxSettings:{},fxOpacityFix:true,animatePaneSizing:false,children:null,containerSelector:\"\",initChildren:true,destroyChildren:true,resizeChildren:true,triggerEventsOnLoad:false,triggerEventsDuringLiveResize:true,onshow_start:null,onshow_end:null,onhide_start:null,onhide_end:null,onopen_start:null,onopen_end:null,onclose_start:null,onclose_end:null,onresize_start:null,onresize_end:null,onsizecontent_start:null,onsizecontent_end:null,onswap_start:null,onswap_end:null,ondrag_start:null,ondrag_end:null},north:{paneSelector:\".ui-layout-north\",size:\"auto\",resizerCursor:\"n-resize\",customHotkey:\"\"},south:{paneSelector:\".ui-layout-south\",size:\"auto\",resizerCursor:\"s-resize\",customHotkey:\"\"},east:{paneSelector:\".ui-layout-east\",size:200,resizerCursor:\"e-resize\",customHotkey:\"\"},west:{paneSelector:\".ui-layout-west\",size:200,resizerCursor:\"w-resize\",customHotkey:\"\"},center:{paneSelector:\".ui-layout-center\",minWidth:0,minHeight:0}};$.layout.optionsMap={layout:(\"name,instanceKey,stateManagement,effects,inset,zIndexes,errors,\"+\"zIndex,scrollToBookmarkOnLoad,showErrorMessages,maskPanesEarly,\"+\"outset,resizeWithWindow,resizeWithWindowDelay,resizeWithWindowMaxDelay,\"+\"onresizeall,onresizeall_start,onresizeall_end,onload,onload_start,onload_end,onunload,onunload_start,onunload_end\").split(\",\"),center:(\"paneClass,contentSelector,contentIgnoreSelector,findNestedContent,applyDemoStyles,triggerEventsOnLoad,\"+\"showOverflowOnHover,maskContents,maskObjects,liveContentResizing,\"+\"containerSelector,children,initChildren,resizeChildren,destroyChildren,\"+\"onresize,onresize_start,onresize_end,onsizecontent,onsizecontent_start,onsizecontent_end\").split(\",\"),noDefault:(\"paneSelector,resizerCursor,customHotkey\").split(\",\")};$.layout.transformData=function(hash,addKeys){var json=addKeys?{panes:{},center:{}}:{},branch,optKey,keys,key,val,i,c;if(typeof hash!==\"object\"){return json}for(optKey in hash){branch=json;val=hash[optKey];keys=optKey.split(\"__\");c=keys.length-1;for(i=0;i<=c;i++){key=keys[i];if(i===c){if($.isPlainObject(val)){branch[key]=$.layout.transformData(val)}else{branch[key]=val}}else{if(!branch[key]){branch[key]={}}branch=branch[key]}}}return json};$.layout.backwardCompatibility={map:{applyDefaultStyles:\"applyDemoStyles\",childOptions:\"children\",initChildLayout:\"initChildren\",destroyChildLayout:\"destroyChildren\",resizeChildLayout:\"resizeChildren\",resizeNestedLayout:\"resizeChildren\",resizeWhileDragging:\"livePaneResizing\",resizeContentWhileDragging:\"liveContentResizing\",triggerEventsWhileDragging:\"triggerEventsDuringLiveResize\",maskIframesOnResize:\"maskContents\",useStateCookie:\"stateManagement.enabled\",\"cookie.autoLoad\":\"stateManagement.autoLoad\",\"cookie.autoSave\":\"stateManagement.autoSave\",\"cookie.keys\":\"stateManagement.stateKeys\",\"cookie.name\":\"stateManagement.cookie.name\",\"cookie.domain\":\"stateManagement.cookie.domain\",\"cookie.path\":\"stateManagement.cookie.path\",\"cookie.expires\":\"stateManagement.cookie.expires\",\"cookie.secure\":\"stateManagement.cookie.secure\",noRoomToOpenTip:\"tips.noRoomToOpen\",togglerTip_open:\"tips.Close\",togglerTip_closed:\"tips.Open\",resizerTip:\"tips.Resize\",sliderTip:\"tips.Slide\"},renameOptions:function(opts){var map=$.layout.backwardCompatibility.map,oldData,newData,value;for(var itemPath in map){oldData=getBranch(itemPath);value=oldData.branch[oldData.key];if(value!==undefined){newData=getBranch(map[itemPath],true);newData.branch[newData.key]=value;delete oldData.branch[oldData.key]}}function getBranch(path,create){var a=path.split(\".\"),c=a.length-1,D={branch:opts,key:a[c]},i=0,k,undef;for(;i<c;i++){k=a[i];if(D.branch[k]==undefined){if(create){D.branch=D.branch[k]={}}else{D.branch={}}}else{D.branch=D.branch[k]}}return D}},renameAllOptions:function(opts){var ren=$.layout.backwardCompatibility.renameOptions;ren(opts);if(opts.defaults){if(typeof opts.panes!==\"object\"){opts.panes={}}$.extend(true,opts.panes,opts.defaults);delete opts.defaults}if(opts.panes){ren(opts.panes)}$.each($.layout.config.allPanes,function(i,pane){if(opts[pane]){ren(opts[pane])}});return opts}};$.fn.layout=function(opts){var browser=$.layout.browser,_c=$.layout.config,cssW=$.layout.cssWidth,cssH=$.layout.cssHeight,elDims=$.layout.getElementDimensions,styles=$.layout.getElementStyles,evtObj=$.layout.getEventObject,evtPane=$.layout.parsePaneName,options=$.extend(true,{},$.layout.defaults),effects=options.effects=$.extend(true,{},$.layout.effects),state={id:\"layout\"+$.now(),initialized:false,paneResizing:false,panesSliding:{},container:{innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0,layoutWidth:0,layoutHeight:0},north:{childIdx:0},south:{childIdx:0},east:{childIdx:0},west:{childIdx:0},center:{childIdx:0}},children={north:null,south:null,east:null,west:null,center:null},timer={data:{},set:function(s,fn,ms){timer.clear(s);timer.data[s]=setTimeout(fn,ms)},clear:function(s){var t=timer.data;if(t[s]){clearTimeout(t[s]);delete t[s]}}},_log=function(msg,popup,debug){var o=options;if((o.showErrorMessages&&!debug)||(debug&&o.showDebugMessages)){$.layout.msg(o.name+\" / \"+msg,(popup!==false))}return false},_runCallbacks=function(evtName,pane,skipBoundEvents){var hasPane=pane&&isStr(pane),s=hasPane?state[pane]:state,o=hasPane?options[pane]:options,lName=options.name,lng=evtName+(evtName.match(/_/)?\"\":\"_end\"),shrt=lng.match(/_end$/)?lng.substr(0,lng.length-4):\"\",fn=o[lng]||o[shrt],retVal=\"NC\",args=[],$P=hasPane?$Ps[pane]:0;if(hasPane&&!$P){return retVal}if(!hasPane&&$.type(pane)===\"boolean\"){skipBoundEvents=pane;pane=\"\"}if(fn){try{if(isStr(fn)){if(fn.match(/,/)){args=fn.split(\",\"),fn=eval(args[0])}else{fn=eval(fn)}}if($.isFunction(fn)){if(args.length){retVal=g(fn)(args[1])}else{if(hasPane){retVal=g(fn)(pane,$Ps[pane],s,o,lName)}else{retVal=g(fn)(Instance,s,o,lName)}}}}catch(ex){_log(options.errors.callbackError.replace(/EVENT/,$.trim((pane||\"\")+\" \"+lng)),false);if($.type(ex)===\"string\"&&string.length){_log(\"Exception:  \"+ex,false)}}}if(!skipBoundEvents&&retVal!==false){if(hasPane){o=options[pane];s=state[pane];$P.triggerHandler(\"layoutpane\"+lng,[pane,$P,s,o,lName]);if(shrt){$P.triggerHandler(\"layoutpane\"+shrt,[pane,$P,s,o,lName])}}else{$N.triggerHandler(\"layout\"+lng,[Instance,s,o,lName]);if(shrt){$N.triggerHandler(\"layout\"+shrt,[Instance,s,o,lName])}}}if(hasPane&&evtName===\"onresize_end\"){resizeChildren(pane+\"\",true)}return retVal;function g(f){return f}},_fixIframe=function(pane){if(browser.mozilla){return}var $P=$Ps[pane];if(state[pane].tagName===\"IFRAME\"){$P.css(_c.hidden).css(_c.visible)}else{$P.find(\"IFRAME\").css(_c.hidden).css(_c.visible)}},cssSize=function(pane,outerSize){var fn=_c[pane].dir==\"horz\"?cssH:cssW;return fn($Ps[pane],outerSize)},cssMinDims=function(pane){var $P=$Ps[pane],dir=_c[pane].dir,d={minWidth:1001-cssW($P,1000),minHeight:1001-cssH($P,1000)};if(dir===\"horz\"){d.minSize=d.minHeight}if(dir===\"vert\"){d.minSize=d.minWidth}return d},setOuterWidth=function(el,outerWidth,autoHide){var $E=el,w;if(isStr(el)){$E=$Ps[el]}else{if(!el.jquery){$E=$(el)}}w=cssW($E,outerWidth);$E.css({width:w});if(w>0){if(autoHide&&$E.data(\"autoHidden\")&&$E.innerHeight()>0){$E.show().data(\"autoHidden\",false);if(!browser.mozilla){$E.css(_c.hidden).css(_c.visible)}}}else{if(autoHide&&!$E.data(\"autoHidden\")){$E.hide().data(\"autoHidden\",true)}}},setOuterHeight=function(el,outerHeight,autoHide){var $E=el,h;if(isStr(el)){$E=$Ps[el]}else{if(!el.jquery){$E=$(el)}}h=cssH($E,outerHeight);$E.css({height:h,visibility:\"visible\"});if(h>0&&$E.innerWidth()>0){if(autoHide&&$E.data(\"autoHidden\")){$E.show().data(\"autoHidden\",false);if(!browser.mozilla){$E.css(_c.hidden).css(_c.visible)}}}else{if(autoHide&&!$E.data(\"autoHidden\")){$E.hide().data(\"autoHidden\",true)}}},_parseSize=function(pane,size,dir){if(!dir){dir=_c[pane].dir}if(isStr(size)&&size.match(/%/)){size=(size===\"100%\")?-1:parseInt(size,10)/100}if(size===0){return 0}else{if(size>=1){return parseInt(size,10)}}var o=options,avail=0;if(dir==\"horz\"){avail=sC.innerHeight-($Ps.north?o.north.spacing_open:0)-($Ps.south?o.south.spacing_open:0)}else{if(dir==\"vert\"){avail=sC.innerWidth-($Ps.west?o.west.spacing_open:0)-($Ps.east?o.east.spacing_open:0)}}if(size===-1){return avail}else{if(size>0){return round(avail*size)}else{if(pane==\"center\"){return 0}else{var dim=(dir===\"horz\"?\"height\":\"width\"),$P=$Ps[pane],$C=dim===\"height\"?$Cs[pane]:false,vis=$.layout.showInvisibly($P),szP=$P.css(dim),szC=$C?$C.css(dim):0;$P.css(dim,\"auto\");if($C){$C.css(dim,\"auto\")}size=(dim===\"height\")?$P.outerHeight():$P.outerWidth();$P.css(dim,szP).css(vis);if($C){$C.css(dim,szC)}return size}}}},getPaneSize=function(pane,inclSpace){var $P=$Ps[pane],o=options[pane],s=state[pane],oSp=(inclSpace?o.spacing_open:0),cSp=(inclSpace?o.spacing_closed:0);if(!$P||s.isHidden){return 0}else{if(s.isClosed||(s.isSliding&&inclSpace)){return cSp}else{if(_c[pane].dir===\"horz\"){return $P.outerHeight()+oSp}else{return $P.outerWidth()+oSp}}}},setSizeLimits=function(pane,slide){if(!isInitialized()){return}var o=options[pane],s=state[pane],c=_c[pane],dir=c.dir,type=c.sizeType.toLowerCase(),isSliding=(slide!=undefined?slide:s.isSliding),$P=$Ps[pane],paneSpacing=o.spacing_open,altPane=_c.oppositeEdge[pane],altS=state[altPane],$altP=$Ps[altPane],altPaneSize=(!$altP||altS.isVisible===false||altS.isSliding?0:(dir==\"horz\"?$altP.outerHeight():$altP.outerWidth())),altPaneSpacing=((!$altP||altS.isHidden?0:options[altPane][altS.isClosed!==false?\"spacing_closed\":\"spacing_open\"])||0),containerSize=(dir==\"horz\"?sC.innerHeight:sC.innerWidth),minCenterDims=cssMinDims(\"center\"),minCenterSize=dir==\"horz\"?max(options.center.minHeight,minCenterDims.minHeight):max(options.center.minWidth,minCenterDims.minWidth),limitSize=(containerSize-paneSpacing-(isSliding?0:(_parseSize(\"center\",minCenterSize,dir)+altPaneSize+altPaneSpacing))),minSize=s.minSize=max(_parseSize(pane,o.minSize),cssMinDims(pane).minSize),maxSize=s.maxSize=min((o.maxSize?_parseSize(pane,o.maxSize):100000),limitSize),r=s.resizerPosition={},top=sC.inset.top,left=sC.inset.left,W=sC.innerWidth,H=sC.innerHeight,rW=o.spacing_open;switch(pane){case\"north\":r.min=top+minSize;r.max=top+maxSize;break;case\"west\":r.min=left+minSize;r.max=left+maxSize;break;case\"south\":r.min=top+H-maxSize-rW;r.max=top+H-minSize-rW;break;case\"east\":r.min=left+W-maxSize-rW;r.max=left+W-minSize-rW;break}},calcNewCenterPaneDims=function(){var d={top:getPaneSize(\"north\",true),bottom:getPaneSize(\"south\",true),left:getPaneSize(\"west\",true),right:getPaneSize(\"east\",true),width:0,height:0};d.width=sC.innerWidth-d.left-d.right;d.height=sC.innerHeight-d.bottom-d.top;d.top+=sC.inset.top;d.bottom+=sC.inset.bottom;d.left+=sC.inset.left;d.right+=sC.inset.right;return d},getHoverClasses=function(el,allStates){var $El=$(el),type=$El.data(\"layoutRole\"),pane=$El.data(\"layoutEdge\"),o=options[pane],root=o[type+\"Class\"],_pane=\"-\"+pane,_open=\"-open\",_closed=\"-closed\",_slide=\"-sliding\",_hover=\"-hover \",_state=$El.hasClass(root+_closed)?_closed:_open,_alt=_state===_closed?_open:_closed,classes=(root+_hover)+(root+_pane+_hover)+(root+_state+_hover)+(root+_pane+_state+_hover);if(allStates){classes+=(root+_alt+_hover)+(root+_pane+_alt+_hover)}if(type==\"resizer\"&&$El.hasClass(root+_slide)){classes+=(root+_slide+_hover)+(root+_pane+_slide+_hover)}return $.trim(classes)},addHover=function(evt,el){var $E=$(el||this);if(evt&&$E.data(\"layoutRole\")===\"toggler\"){evt.stopPropagation()}$E.addClass(getHoverClasses($E))},removeHover=function(evt,el){var $E=$(el||this);$E.removeClass(getHoverClasses($E,true))},onResizerEnter=function(evt){var pane=$(this).data(\"layoutEdge\"),s=state[pane],$d=$(document);if(s.isResizing||state.paneResizing){return}if(options.maskPanesEarly){showMasks(pane,{resizing:true})}},onResizerLeave=function(evt,el){var e=el||this,pane=$(e).data(\"layoutEdge\"),name=pane+\"ResizerLeave\",$d=$(document);timer.clear(pane+\"_openSlider\");timer.clear(name);if(!el){timer.set(name,function(){onResizerLeave(evt,e)},200)}else{if(options.maskPanesEarly&&!state.paneResizing){hideMasks()}}},_create=function(){initOptions();var o=options,s=state;s.creatingLayout=true;runPluginCallbacks(Instance,$.layout.onCreate);if(false===_runCallbacks(\"onload_start\")){return\"cancel\"}_initContainer();initHotkeys();$(window).bind(\"unload.\"+sID,unload);runPluginCallbacks(Instance,$.layout.onLoad);if(o.initPanes){_initLayoutElements()}delete s.creatingLayout;return state.initialized},isInitialized=function(){if(state.initialized||state.creatingLayout){return true}else{return _initLayoutElements()}},_initLayoutElements=function(retry){var o=options;if(!$N.is(\":visible\")){if(!retry&&browser.webkit&&$N[0].tagName===\"BODY\"){setTimeout(function(){_initLayoutElements(true)},50)}return false}if(!getPane(\"center\").length){return _log(o.errors.centerPaneMissing)}state.creatingLayout=true;$.extend(sC,elDims($N,o.inset));initPanes();if(o.scrollToBookmarkOnLoad){var l=self.location;if(l.hash){l.replace(l.hash)}}if(Instance.hasParentLayout){o.resizeWithWindow=false}else{if(o.resizeWithWindow){$(window).bind(\"resize.\"+sID,windowResize)}}delete state.creatingLayout;state.initialized=true;runPluginCallbacks(Instance,$.layout.onReady);_runCallbacks(\"onload_end\");return true},createChildren=function(evt_or_pane,opts){var pane=evtPane.call(this,evt_or_pane),$P=$Ps[pane];if(!$P){return}var $C=$Cs[pane],s=state[pane],o=options[pane],sm=options.stateManagement||{},cos=opts?(o.children=opts):o.children;if($.isPlainObject(cos)){cos=[cos]}else{if(!cos||!$.isArray(cos)){return}}$.each(cos,function(idx,co){if(!$.isPlainObject(co)){return}var $containers=co.containerSelector?$P.find(co.containerSelector):($C||$P);$containers.each(function(){var $cont=$(this),child=$cont.data(\"layout\");if(!child){setInstanceKey({container:$cont,options:co},s);if(sm.includeChildren&&state.stateData[pane]){var paneChildren=state.stateData[pane].children||{},childState=paneChildren[co.instanceKey],co_sm=co.stateManagement||(co.stateManagement={autoLoad:true});if(co_sm.autoLoad===true&&childState){co_sm.autoSave=false;co_sm.includeChildren=true;co_sm.autoLoad=$.extend(true,{},childState)}}child=$cont.layout(co);if(child){refreshChildren(pane,child)}}})})},setInstanceKey=function(child,parentPaneState){var $c=child.container,o=child.options,sm=o.stateManagement,key=o.instanceKey||$c.data(\"layoutInstanceKey\");if(!key){key=(sm&&sm.cookie?sm.cookie.name:\"\")||o.name}if(!key){key=\"layout\"+(++parentPaneState.childIdx)}else{key=key.replace(/[^\\w-]/gi,\"_\").replace(/_{2,}/g,\"_\")}o.instanceKey=key;$c.data(\"layoutInstanceKey\",key);return key},refreshChildren=function(pane,newChild){var $P=$Ps[pane],pC=children[pane],s=state[pane],o;if($.isPlainObject(pC)){$.each(pC,function(key,child){if(child.destroyed){delete pC[key]}});if($.isEmptyObject(pC)){pC=children[pane]=null}}if(!newChild&&!pC){newChild=$P.data(\"layout\")}if(newChild){newChild.hasParentLayout=true;o=newChild.options;setInstanceKey(newChild,s);if(!pC){pC=children[pane]={}}pC[o.instanceKey]=newChild.container.data(\"layout\")}Instance[pane].children=children[pane];if(!newChild){createChildren(pane)}},windowResize=function(){var o=options,delay=Number(o.resizeWithWindowDelay);if(delay<10){delay=100}timer.clear(\"winResize\");timer.set(\"winResize\",function(){timer.clear(\"winResize\");timer.clear(\"winResizeRepeater\");var dims=elDims($N,o.inset);if(dims.innerWidth!==sC.innerWidth||dims.innerHeight!==sC.innerHeight){resizeAll()}},delay);if(!timer.data[\"winResizeRepeater\"]){setWindowResizeRepeater()}},setWindowResizeRepeater=function(){var delay=Number(options.resizeWithWindowMaxDelay);if(delay>0){timer.set(\"winResizeRepeater\",function(){setWindowResizeRepeater();resizeAll()},delay)}},unload=function(){var o=options;_runCallbacks(\"onunload_start\");runPluginCallbacks(Instance,$.layout.onUnload);_runCallbacks(\"onunload_end\")},_initContainer=function(){var N=$N[0],$H=$(\"html\"),tag=sC.tagName=N.tagName,id=sC.id=N.id,cls=sC.className=N.className,o=options,name=o.name,props=\"position,margin,padding,border\",css=\"layoutCSS\",CSS={},hid=\"hidden\",parent=$N.data(\"parentLayout\"),pane=$N.data(\"layoutEdge\"),isChild=parent&&pane,num=$.layout.cssNum,$parent,n;if($N.selector!==undefined){alert($N.selector);sC.selector=$N.selector.split(\".slice\")[0]}sC.ref=(o.name?o.name+\" layout / \":\"\")+tag+(id?\"#\"+id:cls?\".[\"+cls+\"]\":\"\");sC.isBody=(tag===\"BODY\");if(!isChild&&!sC.isBody){$parent=$N.closest(\".\"+$.layout.defaults.panes.paneClass);parent=$parent.data(\"parentLayout\");pane=$parent.data(\"layoutEdge\");isChild=parent&&pane}$N.data({layout:Instance,layoutContainer:sID}).addClass(o.containerClass);var layoutMethods={destroy:\"\",initPanes:\"\",resizeAll:\"resizeAll\",resize:\"resizeAll\"};for(name in layoutMethods){$N.bind(\"layout\"+name.toLowerCase()+\".\"+sID,Instance[layoutMethods[name]||name])}if(isChild){Instance.hasParentLayout=true;parent.refreshChildren(pane,Instance)}if(!$N.data(css)){if(sC.isBody){$N.data(css,$.extend(styles($N,props),{height:$N.css(\"height\"),overflow:$N.css(\"overflow\"),overflowX:$N.css(\"overflowX\"),overflowY:$N.css(\"overflowY\")}));$H.data(css,$.extend(styles($H,\"padding\"),{height:\"auto\",overflow:$H.css(\"overflow\"),overflowX:$H.css(\"overflowX\"),overflowY:$H.css(\"overflowY\")}))}else{$N.data(css,styles($N,props+\",top,bottom,left,right,width,height,overflow,overflowX,overflowY\"))}}try{CSS={overflow:hid,overflowX:hid,overflowY:hid};$N.css(CSS);if(o.inset&&!$.isPlainObject(o.inset)){n=parseInt(o.inset,10)||0;o.inset={top:n,bottom:n,left:n,right:n}}if(sC.isBody){if(!o.outset){o.outset={top:num($H,\"paddingTop\"),bottom:num($H,\"paddingBottom\"),left:num($H,\"paddingLeft\"),right:num($H,\"paddingRight\")}}else{if(!$.isPlainObject(o.outset)){n=parseInt(o.outset,10)||0;o.outset={top:n,bottom:n,left:n,right:n}}}$H.css(CSS).css({height:\"100%\",border:\"none\",padding:0,margin:0});if(browser.isIE6){$N.css({width:\"100%\",height:\"100%\",border:\"none\",padding:0,margin:0,position:\"relative\"});if(!o.inset){o.inset=elDims($N).inset}}else{$N.css({width:\"auto\",height:\"auto\",margin:0,position:\"absolute\"});$N.css(o.outset)}$.extend(sC,elDims($N,o.inset))}else{var p=$N.css(\"position\");if(!p||!p.match(/(fixed|absolute|relative)/)){$N.css(\"position\",\"relative\")}if($N.is(\":visible\")){$.extend(sC,elDims($N,o.inset));if(sC.innerHeight<1){_log(o.errors.noContainerHeight.replace(/CONTAINER/,sC.ref))}}}if(num($N,\"minWidth\")){$N.parent().css(\"overflowX\",\"auto\")}if(num($N,\"minHeight\")){$N.parent().css(\"overflowY\",\"auto\")}}catch(ex){}},initHotkeys=function(panes){panes=panes?panes.split(\",\"):_c.borderPanes;$.each(panes,function(i,pane){var o=options[pane];if(o.enableCursorHotkey||o.customHotkey){$(document).bind(\"keydown.\"+sID,keyDown);return false}})},initOptions=function(){var data,d,pane,key,val,i,c,o;opts=$.layout.transformData(opts,true);opts=$.layout.backwardCompatibility.renameAllOptions(opts);if(!$.isEmptyObject(opts.panes)){data=$.layout.optionsMap.noDefault;for(i=0,c=data.length;i<c;i++){key=data[i];delete opts.panes[key]}data=$.layout.optionsMap.layout;for(i=0,c=data.length;i<c;i++){key=data[i];delete opts.panes[key]}}data=$.layout.optionsMap.layout;var rootKeys=$.layout.config.optionRootKeys;for(key in opts){val=opts[key];if($.inArray(key,rootKeys)<0&&$.inArray(key,data)<0){if(!opts.panes[key]){opts.panes[key]=$.isPlainObject(val)?$.extend(true,{},val):val}delete opts[key]}}$.extend(true,options,opts);$.each(_c.allPanes,function(i,pane){_c[pane]=$.extend(true,{},_c.panes,_c[pane]);d=options.panes;o=options[pane];if(pane===\"center\"){data=$.layout.optionsMap.center;for(i=0,c=data.length;i<c;i++){key=data[i];if(!opts.center[key]&&(opts.panes[key]||!o[key])){o[key]=d[key]}}}else{o=options[pane]=$.extend(true,{},d,o);createFxOptions(pane);if(!o.resizerClass){o.resizerClass=\"ui-layout-resizer\"}if(!o.togglerClass){o.togglerClass=\"ui-layout-toggler\"}}if(!o.paneClass){o.paneClass=\"ui-layout-pane\"}});var zo=opts.zIndex,z=options.zIndexes;if(zo>0){z.pane_normal=zo;z.content_mask=max(zo+1,z.content_mask);z.resizer_normal=max(zo+2,z.resizer_normal)}delete options.panes;function createFxOptions(pane){var o=options[pane],d=options.panes;if(!o.fxSettings){o.fxSettings={}}if(!d.fxSettings){d.fxSettings={}}$.each([\"_open\",\"_close\",\"_size\"],function(i,n){var sName=\"fxName\"+n,sSpeed=\"fxSpeed\"+n,sSettings=\"fxSettings\"+n,fxName=o[sName]=o[sName]||d[sName]||o.fxName||d.fxName||\"none\",fxExists=$.effects&&($.effects[fxName]||($.effects.effect&&$.effects.effect[fxName]));if(fxName===\"none\"||!options.effects[fxName]||!fxExists){fxName=o[sName]=\"none\"}var fx=options.effects[fxName]||{},fx_all=fx.all||null,fx_pane=fx[pane]||null;o[sSpeed]=o[sSpeed]||d[sSpeed]||o.fxSpeed||d.fxSpeed||null;o[sSettings]=$.extend(true,{},fx_all,fx_pane,d.fxSettings,o.fxSettings,d[sSettings],o[sSettings])});delete o.fxName;delete o.fxSpeed;delete o.fxSettings}},getPane=function(pane){var sel=options[pane].paneSelector;if(sel.substr(0,1)===\"#\"){return $N.find(sel).eq(0)}else{var $P=$N.children(sel).eq(0);return $P.length?$P:$N.children(\"form:first\").children(sel).eq(0)}},initPanes=function(evt){evtPane(evt);$.each(_c.allPanes,function(idx,pane){addPane(pane,true)});initHandles();$.each(_c.borderPanes,function(i,pane){if($Ps[pane]&&state[pane].isVisible){setSizeLimits(pane);makePaneFit(pane)}});sizeMidPanes(\"center\");$.each(_c.allPanes,function(idx,pane){afterInitPane(pane)})},addPane=function(pane,force){if(!force&&!isInitialized()){return}var o=options[pane],s=state[pane],c=_c[pane],dir=c.dir,fx=s.fx,spacing=o.spacing_open||0,isCenter=(pane===\"center\"),CSS={},$P=$Ps[pane],size,minSize,maxSize,child;if($P){removePane(pane,false,true,false)}else{$Cs[pane]=false}$P=$Ps[pane]=getPane(pane);if(!$P.length){$Ps[pane]=false;return}if(!$P.data(\"layoutCSS\")){var props=\"position,top,left,bottom,right,width,height,overflow,zIndex,display,backgroundColor,padding,margin,border\";$P.data(\"layoutCSS\",styles($P,props))}Instance[pane]={name:pane,pane:$Ps[pane],content:$Cs[pane],options:options[pane],state:state[pane],children:children[pane]};$P.data({parentLayout:Instance,layoutPane:Instance[pane],layoutEdge:pane,layoutRole:\"pane\"}).css(c.cssReq).css(\"zIndex\",options.zIndexes.pane_normal).css(o.applyDemoStyles?c.cssDemo:{}).addClass(o.paneClass+\" \"+o.paneClass+\"-\"+pane).bind(\"mouseenter.\"+sID,addHover).bind(\"mouseleave.\"+sID,removeHover);var paneMethods={hide:\"\",show:\"\",toggle:\"\",close:\"\",open:\"\",slideOpen:\"\",slideClose:\"\",slideToggle:\"\",size:\"sizePane\",sizePane:\"sizePane\",sizeContent:\"\",sizeHandles:\"\",enableClosable:\"\",disableClosable:\"\",enableSlideable:\"\",disableSlideable:\"\",enableResizable:\"\",disableResizable:\"\",swapPanes:\"swapPanes\",swap:\"swapPanes\",move:\"swapPanes\",removePane:\"removePane\",remove:\"removePane\",createChildren:\"\",resizeChildren:\"\",resizeAll:\"resizeAll\",resizeLayout:\"resizeAll\"},name;for(name in paneMethods){$P.bind(\"layoutpane\"+name.toLowerCase()+\".\"+sID,Instance[paneMethods[name]||name])}initContent(pane,false);if(!isCenter){size=s.size=_parseSize(pane,o.size);minSize=_parseSize(pane,o.minSize)||1;maxSize=_parseSize(pane,o.maxSize)||100000;if(size>0){size=max(min(size,maxSize),minSize)}s.autoResize=o.autoResize;s.isClosed=false;s.isSliding=false;s.isResizing=false;s.isHidden=false;if(!s.pins){s.pins=[]}}s.tagName=$P[0].tagName;s.edge=pane;s.noRoom=false;s.isVisible=true;setPanePosition(pane);if(dir===\"horz\"){CSS.height=cssH($P,size)}else{if(dir===\"vert\"){CSS.width=cssW($P,size)}}$P.css(CSS);if(dir!=\"horz\"){sizeMidPanes(pane,true)}if(state.initialized){initHandles(pane);initHotkeys(pane)}if(o.initClosed&&o.closable&&!o.initHidden){close(pane,true,true)}else{if(o.initHidden||o.initClosed){hide(pane)}else{if(!s.noRoom){$P.css(\"display\",\"block\")}}}$P.css(\"visibility\",\"visible\");if(o.showOverflowOnHover){$P.hover(allowOverflow,resetOverflow)}if(state.initialized){afterInitPane(pane)}},afterInitPane=function(pane){var $P=$Ps[pane],s=state[pane],o=options[pane];if(!$P){return}if($P.data(\"layout\")){refreshChildren(pane,$P.data(\"layout\"))}if(s.isVisible){if(state.initialized){resizeAll()}else{sizeContent(pane)}if(o.triggerEventsOnLoad){_runCallbacks(\"onresize_end\",pane)}else{resizeChildren(pane,true)}}if(o.initChildren&&o.children){createChildren(pane)}},setPanePosition=function(panes){panes=panes?panes.split(\",\"):_c.borderPanes;$.each(panes,function(i,pane){var $P=$Ps[pane],$R=$Rs[pane],o=options[pane],s=state[pane],side=_c[pane].side,CSS={};if(!$P){return}switch(pane){case\"north\":CSS.top=sC.inset.top;CSS.left=sC.inset.left;CSS.right=sC.inset.right;break;case\"south\":CSS.bottom=sC.inset.bottom;CSS.left=sC.inset.left;CSS.right=sC.inset.right;break;case\"west\":CSS.left=sC.inset.left;break;case\"east\":CSS.right=sC.inset.right;break;case\"center\":}$P.css(CSS);if($R&&s.isClosed){$R.css(side,sC.inset[side])}else{if($R&&!s.isHidden){$R.css(side,sC.inset[side]+getPaneSize(pane))}}})},initHandles=function(panes){panes=panes?panes.split(\",\"):_c.borderPanes;$.each(panes,function(i,pane){var $P=$Ps[pane];$Rs[pane]=false;$Ts[pane]=false;if(!$P){return}var o=options[pane],s=state[pane],c=_c[pane],paneId=o.paneSelector.substr(0,1)===\"#\"?o.paneSelector.substr(1):\"\",rClass=o.resizerClass,tClass=o.togglerClass,spacing=(s.isVisible?o.spacing_open:o.spacing_closed),_pane=\"-\"+pane,_state=(s.isVisible?\"-open\":\"-closed\"),I=Instance[pane],$R=I.resizer=$Rs[pane]=$(\"<div></div>\"),$T=I.toggler=(o.closable?$Ts[pane]=$(\"<div></div>\"):false);if(!s.isVisible&&o.slidable){$R.attr(\"title\",o.tips.Slide).css(\"cursor\",o.sliderCursor)}$R.attr(\"id\",paneId?paneId+\"-resizer\":\"\").data({parentLayout:Instance,layoutPane:Instance[pane],layoutEdge:pane,layoutRole:\"resizer\"}).css(_c.resizers.cssReq).css(\"zIndex\",options.zIndexes.resizer_normal).css(o.applyDemoStyles?_c.resizers.cssDemo:{}).addClass(rClass+\" \"+rClass+_pane).hover(addHover,removeHover).hover(onResizerEnter,onResizerLeave).mousedown($.layout.disableTextSelection).mouseup($.layout.enableTextSelection).appendTo($N);if($.fn.disableSelection){$R.disableSelection()}if(o.resizerDblClickToggle){$R.bind(\"dblclick.\"+sID,toggle)}if($T){$T.attr(\"id\",paneId?paneId+\"-toggler\":\"\").data({parentLayout:Instance,layoutPane:Instance[pane],layoutEdge:pane,layoutRole:\"toggler\"}).css(_c.togglers.cssReq).css(o.applyDemoStyles?_c.togglers.cssDemo:{}).addClass(tClass+\" \"+tClass+_pane).hover(addHover,removeHover).bind(\"mouseenter\",onResizerEnter).appendTo($R);if(o.togglerContent_open){$(\"<span>\"+o.togglerContent_open+\"</span>\").data({layoutEdge:pane,layoutRole:\"togglerContent\"}).data(\"layoutRole\",\"togglerContent\").data(\"layoutEdge\",pane).addClass(\"ui-content content-open\").css(\"display\",\"none\").appendTo($T)}if(o.togglerContent_closed){$(\"<span>\"+o.togglerContent_closed+\"</span>\").data({layoutEdge:pane,layoutRole:\"togglerContent\"}).addClass(\"ui-content content-closed\").css(\"display\",\"none\").appendTo($T)}enableClosable(pane)}initResizable(pane);if(s.isVisible){setAsOpen(pane)}else{setAsClosed(pane);bindStartSlidingEvents(pane,true)}});sizeHandles()},initContent=function(pane,resize){if(!isInitialized()){return}var o=options[pane],sel=o.contentSelector,I=Instance[pane],$P=$Ps[pane],$C;if(sel){$C=I.content=$Cs[pane]=(o.findNestedContent)?$P.find(sel).eq(0):$P.children(sel).eq(0)}if($C&&$C.length){$C.data(\"layoutRole\",\"content\");if(!$C.data(\"layoutCSS\")){$C.data(\"layoutCSS\",styles($C,\"height\"))}$C.css(_c.content.cssReq);if(o.applyDemoStyles){$C.css(_c.content.cssDemo);$P.css(_c.content.cssDemoPane)}if($P.css(\"overflowX\").match(/(scroll|auto)/)){$P.css(\"overflow\",\"hidden\")}state[pane].content={};if(resize!==false){sizeContent(pane)}}else{I.content=$Cs[pane]=false}},initResizable=function(panes){var draggingAvailable=$.layout.plugins.draggable,side;panes=panes?panes.split(\",\"):_c.borderPanes;$.each(panes,function(idx,pane){var o=options[pane];if(!draggingAvailable||!$Ps[pane]||!o.resizable){o.resizable=false;return true}var s=state[pane],z=options.zIndexes,c=_c[pane],side=c.dir==\"horz\"?\"top\":\"left\",$P=$Ps[pane],$R=$Rs[pane],base=o.resizerClass,lastPos=0,r,live,resizerClass=base+\"-drag\",resizerPaneClass=base+\"-\"+pane+\"-drag\",helperClass=base+\"-dragging\",helperPaneClass=base+\"-\"+pane+\"-dragging\",helperLimitClass=base+\"-dragging-limit\",helperPaneLimitClass=base+\"-\"+pane+\"-dragging-limit\",helperClassesSet=false;if(!s.isClosed){$R.attr(\"title\",o.tips.Resize).css(\"cursor\",o.resizerCursor)}$R.draggable({containment:$N[0],axis:(c.dir==\"horz\"?\"y\":\"x\"),delay:0,distance:1,grid:o.resizingGrid,helper:\"clone\",opacity:o.resizerDragOpacity,addClasses:false,zIndex:z.resizer_drag,iframeFix:true,start:function(e,ui){o=options[pane];s=state[pane];live=o.livePaneResizing;if(false===_runCallbacks(\"ondrag_start\",pane)){return false}s.isResizing=true;state.paneResizing=pane;timer.clear(pane+\"_closeSlider\");setSizeLimits(pane);r=s.resizerPosition;lastPos=ui.position[side];$R.addClass(resizerClass+\" \"+resizerPaneClass);helperClassesSet=false;showMasks(pane,{resizing:true})},drag:function(e,ui){if(!helperClassesSet){ui.helper.addClass(helperClass+\" \"+helperPaneClass).css({right:\"auto\",bottom:\"auto\"}).children().css(\"visibility\",\"hidden\");helperClassesSet=true;if(s.isSliding){$Ps[pane].css(\"zIndex\",z.pane_sliding)}}var limit=0;if(ui.position[side]<r.min){ui.position[side]=r.min;limit=-1}else{if(ui.position[side]>r.max){ui.position[side]=r.max;limit=1}}if(limit){ui.helper.addClass(helperLimitClass+\" \"+helperPaneLimitClass);window.defaultStatus=(limit>0&&pane.match(/(north|west)/))||(limit<0&&pane.match(/(south|east)/))?o.tips.maxSizeWarning:o.tips.minSizeWarning}else{ui.helper.removeClass(helperLimitClass+\" \"+helperPaneLimitClass);window.defaultStatus=\"\"}if(live&&Math.abs(ui.position[side]-lastPos)>=o.liveResizingTolerance){lastPos=ui.position[side];resizePanes(e,ui,pane)}},stop:function(e,ui){$(\"body\").enableSelection();window.defaultStatus=\"\";$R.removeClass(resizerClass+\" \"+resizerPaneClass);s.isResizing=false;state.paneResizing=false;resizePanes(e,ui,pane,true)}})});var resizePanes=function(evt,ui,pane,resizingDone){var dragPos=ui.position,c=_c[pane],o=options[pane],s=state[pane],resizerPos;switch(pane){case\"north\":resizerPos=dragPos.top;break;case\"west\":resizerPos=dragPos.left;break;case\"south\":resizerPos=sC.layoutHeight-dragPos.top-o.spacing_open;break;case\"east\":resizerPos=sC.layoutWidth-dragPos.left-o.spacing_open;break}var newSize=resizerPos-sC.inset[c.side];if(!resizingDone){if(Math.abs(newSize-s.size)<o.liveResizingTolerance){return}manualSizePane(pane,newSize,false,true);sizeMasks()}else{if(false!==_runCallbacks(\"ondrag_end\",pane)){manualSizePane(pane,newSize,false,true)}hideMasks(true);if(s.isSliding){showMasks(pane,{resizing:true})}}}},sizeMask=function(){var $M=$(this),pane=$M.data(\"layoutMask\"),s=state[pane];if(s.tagName==\"IFRAME\"&&s.isVisible){$M.css({top:s.offsetTop,left:s.offsetLeft,width:s.outerWidth,height:s.outerHeight})}},sizeMasks=function(){$Ms.each(sizeMask)},showMasks=function(pane,args){var c=_c[pane],panes=[\"center\"],z=options.zIndexes,a=$.extend({objectsOnly:false,animation:false,resizing:true,sliding:state[pane].isSliding},args),o,s;if(a.resizing){panes.push(pane)}if(a.sliding){panes.push(_c.oppositeEdge[pane])}if(c.dir===\"horz\"){panes.push(\"west\");panes.push(\"east\")}$.each(panes,function(i,p){s=state[p];o=options[p];if(s.isVisible&&(o.maskObjects||(!a.objectsOnly&&o.maskContents))){getMasks(p).each(function(){sizeMask.call(this);this.style.zIndex=s.isSliding?z.pane_sliding+1:z.pane_normal+1;this.style.display=\"block\"})}})},hideMasks=function(force){if(force||!state.paneResizing){$Ms.hide()}else{if(!force&&!$.isEmptyObject(state.panesSliding)){var i=$Ms.length-1,p,$M;for(;i>=0;i--){$M=$Ms.eq(i);p=$M.data(\"layoutMask\");if(!options[p].maskObjects){$M.hide()}}}}},getMasks=function(pane){var $Masks=$([]),$M,i=0,c=$Ms.length;for(;i<c;i++){$M=$Ms.eq(i);if($M.data(\"layoutMask\")===pane){$Masks=$Masks.add($M)}}if($Masks.length){return $Masks}else{return createMasks(pane)}},createMasks=function(pane){var $P=$Ps[pane],s=state[pane],o=options[pane],z=options.zIndexes,isIframe,el,$M,css,i;if(!o.maskContents&&!o.maskObjects){return $([])}for(i=0;i<(o.maskObjects?2:1);i++){isIframe=o.maskObjects&&i==0;el=document.createElement(isIframe?\"iframe\":\"div\");$M=$(el).data(\"layoutMask\",pane);el.className=\"ui-layout-mask ui-layout-mask-\"+pane;css=el.style;css.background=\"#FFF\";css.position=\"absolute\";css.display=\"block\";if(isIframe){el.src=\"about:blank\";el.frameborder=0;css.border=0;css.opacity=0;css.filter=\"Alpha(Opacity='0')\"}else{css.opacity=0.001;css.filter=\"Alpha(Opacity='1')\"}if(s.tagName==\"IFRAME\"){css.zIndex=z.pane_normal+1;$N.append(el)}else{$M.addClass(\"ui-layout-mask-inside-pane\");css.zIndex=o.maskZindex||z.content_mask;css.top=0;css.left=0;css.width=\"100%\";css.height=\"100%\";$P.append(el)}$Ms=$Ms.add(el)}return $Ms},destroy=function(evt_or_destroyChildren,destroyChildren){$(window).unbind(\".\"+sID);$(document).unbind(\".\"+sID);if(typeof evt_or_destroyChildren===\"object\"){evtPane(evt_or_destroyChildren)}else{destroyChildren=evt_or_destroyChildren}$N.clearQueue().removeData(\"layout\").removeData(\"layoutContainer\").removeClass(options.containerClass).unbind(\".\"+sID);$Ms.remove();$.each(_c.allPanes,function(i,pane){removePane(pane,false,true,destroyChildren)});var css=\"layoutCSS\";if($N.data(css)&&!$N.data(\"layoutRole\")){$N.css($N.data(css)).removeData(css)}if(sC.tagName===\"BODY\"&&($N=$(\"html\")).data(css)){$N.css($N.data(css)).removeData(css)}runPluginCallbacks(Instance,$.layout.onDestroy);unload();for(var n in Instance){if(!n.match(/^(container|options)$/)){delete Instance[n]}}Instance.destroyed=true;return Instance},removePane=function(evt_or_pane,remove,skipResize,destroyChild){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$P=$Ps[pane],$C=$Cs[pane],$R=$Rs[pane],$T=$Ts[pane];if($P&&$.isEmptyObject($P.data())){$P=false}if($C&&$.isEmptyObject($C.data())){$C=false}if($R&&$.isEmptyObject($R.data())){$R=false}if($T&&$.isEmptyObject($T.data())){$T=false}if($P){$P.stop(true,true)}var o=options[pane],s=state[pane],d=\"layout\",css=\"layoutCSS\",pC=children[pane],hasChildren=$.isPlainObject(pC)&&!$.isEmptyObject(pC),destroy=destroyChild!==undefined?destroyChild:o.destroyChildren;if(hasChildren&&destroy){$.each(pC,function(key,child){if(!child.destroyed){child.destroy(true)}if(child.destroyed){delete pC[key]}});if($.isEmptyObject(pC)){pC=children[pane]=null;hasChildren=false}}if($P&&remove&&!hasChildren){$P.remove()}else{if($P&&$P[0]){var root=o.paneClass,pRoot=root+\"-\"+pane,_open=\"-open\",_sliding=\"-sliding\",_closed=\"-closed\",classes=[root,root+_open,root+_closed,root+_sliding,pRoot,pRoot+_open,pRoot+_closed,pRoot+_sliding];$.merge(classes,getHoverClasses($P,true));$P.removeClass(classes.join(\" \")).removeData(\"parentLayout\").removeData(\"layoutPane\").removeData(\"layoutRole\").removeData(\"layoutEdge\").removeData(\"autoHidden\").unbind(\".\"+sID);if(hasChildren&&$C){$C.width($C.width());$.each(pC,function(key,child){child.resizeAll()})}else{if($C){$C.css($C.data(css)).removeData(css).removeData(\"layoutRole\")}}if(!$P.data(d)){$P.css($P.data(css)).removeData(css)}}}if($T){$T.remove()}if($R){$R.remove()}Instance[pane]=$Ps[pane]=$Cs[pane]=$Rs[pane]=$Ts[pane]=false;s={removed:true};if(!skipResize){resizeAll()}},_hidePane=function(pane){var $P=$Ps[pane],o=options[pane],s=$P[0].style;if(o.useOffscreenClose){if(!$P.data(_c.offscreenReset)){$P.data(_c.offscreenReset,{left:s.left,right:s.right})}$P.css(_c.offscreenCSS)}else{$P.hide().removeData(_c.offscreenReset)}},_showPane=function(pane){var $P=$Ps[pane],o=options[pane],off=_c.offscreenCSS,old=$P.data(_c.offscreenReset),s=$P[0].style;$P.show().removeData(_c.offscreenReset);if(o.useOffscreenClose&&old){if(s.left==off.left){s.left=old.left}if(s.right==off.right){s.right=old.right}}},hide=function(evt_or_pane,noAnimation){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),o=options[pane],s=state[pane],$P=$Ps[pane],$R=$Rs[pane];if(pane===\"center\"||!$P||s.isHidden){return}if(state.initialized&&false===_runCallbacks(\"onhide_start\",pane)){return}s.isSliding=false;delete state.panesSliding[pane];if($R){$R.hide()}if(!state.initialized||s.isClosed){s.isClosed=true;s.isHidden=true;s.isVisible=false;if(!state.initialized){_hidePane(pane)}sizeMidPanes(_c[pane].dir===\"horz\"?\"\":\"center\");if(state.initialized||o.triggerEventsOnLoad){_runCallbacks(\"onhide_end\",pane)}}else{s.isHiding=true;close(pane,false,noAnimation)}},show=function(evt_or_pane,openPane,noAnimation,noAlert){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),o=options[pane],s=state[pane],$P=$Ps[pane],$R=$Rs[pane];if(pane===\"center\"||!$P||!s.isHidden){return}if(false===_runCallbacks(\"onshow_start\",pane)){return}s.isShowing=true;s.isSliding=false;delete state.panesSliding[pane];if(openPane===false){close(pane,true)}else{open(pane,false,noAnimation,noAlert)}},toggle=function(evt_or_pane,slide){if(!isInitialized()){return}var evt=evtObj(evt_or_pane),pane=evtPane.call(this,evt_or_pane),s=state[pane];if(evt){evt.stopImmediatePropagation()}if(s.isHidden){show(pane)}else{if(s.isClosed){open(pane,!!slide)}else{close(pane)}}},_closePane=function(pane,setHandles){var $P=$Ps[pane],s=state[pane];_hidePane(pane);s.isClosed=true;s.isVisible=false;if(setHandles){setAsClosed(pane)}},close=function(evt_or_pane,force,noAnimation,skipCallback){var pane=evtPane.call(this,evt_or_pane);if(pane===\"center\"){return}if(!state.initialized&&$Ps[pane]){_closePane(pane,true);return}if(!isInitialized()){return}var $P=$Ps[pane],$R=$Rs[pane],$T=$Ts[pane],o=options[pane],s=state[pane],c=_c[pane],doFX,isShowing,isHiding,wasSliding;$N.queue(function(queueNext){if(!$P||(!o.closable&&!s.isShowing&&!s.isHiding)||(!force&&s.isClosed&&!s.isShowing)){return queueNext()}var abort=!s.isShowing&&false===_runCallbacks(\"onclose_start\",pane);isShowing=s.isShowing;isHiding=s.isHiding;wasSliding=s.isSliding;delete s.isShowing;delete s.isHiding;if(abort){return queueNext()}doFX=!noAnimation&&!s.isClosed&&(o.fxName_close!=\"none\");s.isMoving=true;s.isClosed=true;s.isVisible=false;if(isHiding){s.isHidden=true}else{if(isShowing){s.isHidden=false}}if(s.isSliding){bindStopSlidingEvents(pane,false)}else{sizeMidPanes(_c[pane].dir===\"horz\"?\"\":\"center\",false)}setAsClosed(pane);if(doFX){lockPaneForFX(pane,true);$P.hide(o.fxName_close,o.fxSettings_close,o.fxSpeed_close,function(){lockPaneForFX(pane,false);if(s.isClosed){close_2()}queueNext()\r\n})}else{_hidePane(pane);close_2();queueNext()}});function close_2(){s.isMoving=false;bindStartSlidingEvents(pane,true);var altPane=_c.oppositeEdge[pane];if(state[altPane].noRoom){setSizeLimits(altPane);makePaneFit(altPane)}if(!skipCallback&&(state.initialized||o.triggerEventsOnLoad)){if(!isShowing){_runCallbacks(\"onclose_end\",pane)}if(isShowing){_runCallbacks(\"onshow_end\",pane)}if(isHiding){_runCallbacks(\"onhide_end\",pane)}}}},setAsClosed=function(pane){if(!$Rs[pane]){return}var $P=$Ps[pane],$R=$Rs[pane],$T=$Ts[pane],o=options[pane],s=state[pane],side=_c[pane].side,rClass=o.resizerClass,tClass=o.togglerClass,_pane=\"-\"+pane,_open=\"-open\",_sliding=\"-sliding\",_closed=\"-closed\";$R.css(side,sC.inset[side]).removeClass(rClass+_open+\" \"+rClass+_pane+_open).removeClass(rClass+_sliding+\" \"+rClass+_pane+_sliding).addClass(rClass+_closed+\" \"+rClass+_pane+_closed);if(s.isHidden){$R.hide()}if(o.resizable&&$.layout.plugins.draggable){$R.draggable(\"disable\").removeClass(\"ui-state-disabled\").css(\"cursor\",\"default\").attr(\"title\",\"\")}if($T){$T.removeClass(tClass+_open+\" \"+tClass+_pane+_open).addClass(tClass+_closed+\" \"+tClass+_pane+_closed).attr(\"title\",o.tips.Open);$T.children(\".content-open\").hide();$T.children(\".content-closed\").css(\"display\",\"block\")}syncPinBtns(pane,false);if(state.initialized){sizeHandles()}},open=function(evt_or_pane,slide,noAnimation,noAlert){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$P=$Ps[pane],$R=$Rs[pane],$T=$Ts[pane],o=options[pane],s=state[pane],c=_c[pane],doFX,isShowing;if(pane===\"center\"){return}$N.queue(function(queueNext){if(!$P||(!o.resizable&&!o.closable&&!s.isShowing)||(s.isVisible&&!s.isSliding)){return queueNext()}if(s.isHidden&&!s.isShowing){queueNext();show(pane,true);return}if(s.autoResize&&s.size!=o.size){sizePane(pane,o.size,true,true,true)}else{setSizeLimits(pane,slide)}var cbReturn=_runCallbacks(\"onopen_start\",pane);if(cbReturn===\"abort\"){return queueNext()}if(cbReturn!==\"NC\"){setSizeLimits(pane,slide)}if(s.minSize>s.maxSize){syncPinBtns(pane,false);if(!noAlert&&o.tips.noRoomToOpen){alert(o.tips.noRoomToOpen)}return queueNext()}if(slide){bindStopSlidingEvents(pane,true)}else{if(s.isSliding){bindStopSlidingEvents(pane,false)}else{if(o.slidable){bindStartSlidingEvents(pane,false)}}}s.noRoom=false;makePaneFit(pane);isShowing=s.isShowing;delete s.isShowing;doFX=!noAnimation&&s.isClosed&&(o.fxName_open!=\"none\");s.isMoving=true;s.isVisible=true;s.isClosed=false;if(isShowing){s.isHidden=false}if(doFX){lockPaneForFX(pane,true);$P.show(o.fxName_open,o.fxSettings_open,o.fxSpeed_open,function(){lockPaneForFX(pane,false);if(s.isVisible){open_2()}queueNext()})}else{_showPane(pane);open_2();queueNext()}});function open_2(){s.isMoving=false;_fixIframe(pane);if(!s.isSliding){sizeMidPanes(_c[pane].dir==\"vert\"?\"center\":\"\",false)}setAsOpen(pane)}},setAsOpen=function(pane,skipCallback){var $P=$Ps[pane],$R=$Rs[pane],$T=$Ts[pane],o=options[pane],s=state[pane],side=_c[pane].side,rClass=o.resizerClass,tClass=o.togglerClass,_pane=\"-\"+pane,_open=\"-open\",_closed=\"-closed\",_sliding=\"-sliding\";$R.css(side,sC.inset[side]+getPaneSize(pane)).removeClass(rClass+_closed+\" \"+rClass+_pane+_closed).addClass(rClass+_open+\" \"+rClass+_pane+_open);if(s.isSliding){$R.addClass(rClass+_sliding+\" \"+rClass+_pane+_sliding)}else{$R.removeClass(rClass+_sliding+\" \"+rClass+_pane+_sliding)}removeHover(0,$R);if(o.resizable&&$.layout.plugins.draggable){$R.draggable(\"enable\").css(\"cursor\",o.resizerCursor).attr(\"title\",o.tips.Resize)}else{if(!s.isSliding){$R.css(\"cursor\",\"default\")}}if($T){$T.removeClass(tClass+_closed+\" \"+tClass+_pane+_closed).addClass(tClass+_open+\" \"+tClass+_pane+_open).attr(\"title\",o.tips.Close);removeHover(0,$T);$T.children(\".content-closed\").hide();$T.children(\".content-open\").css(\"display\",\"block\")}syncPinBtns(pane,!s.isSliding);$.extend(s,elDims($P));if(state.initialized){sizeHandles();sizeContent(pane,true)}if(!skipCallback&&(state.initialized||o.triggerEventsOnLoad)&&$P.is(\":visible\")){_runCallbacks(\"onopen_end\",pane);if(s.isShowing){_runCallbacks(\"onshow_end\",pane)}if(state.initialized){_runCallbacks(\"onresize_end\",pane)}}},slideOpen=function(evt_or_pane){if(!isInitialized()){return}var evt=evtObj(evt_or_pane),pane=evtPane.call(this,evt_or_pane),s=state[pane],delay=options[pane].slideDelay_open;if(pane===\"center\"){return}if(evt){evt.stopImmediatePropagation()}if(s.isClosed&&evt&&evt.type===\"mouseenter\"&&delay>0){timer.set(pane+\"_openSlider\",open_NOW,delay)}else{open_NOW()}function open_NOW(){if(!s.isClosed){bindStopSlidingEvents(pane,true)}else{if(!s.isMoving){open(pane,true)}}}},slideClose=function(evt_or_pane){if(!isInitialized()){return}var evt=evtObj(evt_or_pane),pane=evtPane.call(this,evt_or_pane),o=options[pane],s=state[pane],delay=s.isMoving?1000:300;if(pane===\"center\"){return}if(s.isClosed||s.isResizing){return}else{if(o.slideTrigger_close===\"click\"){close_NOW()}else{if(o.preventQuickSlideClose&&s.isMoving){return}else{if(o.preventPrematureSlideClose&&evt&&$.layout.isMouseOverElem(evt,$Ps[pane])){return}else{if(evt){timer.set(pane+\"_closeSlider\",close_NOW,max(o.slideDelay_close,delay))}else{close_NOW()}}}}}function close_NOW(){if(s.isClosed){bindStopSlidingEvents(pane,false)}else{if(!s.isMoving){close(pane)}}}},slideToggle=function(evt_or_pane){var pane=evtPane.call(this,evt_or_pane);toggle(pane,true)},lockPaneForFX=function(pane,doLock){var $P=$Ps[pane],s=state[pane],o=options[pane],z=options.zIndexes;if(doLock){showMasks(pane,{animation:true,objectsOnly:true});$P.css({zIndex:z.pane_animate});if(pane==\"south\"){$P.css({top:sC.inset.top+sC.innerHeight-$P.outerHeight()})}else{if(pane==\"east\"){$P.css({left:sC.inset.left+sC.innerWidth-$P.outerWidth()})}}}else{hideMasks();$P.css({zIndex:(s.isSliding?z.pane_sliding:z.pane_normal)});if(pane==\"south\"){$P.css({top:\"auto\"})}else{if(pane==\"east\"&&!$P.css(\"left\").match(/\\-99999/)){$P.css({left:\"auto\"})}}if(browser.msie&&o.fxOpacityFix&&o.fxName_open!=\"slide\"&&$P.css(\"filter\")&&$P.css(\"opacity\")==1){$P[0].style.removeAttribute(\"filter\")}}},bindStartSlidingEvents=function(pane,enable){var o=options[pane],$P=$Ps[pane],$R=$Rs[pane],evtName=o.slideTrigger_open.toLowerCase();if(!$R||(enable&&!o.slidable)){return}if(evtName.match(/mouseover/)){evtName=o.slideTrigger_open=\"mouseenter\"}else{if(!evtName.match(/(click|dblclick|mouseenter)/)){evtName=o.slideTrigger_open=\"click\"}}if(o.resizerDblClickToggle&&evtName.match(/click/)){$R[enable?\"unbind\":\"bind\"](\"dblclick.\"+sID,toggle)}$R[enable?\"bind\":\"unbind\"](evtName+\".\"+sID,slideOpen).css(\"cursor\",enable?o.sliderCursor:\"default\").attr(\"title\",enable?o.tips.Slide:\"\")},bindStopSlidingEvents=function(pane,enable){var o=options[pane],s=state[pane],c=_c[pane],z=options.zIndexes,evtName=o.slideTrigger_close.toLowerCase(),action=(enable?\"bind\":\"unbind\"),$P=$Ps[pane],$R=$Rs[pane];timer.clear(pane+\"_closeSlider\");if(enable){s.isSliding=true;state.panesSliding[pane]=true;bindStartSlidingEvents(pane,false)}else{s.isSliding=false;delete state.panesSliding[pane]}$P.css(\"zIndex\",enable?z.pane_sliding:z.pane_normal);$R.css(\"zIndex\",enable?z.pane_sliding+2:z.resizer_normal);if(!evtName.match(/(click|mouseleave)/)){evtName=o.slideTrigger_close=\"mouseleave\"}$R[action](evtName,slideClose);if(evtName===\"mouseleave\"){$P[action](\"mouseleave.\"+sID,slideClose);$R[action](\"mouseenter.\"+sID,cancelMouseOut);$P[action](\"mouseenter.\"+sID,cancelMouseOut)}if(!enable){timer.clear(pane+\"_closeSlider\")}else{if(evtName===\"click\"&&!o.resizable){$R.css(\"cursor\",enable?o.sliderCursor:\"default\");$R.attr(\"title\",enable?o.tips.Close:\"\")}}function cancelMouseOut(evt){timer.clear(pane+\"_closeSlider\");evt.stopPropagation()}},makePaneFit=function(pane,isOpening,skipCallback,force){var o=options[pane],s=state[pane],c=_c[pane],$P=$Ps[pane],$R=$Rs[pane],isSidePane=c.dir===\"vert\",hasRoom=false;if(pane===\"center\"||(isSidePane&&s.noVerticalRoom)){hasRoom=(s.maxHeight>=0);if(hasRoom&&s.noRoom){_showPane(pane);if($R){$R.show()}s.isVisible=true;s.noRoom=false;if(isSidePane){s.noVerticalRoom=false}_fixIframe(pane)}else{if(!hasRoom&&!s.noRoom){_hidePane(pane);if($R){$R.hide()}s.isVisible=false;s.noRoom=true}}}if(pane===\"center\"){}else{if(s.minSize<=s.maxSize){hasRoom=true;if(s.size>s.maxSize){sizePane(pane,s.maxSize,skipCallback,true,force)}else{if(s.size<s.minSize){sizePane(pane,s.minSize,skipCallback,true,force)}else{if($R&&s.isVisible&&$P.is(\":visible\")){var pos=s.size+sC.inset[c.side];if($.layout.cssNum($R,c.side)!=pos){$R.css(c.side,pos)}}}}if(s.noRoom){if(s.wasOpen&&o.closable){if(o.autoReopen){open(pane,false,true,true)}else{s.noRoom=false}}else{show(pane,s.wasOpen,true,true)}}}else{if(!s.noRoom){s.noRoom=true;s.wasOpen=!s.isClosed&&!s.isSliding;if(s.isClosed){}else{if(o.closable){close(pane,true,true)}else{hide(pane,true)}}}}}},manualSizePane=function(evt_or_pane,size,skipCallback,noAnimation,force){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),o=options[pane],s=state[pane],forceResize=force||(o.livePaneResizing&&!s.isResizing);if(pane===\"center\"){return}s.autoResize=false;sizePane(pane,size,skipCallback,noAnimation,forceResize)},sizePane=function(evt_or_pane,size,skipCallback,noAnimation,force){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),o=options[pane],s=state[pane],$P=$Ps[pane],$R=$Rs[pane],side=_c[pane].side,dimName=_c[pane].sizeType.toLowerCase(),skipResizeWhileDragging=s.isResizing&&!o.triggerEventsDuringLiveResize,doFX=noAnimation!==true&&o.animatePaneSizing,oldSize,newSize;if(pane===\"center\"){return}$N.queue(function(queueNext){setSizeLimits(pane);oldSize=s.size;size=_parseSize(pane,size);size=max(size,_parseSize(pane,o.minSize));size=min(size,s.maxSize);if(size<s.minSize){queueNext();makePaneFit(pane,false,skipCallback);return}if(!force&&size===oldSize){return queueNext()}s.newSize=size;if(!skipCallback&&state.initialized&&s.isVisible){_runCallbacks(\"onresize_start\",pane)}newSize=cssSize(pane,size);if(doFX&&$P.is(\":visible\")){var fx=$.layout.effects.size[pane]||$.layout.effects.size.all,easing=o.fxSettings_size.easing||fx.easing,z=options.zIndexes,props={};props[dimName]=newSize+\"px\";s.isMoving=true;$P.css({zIndex:z.pane_animate}).show().animate(props,o.fxSpeed_size,easing,function(){$P.css({zIndex:(s.isSliding?z.pane_sliding:z.pane_normal)});s.isMoving=false;delete s.newSize;sizePane_2();queueNext()})}else{$P.css(dimName,newSize);delete s.newSize;if($P.is(\":visible\")){sizePane_2()}else{s.size=size}queueNext()}});function sizePane_2(){var actual=dimName===\"width\"?$P.outerWidth():$P.outerHeight(),tries=[{pane:pane,count:1,target:size,actual:actual,correct:(size===actual),attempt:size,cssSize:newSize}],lastTry=tries[0],thisTry={},msg=\"Inaccurate size after resizing the \"+pane+\"-pane.\";while(!lastTry.correct){thisTry={pane:pane,count:lastTry.count+1,target:size};if(lastTry.actual>size){thisTry.attempt=max(0,lastTry.attempt-(lastTry.actual-size))}else{thisTry.attempt=max(0,lastTry.attempt+(size-lastTry.actual))}thisTry.cssSize=cssSize(pane,thisTry.attempt);$P.css(dimName,thisTry.cssSize);thisTry.actual=dimName==\"width\"?$P.outerWidth():$P.outerHeight();thisTry.correct=(size===thisTry.actual);if(tries.length===1){_log(msg,false,true);_log(lastTry,false,true)}_log(thisTry,false,true);if(tries.length>3){break}tries.push(thisTry);lastTry=tries[tries.length-1]}s.size=size;$.extend(s,elDims($P));if(s.isVisible&&$P.is(\":visible\")){if($R){$R.css(side,size+sC.inset[side])}sizeContent(pane)}if(!skipCallback&&!skipResizeWhileDragging&&state.initialized&&s.isVisible){_runCallbacks(\"onresize_end\",pane)}if(!skipCallback){if(!s.isSliding){sizeMidPanes(_c[pane].dir==\"horz\"?\"\":\"center\",skipResizeWhileDragging,force)}sizeHandles()}var altPane=_c.oppositeEdge[pane];if(size<oldSize&&state[altPane].noRoom){setSizeLimits(altPane);makePaneFit(altPane,false,skipCallback)}if(tries.length>1){_log(msg+\"\\nSee the Error Console for details.\",true,true)}}},sizeMidPanes=function(panes,skipCallback,force){panes=(panes?panes:\"east,west,center\").split(\",\");$.each(panes,function(i,pane){if(!$Ps[pane]){return}var o=options[pane],s=state[pane],$P=$Ps[pane],$R=$Rs[pane],isCenter=(pane==\"center\"),hasRoom=true,CSS={},visCSS=$.layout.showInvisibly($P),newCenter=calcNewCenterPaneDims();$.extend(s,elDims($P));if(pane===\"center\"){if(!force&&s.isVisible&&newCenter.width===s.outerWidth&&newCenter.height===s.outerHeight){$P.css(visCSS);return true}$.extend(s,cssMinDims(pane),{maxWidth:newCenter.width,maxHeight:newCenter.height});CSS=newCenter;s.newWidth=CSS.width;s.newHeight=CSS.height;CSS.width=cssW($P,CSS.width);CSS.height=cssH($P,CSS.height);hasRoom=CSS.width>=0&&CSS.height>=0;if(!state.initialized&&o.minWidth>newCenter.width){var reqPx=o.minWidth-s.outerWidth,minE=options.east.minSize||0,minW=options.west.minSize||0,sizeE=state.east.size,sizeW=state.west.size,newE=sizeE,newW=sizeW;if(reqPx>0&&state.east.isVisible&&sizeE>minE){newE=max(sizeE-minE,sizeE-reqPx);reqPx-=sizeE-newE}if(reqPx>0&&state.west.isVisible&&sizeW>minW){newW=max(sizeW-minW,sizeW-reqPx);reqPx-=sizeW-newW}if(reqPx===0){if(sizeE&&sizeE!=minE){sizePane(\"east\",newE,true,true,force)}if(sizeW&&sizeW!=minW){sizePane(\"west\",newW,true,true,force)}sizeMidPanes(\"center\",skipCallback,force);$P.css(visCSS);return}}}else{if(s.isVisible&&!s.noVerticalRoom){$.extend(s,elDims($P),cssMinDims(pane))}if(!force&&!s.noVerticalRoom&&newCenter.height===s.outerHeight){$P.css(visCSS);return true}CSS.top=newCenter.top;CSS.bottom=newCenter.bottom;s.newSize=newCenter.height;CSS.height=cssH($P,newCenter.height);s.maxHeight=CSS.height;hasRoom=(s.maxHeight>=0);if(!hasRoom){s.noVerticalRoom=true}}if(hasRoom){if(!skipCallback&&state.initialized){_runCallbacks(\"onresize_start\",pane)}$P.css(CSS);if(pane!==\"center\"){sizeHandles(pane)}if(s.noRoom&&!s.isClosed&&!s.isHidden){makePaneFit(pane)}if(s.isVisible){$.extend(s,elDims($P));if(state.initialized){sizeContent(pane)}}}else{if(!s.noRoom&&s.isVisible){makePaneFit(pane)}}$P.css(visCSS);delete s.newSize;delete s.newWidth;delete s.newHeight;if(!s.isVisible){return true}if(pane===\"center\"){var fix=browser.isIE6||!browser.boxModel;if($Ps.north&&(fix||state.north.tagName==\"IFRAME\")){$Ps.north.css(\"width\",cssW($Ps.north,sC.innerWidth))}if($Ps.south&&(fix||state.south.tagName==\"IFRAME\")){$Ps.south.css(\"width\",cssW($Ps.south,sC.innerWidth))}}if(!skipCallback&&state.initialized){_runCallbacks(\"onresize_end\",pane)}})},resizeAll=function(evt_or_refresh){var oldW=sC.innerWidth,oldH=sC.innerHeight;evtPane(evt_or_refresh);if(!$N.is(\":visible\")){return}if(!state.initialized){_initLayoutElements();return}if(evt_or_refresh===true&&$.isPlainObject(options.outset)){$N.css(options.outset)}$.extend(sC,elDims($N,options.inset));if(!sC.outerHeight){return}if(evt_or_refresh===true){setPanePosition()}if(false===_runCallbacks(\"onresizeall_start\")){return false}var shrunkH=(sC.innerHeight<oldH),shrunkW=(sC.innerWidth<oldW),$P,o,s;$.each([\"south\",\"north\",\"east\",\"west\"],function(i,pane){if(!$Ps[pane]){return}o=options[pane];s=state[pane];if(s.autoResize&&s.size!=o.size){sizePane(pane,o.size,true,true,true)}else{setSizeLimits(pane);makePaneFit(pane,false,true,true)}});sizeMidPanes(\"\",true,true);sizeHandles();$.each(_c.allPanes,function(i,pane){$P=$Ps[pane];if(!$P){return}if(state[pane].isVisible){_runCallbacks(\"onresize_end\",pane)}});_runCallbacks(\"onresizeall_end\")},resizeChildren=function(evt_or_pane,skipRefresh){var pane=evtPane.call(this,evt_or_pane);if(!options[pane].resizeChildren){return}if(!skipRefresh){refreshChildren(pane)}var pC=children[pane];if($.isPlainObject(pC)){$.each(pC,function(key,child){if(!child.destroyed){child.resizeAll()}})}},sizeContent=function(evt_or_panes,remeasure){if(!isInitialized()){return}var panes=evtPane.call(this,evt_or_panes);panes=panes?panes.split(\",\"):_c.allPanes;$.each(panes,function(idx,pane){var $P=$Ps[pane],$C=$Cs[pane],o=options[pane],s=state[pane],m=s.content;if(!$P||!$C||!$P.is(\":visible\")){return true}if(!$C.length){initContent(pane,false);if(!$C){return}}if(false===_runCallbacks(\"onsizecontent_start\",pane)){return}if((!s.isMoving&&!s.isResizing)||o.liveContentResizing||remeasure||m.top==undefined){_measure();if(m.hiddenFooters>0&&$P.css(\"overflow\")===\"hidden\"){$P.css(\"overflow\",\"visible\");_measure();$P.css(\"overflow\",\"hidden\")}}var newH=s.innerHeight-(m.spaceAbove-s.css.paddingTop)-(m.spaceBelow-s.css.paddingBottom);if(!$C.is(\":visible\")||m.height!=newH){setOuterHeight($C,newH,true);m.height=newH}if(state.initialized){_runCallbacks(\"onsizecontent_end\",pane)}function _below($E){return max(s.css.paddingBottom,(parseInt($E.css(\"marginBottom\"),10)||0))}function _measure(){var ignore=options[pane].contentIgnoreSelector,$Fs=$C.nextAll().not(\".ui-layout-mask\").not(ignore||\":lt(0)\"),$Fs_vis=$Fs.filter(\":visible\"),$F=$Fs_vis.filter(\":last\");m={top:$C[0].offsetTop,height:$C.outerHeight(),numFooters:$Fs.length,hiddenFooters:$Fs.length-$Fs_vis.length,spaceBelow:0};m.spaceAbove=m.top;m.bottom=m.top+m.height;if($F.length){m.spaceBelow=($F[0].offsetTop+$F.outerHeight())-m.bottom+_below($F)}else{m.spaceBelow=_below($C)}}})},sizeHandles=function(evt_or_panes){var panes=evtPane.call(this,evt_or_panes);panes=panes?panes.split(\",\"):_c.borderPanes;$.each(panes,function(i,pane){var o=options[pane],s=state[pane],$P=$Ps[pane],$R=$Rs[pane],$T=$Ts[pane],$TC;if(!$P||!$R){return}var dir=_c[pane].dir,_state=(s.isClosed?\"_closed\":\"_open\"),spacing=o[\"spacing\"+_state],togAlign=o[\"togglerAlign\"+_state],togLen=o[\"togglerLength\"+_state],paneLen,left,offset,CSS={};if(spacing===0){$R.hide();return}else{if(!s.noRoom&&!s.isHidden){$R.show()}}if(dir===\"horz\"){paneLen=sC.innerWidth;s.resizerLength=paneLen;left=$.layout.cssNum($P,\"left\");$R.css({width:cssW($R,paneLen),height:cssH($R,spacing),left:left>-9999?left:sC.inset.left})}else{paneLen=$P.outerHeight();s.resizerLength=paneLen;$R.css({height:cssH($R,paneLen),width:cssW($R,spacing),top:sC.inset.top+getPaneSize(\"north\",true)})}removeHover(o,$R);if($T){if(togLen===0||(s.isSliding&&o.hideTogglerOnSlide)){$T.hide();return}else{$T.show()}if(!(togLen>0)||togLen===\"100%\"||togLen>paneLen){togLen=paneLen;offset=0}else{if(isStr(togAlign)){switch(togAlign){case\"top\":case\"left\":offset=0;break;case\"bottom\":case\"right\":offset=paneLen-togLen;break;case\"middle\":case\"center\":default:offset=round((paneLen-togLen)/2)}}else{var x=parseInt(togAlign,10);if(togAlign>=0){offset=x}else{offset=paneLen-togLen+x}}}if(dir===\"horz\"){var width=cssW($T,togLen);$T.css({width:width,height:cssH($T,spacing),left:offset,top:0})}else{var height=cssH($T,togLen);$T.css({height:height,width:cssW($T,spacing),top:offset,left:0});$T.children(\".ui-content\").each(function(){$TC=$(this);$TC.css(\"marginTop\",round((height-$TC.outerHeight())/2))})}removeHover(0,$T)}if(!state.initialized&&(o.initHidden||s.isHidden)){$R.hide();if($T){$T.hide()}}})},enableClosable=function(evt_or_pane){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$T=$Ts[pane],o=options[pane];if(!$T){return}o.closable=true;$T.bind(\"click.\"+sID,function(evt){evt.stopPropagation();toggle(pane)}).css(\"visibility\",\"visible\").css(\"cursor\",\"pointer\").attr(\"title\",state[pane].isClosed?o.tips.Open:o.tips.Close).show()},disableClosable=function(evt_or_pane,hide){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$T=$Ts[pane];if(!$T){return}options[pane].closable=false;if(state[pane].isClosed){open(pane,false,true)}$T.unbind(\".\"+sID).css(\"visibility\",hide?\"hidden\":\"visible\").css(\"cursor\",\"default\").attr(\"title\",\"\")},enableSlidable=function(evt_or_pane){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$R=$Rs[pane];if(!$R||!$R.data(\"draggable\")){return}options[pane].slidable=true;if(state[pane].isClosed){bindStartSlidingEvents(pane,true)}},disableSlidable=function(evt_or_pane){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$R=$Rs[pane];if(!$R){return}options[pane].slidable=false;if(state[pane].isSliding){close(pane,false,true)}else{bindStartSlidingEvents(pane,false);$R.css(\"cursor\",\"default\").attr(\"title\",\"\");removeHover(null,$R[0])}},enableResizable=function(evt_or_pane){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$R=$Rs[pane],o=options[pane];if(!$R||!$R.data(\"draggable\")){return}o.resizable=true;$R.draggable(\"enable\");if(!state[pane].isClosed){$R.css(\"cursor\",o.resizerCursor).attr(\"title\",o.tips.Resize)}},disableResizable=function(evt_or_pane){if(!isInitialized()){return}var pane=evtPane.call(this,evt_or_pane),$R=$Rs[pane];if(!$R||!$R.data(\"draggable\")){return}options[pane].resizable=false;$R.draggable(\"disable\").css(\"cursor\",\"default\").attr(\"title\",\"\");removeHover(null,$R[0])},swapPanes=function(evt_or_pane1,pane2){if(!isInitialized()){return}var pane1=evtPane.call(this,evt_or_pane1);state[pane1].edge=pane2;state[pane2].edge=pane1;if(false===_runCallbacks(\"onswap_start\",pane1)||false===_runCallbacks(\"onswap_start\",pane2)){state[pane1].edge=pane1;state[pane2].edge=pane2;return}var oPane1=copy(pane1),oPane2=copy(pane2),sizes={};sizes[pane1]=oPane1?oPane1.state.size:0;sizes[pane2]=oPane2?oPane2.state.size:0;$Ps[pane1]=false;$Ps[pane2]=false;state[pane1]={};state[pane2]={};if($Ts[pane1]){$Ts[pane1].remove()}if($Ts[pane2]){$Ts[pane2].remove()}if($Rs[pane1]){$Rs[pane1].remove()}if($Rs[pane2]){$Rs[pane2].remove()}$Rs[pane1]=$Rs[pane2]=$Ts[pane1]=$Ts[pane2]=false;move(oPane1,pane2);move(oPane2,pane1);oPane1=oPane2=sizes=null;if($Ps[pane1]){$Ps[pane1].css(_c.visible)}if($Ps[pane2]){$Ps[pane2].css(_c.visible)}resizeAll();_runCallbacks(\"onswap_end\",pane1);_runCallbacks(\"onswap_end\",pane2);return;function copy(n){var $P=$Ps[n],$C=$Cs[n];return !$P?false:{pane:n,P:$P?$P[0]:false,C:$C?$C[0]:false,state:$.extend(true,{},state[n]),options:$.extend(true,{},options[n])}}function move(oPane,pane){if(!oPane){return}var P=oPane.P,C=oPane.C,oldPane=oPane.pane,c=_c[pane],s=$.extend(true,{},state[pane]),o=options[pane],fx={resizerCursor:o.resizerCursor},re,size,pos;$.each(\"fxName,fxSpeed,fxSettings\".split(\",\"),function(i,k){fx[k+\"_open\"]=o[k+\"_open\"];fx[k+\"_close\"]=o[k+\"_close\"];fx[k+\"_size\"]=o[k+\"_size\"]});$Ps[pane]=$(P).data({layoutPane:Instance[pane],layoutEdge:pane}).css(_c.hidden).css(c.cssReq);$Cs[pane]=C?$(C):false;options[pane]=$.extend(true,{},oPane.options,fx);state[pane]=$.extend(true,{},oPane.state);re=new RegExp(o.paneClass+\"-\"+oldPane,\"g\");P.className=P.className.replace(re,o.paneClass+\"-\"+pane);initHandles(pane);if(c.dir!=_c[oldPane].dir){size=sizes[pane]||0;setSizeLimits(pane);size=max(size,state[pane].minSize);manualSizePane(pane,size,true,true)}else{$Rs[pane].css(c.side,sC.inset[c.side]+(state[pane].isVisible?getPaneSize(pane):0))}if(oPane.state.isVisible&&!s.isVisible){setAsOpen(pane,true)}else{setAsClosed(pane);bindStartSlidingEvents(pane,true)}oPane=null}},syncPinBtns=function(pane,doPin){if($.layout.plugins.buttons){$.each(state[pane].pins,function(i,selector){$.layout.buttons.setPinState(Instance,$(selector),pane,doPin)})}};function keyDown(evt){if(!evt){return true}var code=evt.keyCode;if(code<33){return true}var PANE={38:\"north\",40:\"south\",37:\"west\",39:\"east\"},ALT=evt.altKey,SHIFT=evt.shiftKey,CTRL=evt.ctrlKey,CURSOR=(CTRL&&code>=37&&code<=40),o,k,m,pane;if(CURSOR&&options[PANE[code]].enableCursorHotkey){pane=PANE[code]}else{if(CTRL||SHIFT){$.each(_c.borderPanes,function(i,p){o=options[p];k=o.customHotkey;m=o.customHotkeyModifier;if((SHIFT&&m==\"SHIFT\")||(CTRL&&m==\"CTRL\")||(CTRL&&SHIFT)){if(k&&code===(isNaN(k)||k<=9?k.toUpperCase().charCodeAt(0):k)){pane=p;return false}}})}}if(!pane||!$Ps[pane]||!options[pane].closable||state[pane].isHidden){return true}toggle(pane);evt.stopPropagation();evt.returnValue=false;return false}function allowOverflow(el){if(!isInitialized()){return}if(this&&this.tagName){el=this}var $P;if(isStr(el)){$P=$Ps[el]}else{if($(el).data(\"layoutRole\")){$P=$(el)}else{$(el).parents().each(function(){if($(this).data(\"layoutRole\")){$P=$(this);return false}})}}if(!$P||!$P.length){return}var pane=$P.data(\"layoutEdge\"),s=state[pane];if(s.cssSaved){resetOverflow(pane)}if(s.isSliding||s.isResizing||s.isClosed){s.cssSaved=false;return}var newCSS={zIndex:(options.zIndexes.resizer_normal+1)},curCSS={},of=$P.css(\"overflow\"),ofX=$P.css(\"overflowX\"),ofY=$P.css(\"overflowY\");if(of!=\"visible\"){curCSS.overflow=of;newCSS.overflow=\"visible\"}if(ofX&&!ofX.match(/(visible|auto)/)){curCSS.overflowX=ofX;newCSS.overflowX=\"visible\"}if(ofY&&!ofY.match(/(visible|auto)/)){curCSS.overflowY=ofX;newCSS.overflowY=\"visible\"}s.cssSaved=curCSS;$P.css(newCSS);$.each(_c.allPanes,function(i,p){if(p!=pane){resetOverflow(p)}})}function resetOverflow(el){if(!isInitialized()){return}if(this&&this.tagName){el=this}var $P;if(isStr(el)){$P=$Ps[el]}else{if($(el).data(\"layoutRole\")){$P=$(el)}else{$(el).parents().each(function(){if($(this).data(\"layoutRole\")){$P=$(this);return false}})}}if(!$P||!$P.length){return}var pane=$P.data(\"layoutEdge\"),s=state[pane],CSS=s.cssSaved||{};if(!s.isSliding&&!s.isResizing){$P.css(\"zIndex\",options.zIndexes.pane_normal)}$P.css(CSS);s.cssSaved=false}var $N=$(this).eq(0);if(!$N.length){return _log(options.errors.containerMissing)}if($N.data(\"layoutContainer\")&&$N.data(\"layout\")){return $N.data(\"layout\")}var $Ps={},$Cs={},$Rs={},$Ts={},$Ms=$([]),sC=state.container,sID=state.id;var Instance={options:options,state:state,container:$N,panes:$Ps,contents:$Cs,resizers:$Rs,togglers:$Ts,hide:hide,show:show,toggle:toggle,open:open,close:close,slideOpen:slideOpen,slideClose:slideClose,slideToggle:slideToggle,setSizeLimits:setSizeLimits,_sizePane:sizePane,sizePane:manualSizePane,sizeContent:sizeContent,swapPanes:swapPanes,showMasks:showMasks,hideMasks:hideMasks,initContent:initContent,addPane:addPane,removePane:removePane,createChildren:createChildren,refreshChildren:refreshChildren,enableClosable:enableClosable,disableClosable:disableClosable,enableSlidable:enableSlidable,disableSlidable:disableSlidable,enableResizable:enableResizable,disableResizable:disableResizable,allowOverflow:allowOverflow,resetOverflow:resetOverflow,destroy:destroy,initPanes:isInitialized,resizeAll:resizeAll,runCallbacks:_runCallbacks,hasParentLayout:false,children:children,north:false,south:false,west:false,east:false,center:false};if(_create()===\"cancel\"){return null}else{return Instance}}})(jQuery);(function($){if(!$.layout){return}if(!$.ui){$.ui={}}$.ui.cookie={acceptsCookies:!!navigator.cookieEnabled,read:function(name){var c=document.cookie,cs=c?c.split(\";\"):[],pair,data,i;for(i=0;pair=cs[i];i++){data=$.trim(pair).split(\"=\");if(data[0]==name){return decodeURIComponent(data[1])}}return null},write:function(name,val,cookieOpts){var params=\"\",date=\"\",clear=false,o=cookieOpts||{},x=o.expires||null,t=$.type(x);if(t===\"date\"){date=x}else{if(t===\"string\"&&x>0){x=parseInt(x,10);t=\"number\"}}if(t===\"number\"){date=new Date();if(x>0){date.setDate(date.getDate()+x)}else{date.setFullYear(1970);clear=true}}if(date){params+=\";expires=\"+date.toUTCString()}if(o.path){params+=\";path=\"+o.path}if(o.domain){params+=\";domain=\"+o.domain}if(o.secure){params+=\";secure\"}document.cookie=name+\"=\"+(clear?\"\":encodeURIComponent(val))+params},clear:function(name){$.ui.cookie.write(name,\"\",{expires:-1})}};if(!$.cookie){$.cookie=function(k,v,o){var C=$.ui.cookie;if(v===null){C.clear(k)}else{if(v===undefined){return C.read(k)}else{C.write(k,v,o)}}}}$.layout.plugins.stateManagement=true;$.layout.defaults.stateManagement={enabled:false,autoSave:true,autoLoad:true,animateLoad:true,includeChildren:true,stateKeys:\"north.size,south.size,east.size,west.size,\"+\"north.isClosed,south.isClosed,east.isClosed,west.isClosed,\"+\"north.isHidden,south.isHidden,east.isHidden,west.isHidden\",cookie:{name:\"\",domain:\"\",path:\"\",expires:\"\",secure:false}};$.layout.optionsMap.layout.push(\"stateManagement\");$.layout.config.optionRootKeys.push(\"stateManagement\");$.layout.state={saveCookie:function(inst,keys,cookieOpts){var o=inst.options,sm=o.stateManagement,oC=$.extend(true,{},sm.cookie,cookieOpts||null),data=inst.state.stateData=inst.readState(keys||sm.stateKeys);$.ui.cookie.write(oC.name||o.name||\"Layout\",$.layout.state.encodeJSON(data),oC);return $.extend(true,{},data)},deleteCookie:function(inst){var o=inst.options;$.ui.cookie.clear(o.stateManagement.cookie.name||o.name||\"Layout\")},readCookie:function(inst){var o=inst.options;var c=$.ui.cookie.read(o.stateManagement.cookie.name||o.name||\"Layout\");return c?$.layout.state.decodeJSON(c):{}},loadCookie:function(inst){var c=$.layout.state.readCookie(inst);if(c&&!$.isEmptyObject(c)){inst.state.stateData=$.extend(true,{},c);inst.loadState(c)}return c},loadState:function(inst,data,opts){if(!$.isPlainObject(data)||$.isEmptyObject(data)){return}data=inst.state.stateData=$.layout.transformData(data);var smo=inst.options.stateManagement;opts=$.extend({animateLoad:false,includeChildren:smo.includeChildren},opts);if(!inst.state.initialized){var o=$.extend(true,{},data);$.each($.layout.config.allPanes,function(idx,pane){if(o[pane]){delete o[pane].children}});$.extend(true,inst.options,o)}else{var noAnimate=!opts.animateLoad,o,c,h,state,open;$.each($.layout.config.borderPanes,function(idx,pane){o=data[pane];if(!$.isPlainObject(o)){return}s=o.size;c=o.initClosed;h=o.initHidden;ar=o.autoResize;state=inst.state[pane];open=state.isVisible;if(ar){state.autoResize=ar}if(!open){inst._sizePane(pane,s,false,false,false)}if(h===true){inst.hide(pane,noAnimate)}else{if(c===true){inst.close(pane,false,noAnimate)}else{if(c===false){inst.open(pane,false,noAnimate)}else{if(h===false){inst.show(pane,false,noAnimate)}}}}if(open){inst._sizePane(pane,s,false,false,noAnimate)}});if(opts.includeChildren){var paneStateChildren,childState;$.each(inst.children,function(pane,paneChildren){paneStateChildren=data[pane]?data[pane].children:0;if(paneStateChildren&&paneChildren){$.each(paneChildren,function(stateKey,child){childState=paneStateChildren[stateKey];if(child&&childState){child.loadState(childState)}})}})}}},readState:function(inst,opts){if($.type(opts)===\"string\"){opts={keys:opts}}if(!opts){opts={}}var sm=inst.options.stateManagement,ic=opts.includeChildren,recurse=ic!==undefined?ic:sm.includeChildren,keys=opts.stateKeys||sm.stateKeys,alt={isClosed:\"initClosed\",isHidden:\"initHidden\"},state=inst.state,panes=$.layout.config.allPanes,data={},pair,pane,key,val,ps,pC,child,array,count,branch;if($.isArray(keys)){keys=keys.join(\",\")}keys=keys.replace(/__/g,\".\").split(\",\");for(var i=0,n=keys.length;i<n;i++){pair=keys[i].split(\".\");pane=pair[0];key=pair[1];if($.inArray(pane,panes)<0){continue}val=state[pane][key];if(val==undefined){continue}if(key==\"isClosed\"&&state[pane][\"isSliding\"]){val=true}(data[pane]||(data[pane]={}))[alt[key]?alt[key]:key]=val}if(recurse){$.each(panes,function(idx,pane){pC=inst.children[pane];ps=state.stateData[pane];if($.isPlainObject(pC)&&!$.isEmptyObject(pC)){branch=data[pane]||(data[pane]={});if(!branch.children){branch.children={}}$.each(pC,function(key,child){if(child.state.initialized){branch.children[key]=$.layout.state.readState(child)}else{if(ps&&ps.children&&ps.children[key]){branch.children[key]=$.extend(true,{},ps.children[key])}}})}})}return data},encodeJSON:function(json){var local=window.JSON||{};return(local.stringify||stringify)(json);function stringify(h){var D=[],i=0,k,v,t,a=$.isArray(h);for(k in h){v=h[k];t=typeof v;if(t==\"string\"){v='\"'+v+'\"'}else{if(t==\"object\"){v=parse(v)}}D[i++]=(!a?'\"'+k+'\":':\"\")+v}return(a?\"[\":\"{\")+D.join(\",\")+(a?\"]\":\"}\")}},decodeJSON:function(str){try{return $.parseJSON?$.parseJSON(str):window[\"eval\"](\"(\"+str+\")\")||{}}catch(e){return{}}},_create:function(inst){var s=$.layout.state,o=inst.options,sm=o.stateManagement;$.extend(inst,{readCookie:function(){return s.readCookie(inst)},deleteCookie:function(){s.deleteCookie(inst)},saveCookie:function(keys,cookieOpts){return s.saveCookie(inst,keys,cookieOpts)},loadCookie:function(){return s.loadCookie(inst)},loadState:function(stateData,opts){s.loadState(inst,stateData,opts)},readState:function(keys){return s.readState(inst,keys)},encodeJSON:s.encodeJSON,decodeJSON:s.decodeJSON});inst.state.stateData={};if(!sm.autoLoad){return}if($.isPlainObject(sm.autoLoad)){if(!$.isEmptyObject(sm.autoLoad)){inst.loadState(sm.autoLoad)}}else{if(sm.enabled){if($.isFunction(sm.autoLoad)){var d={};try{d=sm.autoLoad(inst,inst.state,inst.options,inst.options.name||\"\")}catch(e){}if(d&&$.isPlainObject(d)&&!$.isEmptyObject(d)){inst.loadState(d)}}else{inst.loadCookie()}}}},_unload:function(inst){var sm=inst.options.stateManagement;if(sm.enabled&&sm.autoSave){if($.isFunction(sm.autoSave)){try{sm.autoSave(inst,inst.state,inst.options,inst.options.name||\"\")}catch(e){}}else{inst.saveCookie()}}}};$.layout.onCreate.push($.layout.state._create);$.layout.onUnload.push($.layout.state._unload)})(jQuery);(function($){if(!$.layout){return}$.layout.plugins.buttons=true;$.layout.defaults.autoBindCustomButtons=false;$.layout.optionsMap.layout.push(\"autoBindCustomButtons\");$.layout.buttons={config:{borderPanes:\"north,south,west,east\"},init:function(inst){var pre=\"ui-layout-button-\",layout=inst.options.name||\"\",name;$.each(\"toggle,open,close,pin,toggle-slide,open-slide\".split(\",\"),function(i,action){$.each($.layout.buttons.config.borderPanes.split(\",\"),function(ii,pane){$(\".\"+pre+action+\"-\"+pane).each(function(){name=$(this).data(\"layoutName\")||$(this).attr(\"layoutName\");if(name==undefined||name===layout){inst.bindButton(this,action,pane)}})})})},get:function(inst,selector,pane,action){var $E=$(selector),o=inst.options;if($E.length&&$.layout.buttons.config.borderPanes.indexOf(pane)>=0){var btn=o[pane].buttonClass+\"-\"+action;$E.addClass(btn+\" \"+btn+\"-\"+pane).data(\"layoutName\",o.name)}return $E},bind:function(inst,sel,action,pane){var _=$.layout.buttons;switch(action.toLowerCase()){case\"toggle\":_.addToggle(inst,sel,pane);break;case\"open\":_.addOpen(inst,sel,pane);break;case\"close\":_.addClose(inst,sel,pane);break;case\"pin\":_.addPin(inst,sel,pane);break;case\"toggle-slide\":_.addToggle(inst,sel,pane,true);break;case\"open-slide\":_.addOpen(inst,sel,pane,true);break}return inst},addToggle:function(inst,selector,pane,slide){$.layout.buttons.get(inst,selector,pane,\"toggle\").click(function(evt){inst.toggle(pane,!!slide);evt.stopPropagation()});return inst},addOpen:function(inst,selector,pane,slide){$.layout.buttons.get(inst,selector,pane,\"open\").attr(\"title\",inst.options[pane].tips.Open).click(function(evt){inst.open(pane,!!slide);evt.stopPropagation()});return inst},addClose:function(inst,selector,pane){$.layout.buttons.get(inst,selector,pane,\"close\").attr(\"title\",inst.options[pane].tips.Close).click(function(evt){inst.close(pane);evt.stopPropagation()});return inst},addPin:function(inst,selector,pane){var $E=$.layout.buttons.get(inst,selector,pane,\"pin\");if($E.length){var s=inst.state[pane];$E.click(function(evt){$.layout.buttons.setPinState(inst,$(this),pane,(s.isSliding||s.isClosed));if(s.isSliding||s.isClosed){inst.open(pane)}else{inst.close(pane)}evt.stopPropagation()});$.layout.buttons.setPinState(inst,$E,pane,(!s.isClosed&&!s.isSliding));s.pins.push(selector)}return inst},setPinState:function(inst,$Pin,pane,doPin){var updown=$Pin.attr(\"pin\");if(updown&&doPin===(updown==\"down\")){return}var po=inst.options[pane],lang=po.tips,pin=po.buttonClass+\"-pin\",side=pin+\"-\"+pane,UP=pin+\"-up \"+side+\"-up\",DN=pin+\"-down \"+side+\"-down\";$Pin.attr(\"pin\",doPin?\"down\":\"up\").attr(\"title\",doPin?lang.Unpin:lang.Pin).removeClass(doPin?UP:DN).addClass(doPin?DN:UP)},syncPinBtns:function(inst,pane,doPin){$.each(state[pane].pins,function(i,selector){$.layout.buttons.setPinState(inst,$(selector),pane,doPin)})},_load:function(inst){$.extend(inst,{bindButton:function(selector,action,pane){return $.layout.buttons.bind(inst,selector,action,pane)},addToggleBtn:function(selector,pane,slide){return $.layout.buttons.addToggle(inst,selector,pane,slide)},addOpenBtn:function(selector,pane,slide){return $.layout.buttons.addOpen(inst,selector,pane,slide)},addCloseBtn:function(selector,pane){return $.layout.buttons.addClose(inst,selector,pane)},addPinBtn:function(selector,pane){return $.layout.buttons.addPin(inst,selector,pane)}});for(var i=0;i<4;i++){var pane=$.layout.buttons.config.borderPanes[i];inst.state[pane].pins=[]}if(inst.options.autoBindCustomButtons){$.layout.buttons.init(inst)}},_unload:function(inst){}};$.layout.onLoad.push($.layout.buttons._load)})(jQuery);(function($){$.layout.plugins.browserZoom=true;$.layout.defaults.browserZoomCheckInterval=1000;$.layout.optionsMap.layout.push(\"browserZoomCheckInterval\");$.layout.browserZoom={_init:function(inst){if($.layout.browserZoom.ratio()!==false){$.layout.browserZoom._setTimer(inst)}},_setTimer:function(inst){if(inst.destroyed){return}var o=inst.options,s=inst.state,ms=inst.hasParentLayout?5000:Math.max(o.browserZoomCheckInterval,100);setTimeout(function(){if(inst.destroyed||!o.resizeWithWindow){return}var d=$.layout.browserZoom.ratio();if(d!==s.browserZoom){s.browserZoom=d;inst.resizeAll()}$.layout.browserZoom._setTimer(inst)},ms)},ratio:function(){var w=window,s=screen,d=document,dE=d.documentElement||d.body,b=$.layout.browser,v=b.version,r,sW,cW;if(!b.msie||v>8){return false}if(s.deviceXDPI&&s.systemXDPI){return calc(s.deviceXDPI,s.systemXDPI)}if(b.webkit&&(r=d.body.getBoundingClientRect)){return calc((r.left-r.right),d.body.offsetWidth)}if(b.webkit&&(sW=w.outerWidth)){return calc(sW,w.innerWidth)}if((sW=s.width)&&(cW=dE.clientWidth)){return calc(sW,cW)}return false;function calc(x,y){return(parseInt(x,10)/parseInt(y,10)*100).toFixed()}}};$.layout.onReady.push($.layout.browserZoom._init)})(jQuery);(function($){if($.effects){$.layout.defaults.panes.useOffscreenClose=false;if($.layout.plugins){$.layout.plugins.effects.slideOffscreen=true}$.layout.effects.slideOffscreen=$.extend(true,{},$.layout.effects.slide);$.effects.slideOffscreen=function(o){return this.queue(function(){var fx=$.effects,opt=o.options,$el=$(this),pane=$el.data(\"layoutEdge\"),state=$el.data(\"parentLayout\").state,dist=state[pane].size,s=this.style,props=[\"top\",\"bottom\",\"left\",\"right\"],mode=fx.setMode($el,opt.mode||\"show\"),show=(mode==\"show\"),dir=opt.direction||\"left\",ref=(dir==\"up\"||dir==\"down\")?\"top\":\"left\",pos=(dir==\"up\"||dir==\"left\"),offscrn=$.layout.config.offscreenCSS||{},keyLR=$.layout.config.offscreenReset,keyTB=\"offscreenResetTop\",animation={};animation[ref]=(show?(pos?\"+=\":\"-=\"):(pos?\"-=\":\"+=\"))+dist;if(show){$el.data(keyTB,{top:s.top,bottom:s.bottom});if(pos){$el.css(ref,isNaN(dist)?\"-\"+dist:-dist)}else{if(dir===\"right\"){$el.css({left:state.container.layoutWidth,right:\"auto\"})}else{$el.css({top:state.container.layoutHeight,bottom:\"auto\"})}}if(ref===\"top\"){$el.css($el.data(keyLR)||{})}}else{$el.data(keyTB,{top:s.top,bottom:s.bottom});$el.data(keyLR,{left:s.left,right:s.right})}$el.show().animate(animation,{queue:false,duration:o.duration,easing:opt.easing,complete:function(){if($el.data(keyTB)){$el.css($el.data(keyTB)).removeData(keyTB)}if(show){$el.css($el.data(keyLR)||{}).removeData(keyLR)}else{$el.css(offscrn)}if(o.callback){o.callback.apply(this,arguments)}$el.dequeue()}})})}}})(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/css/default/zTreeStyle.css",
    "content": "/*-------------------------------------\r\nzTree Style\r\n\r\nversion:\t3.4\r\nauthor:\t\tHunter.z\r\nemail:\t\thunter.z@263.net\r\nwebsite:\thttp://code.google.com/p/jquerytree/\r\n\r\n-------------------------------------*/\r\n\r\n.ztree * {padding:0; margin:0; font-size:12px;}\r\n.ztree {margin:0; padding:2px; color:#333}\r\n.ztree li{padding:0; margin:0; list-style:none; line-height:18px; text-align:left; white-space:nowrap; outline:0}\r\n.ztree li ul{ margin:0; padding:0 0 0 18px}\r\n.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;}\r\n\r\n.ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; /* height:17px; */ color:#333; background-color: transparent;\r\n\ttext-decoration:none; vertical-align:top; display: inline-block}\r\n.ztree li a:hover {text-decoration:underline}\r\n/*.ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}*/\r\n.ztree li a.curSelectedNode {padding-top:0px; background-color:#F6F6F6; color:#0663A2; border:1px #DDDDDD solid; opacity:0.8;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\r\n/*.ztree li a.curSelectedNode {padding-top:0px; color:#0663a2; font-weight:bold; height:16px; opacity:0.8;}*/\r\n.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}\r\n.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid;\r\n\topacity:0.8; filter:alpha(opacity=80)}\r\n.ztree li a.tmpTargetNode_prev {}\r\n.ztree li a.tmpTargetNode_next {}\r\n.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;\r\n\tfont-size:12px; border:1px #7EC4CC solid; *border:0px}\r\n.ztree li span {line-height:16px; margin-right:2px}\r\n.ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle;\r\n\tborder:0 none; cursor: pointer;outline:none;\r\n\tbackground-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\r\n\tbackground-image:url(\"./img/zTreeStandard.png\"); *background-image:url(\"./img/zTreeStandard.gif\")}\r\n\r\n/* IE7 fix */\r\n.ztree li span.button.level0 {*margin-left:-15px;}\r\n\r\n.ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto}\r\n.ztree li span.button.chk.checkbox_false_full {background-position:0 0}\r\n.ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px}\r\n.ztree li span.button.chk.checkbox_false_part {background-position:0 -28px}\r\n.ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px}\r\n.ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px}\r\n.ztree li span.button.chk.checkbox_true_full {background-position:-14px 0}\r\n.ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px}\r\n.ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px}\r\n.ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px}\r\n.ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px}\r\n.ztree li span.button.chk.radio_false_full {background-position:-28px 0}\r\n.ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px}\r\n.ztree li span.button.chk.radio_false_part {background-position:-28px -28px}\r\n.ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px}\r\n.ztree li span.button.chk.radio_false_disable {background-position:-28px -56px}\r\n.ztree li span.button.chk.radio_true_full {background-position:-42px 0}\r\n.ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px}\r\n.ztree li span.button.chk.radio_true_part {background-position:-42px -28px}\r\n.ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px}\r\n.ztree li span.button.chk.radio_true_disable {background-position:-42px -56px}\r\n\r\n.ztree li span.button.switch {width:18px; height:18px}\r\n.ztree li span.button.root_open{background-position:-92px -54px}\r\n.ztree li span.button.root_close{background-position:-74px -54px}\r\n.ztree li span.button.roots_open{background-position:-92px 0}\r\n.ztree li span.button.roots_close{background-position:-74px 0}\r\n.ztree li span.button.center_open{background-position:-92px -18px}\r\n.ztree li span.button.center_close{background-position:-74px -18px}\r\n.ztree li span.button.bottom_open{background-position:-92px -36px}\r\n.ztree li span.button.bottom_close{background-position:-74px -36px}\r\n.ztree li span.button.noline_open{background-position:-92px -72px}\r\n.ztree li span.button.noline_close{background-position:-74px -72px}\r\n.ztree li span.button.root_docu{ background:none;}\r\n.ztree li span.button.roots_docu{background-position:-56px 0}\r\n.ztree li span.button.center_docu{background-position:-56px -18px}\r\n.ztree li span.button.bottom_docu{background-position:-56px -36px}\r\n.ztree li span.button.noline_docu{ background:none;}\r\n\r\n.ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; /* vertical-align:top; * */vertical-align:middle}\r\n.ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle}\r\n\r\n.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}\r\n\r\nul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}\r\n\r\nspan.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;\r\n\tbackground-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\r\n\tbackground-position:-110px -80px; background-image:url(\"./img/zTreeStandard.png\"); *background-image:url(\"./img/zTreeStandard.gif\")}\r\n\r\nul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}\r\n.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}\r\n\r\n/* level style*/\r\n/*.ztree li span.button.level0 {\r\n\tdisplay:none;\r\n}\r\n.ztree li ul.level0 {\r\n\tpadding:0;\r\n\tbackground:none;\r\n}*/\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/css/metro/zTreeStyle.css",
    "content": "/*-------------------------------------\r\nzTree Style\r\n\r\nversion:    3.4\r\nauthor:     Hunter.z\r\nemail:      hunter.z@263.net\r\nwebsite:    http://code.google.com/p/jquerytree/\r\n\r\n-------------------------------------*/\r\n\r\n.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}\r\n.ztree {margin:0; padding:5px; color:#333}\r\n.ztree li{padding:0; margin:0; list-style:none; line-height:21px; text-align:left; white-space:nowrap; outline:0}\r\n.ztree li ul{ margin:0; padding:0 0 0 18px}\r\n.ztree li ul.line{ background:url(./img/line_conn.png) 0 0 repeat-y;}\r\n\r\n.ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; display: inline-block}\r\n.ztree li a:hover {text-decoration:underline}\r\n.ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:22px; -webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\r\n.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:22px; border:1px #666 solid; -webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\r\n.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid;\r\n    opacity:0.8; filter:alpha(opacity=80)}\r\n.ztree li a.tmpTargetNode_prev {}\r\n.ztree li a.tmpTargetNode_next {}\r\n.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;\r\n    font-size:12px; border:1px #7EC4CC solid; *border:0px}\r\n.ztree li span {line-height:21px; margin-right:2px}\r\n.ztree li span.button {line-height:0; margin:0; width:21px; height:21px; display: inline-block; vertical-align:middle;\r\n    border:0 none; cursor: pointer;outline:none;\r\n    background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\r\n    background-image:url(\"./img/metro.png\"); *background-image:url(\"./img/metro.gif\")}\r\n\r\n.ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto}\r\n.ztree li span.button.chk.checkbox_false_full {background-position: -5px -5px;}\r\n.ztree li span.button.chk.checkbox_false_full_focus {background-position: -5px -26px;}\r\n.ztree li span.button.chk.checkbox_false_part {background-position: -5px -48px;}\r\n.ztree li span.button.chk.checkbox_false_part_focus {background-position: -5px -68px;}\r\n.ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;}\r\n.ztree li span.button.chk.checkbox_true_full {background-position: -26px -5px;}\r\n.ztree li span.button.chk.checkbox_true_full_focus {background-position: -26px -26px;}\r\n.ztree li span.button.chk.checkbox_true_part {background-position: -26px -48px;}\r\n.ztree li span.button.chk.checkbox_true_part_focus {background-position: -26px -68px;}\r\n.ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;}\r\n.ztree li span.button.chk.radio_false_full {background-position: -47px -5px;}\r\n.ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;}\r\n.ztree li span.button.chk.radio_false_part {background-position: -47px -47px;}\r\n.ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;}\r\n.ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;}\r\n.ztree li span.button.chk.radio_true_full {background-position: -68px -5px;}\r\n.ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;}\r\n.ztree li span.button.chk.radio_true_part {background-position: -68px -47px;}\r\n.ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;}\r\n.ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;}\r\n\r\n.ztree li span.button.switch {width:21px; height:21px}\r\n.ztree li span.button.root_open{background-position:-105px -85px}\r\n.ztree li span.button.root_close{background-position:-126px -85px}\r\n.ztree li span.button.roots_open{background-position: -105px 0;}\r\n.ztree li span.button.roots_close{background-position: -126px 0;}\r\n.ztree li span.button.center_open{background-position: -105px -21px;}\r\n.ztree li span.button.center_close{background-position: -126px -21px;}\r\n.ztree li span.button.bottom_open{background-position: -105px -42px;}\r\n.ztree li span.button.bottom_close{background-position: -126px -42px;}\r\n.ztree li span.button.noline_open{background-position: -126px -84px;}\r\n.ztree li span.button.noline_close{background-position: -105px -84px;}\r\n.ztree li span.button.root_docu{ background:none;}\r\n.ztree li span.button.roots_docu{background-position: -84px 0;}\r\n.ztree li span.button.center_docu{background-position: -84px -21px;}\r\n.ztree li span.button.bottom_docu{background-position: -84px -42px;}\r\n.ztree li span.button.noline_docu{ background:none;}\r\n\r\n.ztree li span.button.ico_open{margin-right:2px; background-position: -147px -21px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.ico_close{margin-right:2px; margin-right:2px; background-position: -147px 0; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.edit:hover {\r\n  background-position: -168px -21px;\r\n}\r\n.ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.remove:hover {\r\n  background-position: -168px -42px;\r\n}\r\n.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.add:hover {\r\n  background-position: -168px 0;\r\n}\r\n.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}\r\n\r\nul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}\r\n\r\nspan.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;\r\n    background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\r\n    background-position:-168px -84px; background-image:url(\"./img/metro.png\"); *background-image:url(\"./img/metro.gif\")}\r\n\r\nul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}\r\n.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}\r\n\r\n/* 树搜索相关 */\r\n.treeSearchInput {padding:13px 0 0 20px;}\r\n.treeSearchInput label {padding:5px 0 3px 0;font-size:13px;font-weight:normal;vertical-align:middle;}\r\n.treeSearchInput input {width:145px;vertical-align:middle;line-height:24px;height:26px;border:1px solid #bbb;padding:0 4px;}\r\n.treeSearchInput button {border:1px solid #bbb;vertical-align:middle;height:26px;height:26px\\9;font-size:13px;background:#efefef;padding:0 8px;}\r\n.treeShowHideButton {position:absolute;right:8px;top:2px;font-size:12px;color:#333;z-index:3;}\r\n.treeShowHideButton label {cursor:pointer;}\r\n.treeExpandCollapse {float:right;margin:6px 5px;padding:5px;font-size:12px;color:#333;position:relative;z-index:2;background:#fff;}\r\n.treeExpandCollapse a {text-decoration:none;color:#333}\r\n.treeselect.ztree {padding:10px 20px;}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/css/simple/zTreeStyle.css",
    "content": "/*-------------------------------------\r\nzTree Style\r\n\r\nversion:    3.4\r\nauthor:     Hunter.z\r\nemail:      hunter.z@263.net\r\nwebsite:    http://code.google.com/p/jquerytree/\r\n\r\n-------------------------------------*/\r\n\r\n.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}\r\n.ztree {margin:0; padding:5px; color:#333}\r\n.ztree li{padding:0; margin:0; list-style:none; line-height:21px; text-align:left; white-space:nowrap; outline:0}\r\n.ztree li ul{ margin:0; padding:0 0 0 18px}\r\n.ztree li ul.line{ background:url(./img/line_conn.png) 0 0 repeat-y;}\r\n\r\n.ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; display: inline-block}\r\n.ztree li a:hover {text-decoration:underline}\r\n.ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; opacity:0.8;}\r\n.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; border:1px #666 solid; opacity:0.8;}\r\n.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid;\r\n    opacity:0.8; filter:alpha(opacity=80)}\r\n.ztree li a.tmpTargetNode_prev {}\r\n.ztree li a.tmpTargetNode_next {}\r\n.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;\r\n    font-size:12px; border:1px #7EC4CC solid; *border:0px}\r\n.ztree li span {line-height:21px; margin-right:2px}\r\n.ztree li span.button {line-height:0; margin:0; width:21px; height:21px; display: inline-block; vertical-align:middle;\r\n    border:0 none; cursor: pointer;outline:none;\r\n    background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\r\n    background-image:url(\"./img/metro.png\"); *background-image:url(\"./img/metro.gif\")}\r\n\r\n.ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto}\r\n.ztree li span.button.chk.checkbox_false_full {background-position: -5px -5px;}\r\n.ztree li span.button.chk.checkbox_false_full_focus {background-position: -5px -26px;}\r\n.ztree li span.button.chk.checkbox_false_part {background-position: -5px -48px;}\r\n.ztree li span.button.chk.checkbox_false_part_focus {background-position: -5px -68px;}\r\n.ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;}\r\n.ztree li span.button.chk.checkbox_true_full {background-position: -26px -5px;}\r\n.ztree li span.button.chk.checkbox_true_full_focus {background-position: -26px -26px;}\r\n.ztree li span.button.chk.checkbox_true_part {background-position: -26px -48px;}\r\n.ztree li span.button.chk.checkbox_true_part_focus {background-position: -26px -68px;}\r\n.ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;}\r\n.ztree li span.button.chk.radio_false_full {background-position: -47px -5px;}\r\n.ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;}\r\n.ztree li span.button.chk.radio_false_part {background-position: -47px -47px;}\r\n.ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;}\r\n.ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;}\r\n.ztree li span.button.chk.radio_true_full {background-position: -68px -5px;}\r\n.ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;}\r\n.ztree li span.button.chk.radio_true_part {background-position: -68px -47px;}\r\n.ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;}\r\n.ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;}\r\n\r\n.ztree li span.button.switch {width:21px; height:21px}\r\n.ztree li span.button.root_open{background-position:-92px -54px}\r\n.ztree li span.button.root_close{background-position:-74px -54px}\r\n.ztree li span.button.roots_open{background-position: -105px 0;}\r\n.ztree li span.button.roots_close{background-position: -126px 0;}\r\n.ztree li span.button.center_open{background-position: -105px -21px;}\r\n.ztree li span.button.center_close{background-position: -126px -21px;}\r\n.ztree li span.button.bottom_open{background-position: -105px -42px;}\r\n.ztree li span.button.bottom_close{background-position: -126px -42px;}\r\n.ztree li span.button.noline_open{background-position: -126px -84px;}\r\n.ztree li span.button.noline_close{background-position: -105px -84px;}\r\n.ztree li span.button.root_docu{ background:none;}\r\n.ztree li span.button.roots_docu{background-position: -84px 0;}\r\n.ztree li span.button.center_docu{background-position: -84px -21px;}\r\n.ztree li span.button.bottom_docu{background-position: -84px -42px;}\r\n.ztree li span.button.noline_docu{ background:none;}\r\n\r\n.ztree li span.button.ico_open{margin-right:2px; background-position: -147px -21px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.ico_close{margin-right:2px; margin-right:2px; background-position: -147px 0; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.edit:hover {\r\n  background-position: -168px -21px;\r\n}\r\n.ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.remove:hover {\r\n  background-position: -168px -42px;\r\n}\r\n.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle}\r\n.ztree li span.button.add:hover {\r\n  background-position: -168px 0;\r\n}\r\n.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}\r\n\r\nul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}\r\n\r\nspan.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;\r\n    background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\r\n    background-position:-168px -84px; background-image:url(\"./img/metro.png\"); *background-image:url(\"./img/metro.gif\")}\r\n\r\nul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}\r\n.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}\r\n\r\n/* simple */\r\n\r\n.ztree * {font-size:14px;font-family:\"Microsoft Yahei\",Verdana,Simsun,\"Segoe UI Web Light\",\"Segoe UI Light\",\"Segoe UI Web Regular\",\"Segoe UI\",\"Segoe UI Symbol\",\"Helvetica Neue\",Arial;}\r\n.ztree li ul{ margin:0; padding:0}\r\n.ztree li {line-height:28px;}\r\n.ztree li a {width:100%;height:28px;padding-top: 0px;}\r\n.ztree li a:hover {text-decoration:none; background-color: #E7E7E7;}\r\n.ztree11 li a span.button.switch {visibility:hidden}\r\n.ztree11.showIcon li a span.button.switch {visibility:visible}\r\n.ztree li a.curSelectedNode {background-color:#D4D4D4;border:0;height:28px;}\r\n.ztree li span {line-height:26px;margin-right:0px;}\r\n.ztree li span.button {margin-top: -7px;}\r\n.ztree li span.button.switch {width:16px;height: 16px;}\r\n.ztree li a.level0 span {font-size:15px;font-weight:bold;}\r\n.ztree li span.button {background-image:url(\"img/left_menu.png\"); *background-image:url(\"./left_menu.gif\")}\r\n.ztree li span.button.switch.level0 {width: 20px; height:20px}\r\n.ztree li span.button.switch.level1 {width: 20px; height:20px}\r\n.ztree li span.button.noline_open {background-position: 0 0;}\r\n.ztree li span.button.noline_close {background-position: -18px 0;}\r\n.ztree li span.button.noline_open.level0 {background-position: 0 -17px;}\r\n.ztree li span.button.noline_close.level0 {background-position: -18px -17px;}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/js/jquery.ztree.all-3.5.js",
    "content": "\r\n/*\r\n * JQuery zTree core 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\tvar settings = {}, roots = {}, caches = {},\r\n\t//default consts of core\r\n\t_consts = {\r\n\t\tclassName: {\r\n\t\t\tBUTTON: \"button\",\r\n\t\t\tLEVEL: \"level\",\r\n\t\t\tICO_LOADING: \"ico_loading\",\r\n\t\t\tSWITCH: \"switch\"\r\n\t\t},\r\n\t\tevent: {\r\n\t\t\tNODECREATED: \"ztree_nodeCreated\",\r\n\t\t\tCLICK: \"ztree_click\",\r\n\t\t\tEXPAND: \"ztree_expand\",\r\n\t\t\tCOLLAPSE: \"ztree_collapse\",\r\n\t\t\tASYNC_SUCCESS: \"ztree_async_success\",\r\n\t\t\tASYNC_ERROR: \"ztree_async_error\"\r\n\t\t},\r\n\t\tid: {\r\n\t\t\tA: \"_a\",\r\n\t\t\tICON: \"_ico\",\r\n\t\t\tSPAN: \"_span\",\r\n\t\t\tSWITCH: \"_switch\",\r\n\t\t\tUL: \"_ul\"\r\n\t\t},\r\n\t\tline: {\r\n\t\t\tROOT: \"root\",\r\n\t\t\tROOTS: \"roots\",\r\n\t\t\tCENTER: \"center\",\r\n\t\t\tBOTTOM: \"bottom\",\r\n\t\t\tNOLINE: \"noline\",\r\n\t\t\tLINE: \"line\"\r\n\t\t},\r\n\t\tfolder: {\r\n\t\t\tOPEN: \"open\",\r\n\t\t\tCLOSE: \"close\",\r\n\t\t\tDOCU: \"docu\"\r\n\t\t},\r\n\t\tnode: {\r\n\t\t\tCURSELECTED: \"curSelectedNode\"\r\n\t\t}\r\n\t},\r\n\t//default setting of core\r\n\t_setting = {\r\n\t\ttreeId: \"\",\r\n\t\ttreeObj: null,\r\n\t\tview: {\r\n\t\t\taddDiyDom: null,\r\n\t\t\tautoCancelSelected: true,\r\n\t\t\tdblClickExpand: true,\r\n\t\t\texpandSpeed: \"fast\",\r\n\t\t\tfontCss: {},\r\n\t\t\tnameIsHTML: false,\r\n\t\t\tselectedMulti: true,\r\n\t\t\tshowIcon: true,\r\n\t\t\tshowLine: true,\r\n\t\t\tshowTitle: true\r\n\t\t},\r\n\t\tdata: {\r\n\t\t\tkey: {\r\n\t\t\t\tchildren: \"children\",\r\n\t\t\t\tname: \"name\",\r\n\t\t\t\ttitle: \"\",\r\n\t\t\t\turl: \"url\"\r\n\t\t\t},\r\n\t\t\tsimpleData: {\r\n\t\t\t\tenable: false,\r\n\t\t\t\tidKey: \"id\",\r\n\t\t\t\tpIdKey: \"pId\",\r\n\t\t\t\trootPId: null\r\n\t\t\t},\r\n\t\t\tkeep: {\r\n\t\t\t\tparent: false,\r\n\t\t\t\tleaf: false\r\n\t\t\t}\r\n\t\t},\r\n\t\tasync: {\r\n\t\t\tenable: false,\r\n\t\t\tcontentType: \"application/x-www-form-urlencoded\",\r\n\t\t\ttype: \"post\",\r\n\t\t\tdataType: \"text\",\r\n\t\t\turl: \"\",\r\n\t\t\tautoParam: [],\r\n\t\t\totherParam: [],\r\n\t\t\tdataFilter: null\r\n\t\t},\r\n\t\tcallback: {\r\n\t\t\tbeforeAsync:null,\r\n\t\t\tbeforeClick:null,\r\n\t\t\tbeforeDblClick:null,\r\n\t\t\tbeforeRightClick:null,\r\n\t\t\tbeforeMouseDown:null,\r\n\t\t\tbeforeMouseUp:null,\r\n\t\t\tbeforeExpand:null,\r\n\t\t\tbeforeCollapse:null,\r\n\t\t\tbeforeRemove:null,\r\n\r\n\t\t\tonAsyncError:null,\r\n\t\t\tonAsyncSuccess:null,\r\n\t\t\tonNodeCreated:null,\r\n\t\t\tonClick:null,\r\n\t\t\tonDblClick:null,\r\n\t\t\tonRightClick:null,\r\n\t\t\tonMouseDown:null,\r\n\t\t\tonMouseUp:null,\r\n\t\t\tonExpand:null,\r\n\t\t\tonCollapse:null,\r\n\t\t\tonRemove:null\r\n\t\t}\r\n\t},\r\n\t//default root of core\r\n\t//zTree use root to save full data\r\n\t_initRoot = function (setting) {\r\n\t\tvar r = data.getRoot(setting);\r\n\t\tif (!r) {\r\n\t\t\tr = {};\r\n\t\t\tdata.setRoot(setting, r);\r\n\t\t}\r\n\t\tr[setting.data.key.children] = [];\r\n\t\tr.expandTriggerFlag = false;\r\n\t\tr.curSelectedList = [];\r\n\t\tr.noSelection = true;\r\n\t\tr.createdNodes = [];\r\n\t\tr.zId = 0;\r\n\t\tr._ver = (new Date()).getTime();\r\n\t},\r\n\t//default cache of core\r\n\t_initCache = function(setting) {\r\n\t\tvar c = data.getCache(setting);\r\n\t\tif (!c) {\r\n\t\t\tc = {};\r\n\t\t\tdata.setCache(setting, c);\r\n\t\t}\r\n\t\tc.nodes = [];\r\n\t\tc.doms = [];\r\n\t},\r\n\t//default bindEvent of core\r\n\t_bindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.bind(c.NODECREATED, function (event, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onNodeCreated, [event, treeId, node]);\r\n\t\t});\r\n\r\n\t\to.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) {\r\n\t\t\ttools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]);\r\n\t\t});\r\n\r\n\t\to.bind(c.EXPAND, function (event, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onExpand, [event, treeId, node]);\r\n\t\t});\r\n\r\n\t\to.bind(c.COLLAPSE, function (event, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onCollapse, [event, treeId, node]);\r\n\t\t});\r\n\r\n\t\to.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) {\r\n\t\t\ttools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]);\r\n\t\t});\r\n\r\n\t\to.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) {\r\n\t\t\ttools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]);\r\n\t\t});\r\n\t},\r\n\t_unbindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.unbind(c.NODECREATED)\r\n\t\t.unbind(c.CLICK)\r\n\t\t.unbind(c.EXPAND)\r\n\t\t.unbind(c.COLLAPSE)\r\n\t\t.unbind(c.ASYNC_SUCCESS)\r\n\t\t.unbind(c.ASYNC_ERROR);\r\n\t},\t\r\n\t//default event proxy of core\r\n\t_eventProxy = function(event) {\r\n\t\tvar target = event.target,\r\n\t\tsetting = data.getSetting(event.data.treeId),\r\n\t\ttId = \"\", node = null,\r\n\t\tnodeEventType = \"\", treeEventType = \"\",\r\n\t\tnodeEventCallback = null, treeEventCallback = null,\r\n\t\ttmp = null;\r\n\r\n\t\tif (tools.eqs(event.type, \"mousedown\")) {\r\n\t\t\ttreeEventType = \"mousedown\";\r\n\t\t} else if (tools.eqs(event.type, \"mouseup\")) {\r\n\t\t\ttreeEventType = \"mouseup\";\r\n\t\t} else if (tools.eqs(event.type, \"contextmenu\")) {\r\n\t\t\ttreeEventType = \"contextmenu\";\r\n\t\t} else if (tools.eqs(event.type, \"click\")) {\r\n\t\t\tif (tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.SWITCH) !== null) {\r\n\t\t\t\ttId = ($(target).parent(\"li\").get(0) || $(target).parentsUntil(\"li\").parent().get(0)).id;\r\n\t\t\t\tnodeEventType = \"switchNode\";\r\n\t\t\t} else {\r\n\t\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\t\tif (tmp) {\r\n\t\t\t\t\ttId = ($(tmp).parent(\"li\").get(0) || $(tmp).parentsUntil(\"li\").parent().get(0)).id;\r\n\t\t\t\t\tnodeEventType = \"clickNode\";\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(event.type, \"dblclick\")) {\r\n\t\t\ttreeEventType = \"dblclick\";\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {\r\n\t\t\t\ttId = ($(tmp).parent(\"li\").get(0) || $(tmp).parentsUntil(\"li\").parent().get(0)).id;\r\n\t\t\t\tnodeEventType = \"switchNode\";\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (treeEventType.length > 0 && tId.length == 0) {\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {tId = ($(tmp).parent(\"li\").get(0) || $(tmp).parentsUntil(\"li\").parent().get(0)).id;}\r\n\t\t}\r\n\t\t// event to node\r\n\t\tif (tId.length>0) {\r\n\t\t\tnode = data.getNodeCache(setting, tId);\r\n\t\t\tswitch (nodeEventType) {\r\n\t\t\t\tcase \"switchNode\" :\r\n\t\t\t\t\tif (!node.isParent) {\r\n\t\t\t\t\t\tnodeEventType = \"\";\r\n\t\t\t\t\t} else if (tools.eqs(event.type, \"click\") \r\n\t\t\t\t\t\t|| (tools.eqs(event.type, \"dblclick\") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) {\r\n\t\t\t\t\t\tnodeEventCallback = handler.onSwitchNode;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tnodeEventType = \"\";\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"clickNode\" :\r\n\t\t\t\t\tnodeEventCallback = handler.onClickNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// event to zTree\r\n\t\tswitch (treeEventType) {\r\n\t\t\tcase \"mousedown\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeMousedown;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"mouseup\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeMouseup;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"dblclick\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeDblclick;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"contextmenu\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeContextmenu;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t\tvar proxyResult = {\r\n\t\t\tstop: false,\r\n\t\t\tnode: node,\r\n\t\t\tnodeEventType: nodeEventType,\r\n\t\t\tnodeEventCallback: nodeEventCallback,\r\n\t\t\ttreeEventType: treeEventType,\r\n\t\t\ttreeEventCallback: treeEventCallback\r\n\t\t};\r\n\t\treturn proxyResult\r\n\t},\r\n\t//default init node of core\r\n\t_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (!n) return;\r\n\t\tvar r = data.getRoot(setting),\r\n\t\tchildKey = setting.data.key.children;\r\n\t\tn.level = level;\r\n\t\tn.tId = setting.treeId + \"_\" + (++r.zId);\r\n\t\tn.parentTId = parentNode ? parentNode.tId : null;\r\n\t\tif (n[childKey] && n[childKey].length > 0) {\r\n\t\t\tif (typeof n.open == \"string\") n.open = tools.eqs(n.open, \"true\");\r\n\t\t\tn.open = !!n.open;\r\n\t\t\tn.isParent = true;\r\n\t\t\tn.zAsync = true;\r\n\t\t} else {\r\n\t\t\tn.open = false;\r\n\t\t\tif (typeof n.isParent == \"string\") n.isParent = tools.eqs(n.isParent, \"true\");\r\n\t\t\tn.isParent = !!n.isParent;\r\n\t\t\tn.zAsync = !n.isParent;\r\n\t\t}\r\n\t\tn.isFirstNode = isFirstNode;\r\n\t\tn.isLastNode = isLastNode;\r\n\t\tn.getParentNode = function() {return data.getNodeCache(setting, n.parentTId);};\r\n\t\tn.getPreNode = function() {return data.getPreNode(setting, n);};\r\n\t\tn.getNextNode = function() {return data.getNextNode(setting, n);};\r\n\t\tn.isAjaxing = false;\r\n\t\tdata.fixPIdKeyValue(setting, n);\r\n\t},\r\n\t_init = {\r\n\t\tbind: [_bindEvent],\r\n\t\tunbind: [_unbindEvent],\r\n\t\tcaches: [_initCache],\r\n\t\tnodes: [_initNode],\r\n\t\tproxys: [_eventProxy],\r\n\t\troots: [_initRoot],\r\n\t\tbeforeA: [],\r\n\t\tafterA: [],\r\n\t\tinnerBeforeA: [],\r\n\t\tinnerAfterA: [],\r\n\t\tzTreeTools: []\r\n\t},\r\n\t//method of operate data\r\n\tdata = {\r\n\t\taddNodeCache: function(setting, node) {\r\n\t\t\tdata.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node;\r\n\t\t},\r\n\t\tgetNodeCacheId: function(tId) {\r\n\t\t\treturn tId.substring(tId.lastIndexOf(\"_\")+1);\r\n\t\t},\r\n\t\taddAfterA: function(afterA) {\r\n\t\t\t_init.afterA.push(afterA);\r\n\t\t},\r\n\t\taddBeforeA: function(beforeA) {\r\n\t\t\t_init.beforeA.push(beforeA);\r\n\t\t},\r\n\t\taddInnerAfterA: function(innerAfterA) {\r\n\t\t\t_init.innerAfterA.push(innerAfterA);\r\n\t\t},\r\n\t\taddInnerBeforeA: function(innerBeforeA) {\r\n\t\t\t_init.innerBeforeA.push(innerBeforeA);\r\n\t\t},\r\n\t\taddInitBind: function(bindEvent) {\r\n\t\t\t_init.bind.push(bindEvent);\r\n\t\t},\r\n\t\taddInitUnBind: function(unbindEvent) {\r\n\t\t\t_init.unbind.push(unbindEvent);\r\n\t\t},\r\n\t\taddInitCache: function(initCache) {\r\n\t\t\t_init.caches.push(initCache);\r\n\t\t},\r\n\t\taddInitNode: function(initNode) {\r\n\t\t\t_init.nodes.push(initNode);\r\n\t\t},\r\n\t\taddInitProxy: function(initProxy) {\r\n\t\t\t_init.proxys.push(initProxy);\r\n\t\t},\r\n\t\taddInitRoot: function(initRoot) {\r\n\t\t\t_init.roots.push(initRoot);\r\n\t\t},\r\n\t\taddNodesData: function(setting, parentNode, nodes) {\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (!parentNode[childKey]) parentNode[childKey] = [];\r\n\t\t\tif (parentNode[childKey].length > 0) {\r\n\t\t\t\tparentNode[childKey][parentNode[childKey].length - 1].isLastNode = false;\r\n\t\t\t\tview.setNodeLineIcos(setting, parentNode[childKey][parentNode[childKey].length - 1]);\r\n\t\t\t}\r\n\t\t\tparentNode.isParent = true;\r\n\t\t\tparentNode[childKey] = parentNode[childKey].concat(nodes);\r\n\t\t},\r\n\t\taddSelectedNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tif (!data.isSelectedNode(setting, node)) {\r\n\t\t\t\troot.curSelectedList.push(node);\r\n\t\t\t}\r\n\t\t},\r\n\t\taddCreatedNode: function(setting, node) {\r\n\t\t\tif (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {\r\n\t\t\t\tvar root = data.getRoot(setting);\r\n\t\t\t\troot.createdNodes.push(node);\r\n\t\t\t}\r\n\t\t},\r\n\t\taddZTreeTools: function(zTreeTools) {\r\n\t\t\t_init.zTreeTools.push(zTreeTools);\r\n\t\t},\r\n\t\texSetting: function(s) {\r\n\t\t\t$.extend(true, _setting, s);\r\n\t\t},\r\n\t\tfixPIdKeyValue: function(setting, node) {\r\n\t\t\tif (setting.data.simpleData.enable) {\r\n\t\t\t\tnode[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId;\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetAfterA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.afterA.length; i<j; i++) {\r\n\t\t\t\t_init.afterA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetBeforeA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.beforeA.length; i<j; i++) {\r\n\t\t\t\t_init.beforeA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetInnerAfterA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.innerAfterA.length; i<j; i++) {\r\n\t\t\t\t_init.innerAfterA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetInnerBeforeA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.innerBeforeA.length; i<j; i++) {\r\n\t\t\t\t_init.innerBeforeA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetCache: function(setting) {\r\n\t\t\treturn caches[setting.treeId];\r\n\t\t},\r\n\t\tgetNextNode: function(setting, node) {\r\n\t\t\tif (!node) return null;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tp = node.parentTId ? node.getParentNode() : data.getRoot(setting);\r\n\t\t\tfor (var i=0, l=p[childKey].length-1; i<=l; i++) {\r\n\t\t\t\tif (p[childKey][i] === node) {\r\n\t\t\t\t\treturn (i==l ? null : p[childKey][i+1]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tgetNodeByParam: function(setting, nodes, key, value) {\r\n\t\t\tif (!nodes || !key) return null;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i][key] == value) {\r\n\t\t\t\t\treturn nodes[i];\r\n\t\t\t\t}\r\n\t\t\t\tvar tmp = data.getNodeByParam(setting, nodes[i][childKey], key, value);\r\n\t\t\t\tif (tmp) return tmp;\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tgetNodeCache: function(setting, tId) {\r\n\t\t\tif (!tId) return null;\r\n\t\t\tvar n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)];\r\n\t\t\treturn n ? n : null;\r\n\t\t},\r\n\t\tgetNodeName: function(setting, node) {\r\n\t\t\tvar nameKey = setting.data.key.name;\r\n\t\t\treturn \"\" + node[nameKey];\r\n\t\t},\r\n\t\tgetNodeTitle: function(setting, node) {\r\n\t\t\tvar t = setting.data.key.title === \"\" ? setting.data.key.name : setting.data.key.title;\r\n\t\t\treturn \"\" + node[t];\r\n\t\t},\r\n\t\tgetNodes: function(setting) {\r\n\t\t\treturn data.getRoot(setting)[setting.data.key.children];\r\n\t\t},\r\n\t\tgetNodesByParam: function(setting, nodes, key, value) {\r\n\t\t\tif (!nodes || !key) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tresult = [];\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i][key] == value) {\r\n\t\t\t\t\tresult.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tresult = result.concat(data.getNodesByParam(setting, nodes[i][childKey], key, value));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tgetNodesByParamFuzzy: function(setting, nodes, key, value) {\r\n\t\t\tif (!nodes || !key) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tresult = [];\r\n\t\t\tvalue = value.toLowerCase();\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (typeof nodes[i][key] == \"string\" && nodes[i][key].toLowerCase().indexOf(value)>-1) {\r\n\t\t\t\t\tresult.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tresult = result.concat(data.getNodesByParamFuzzy(setting, nodes[i][childKey], key, value));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tgetNodesByFilter: function(setting, nodes, filter, isSingle, invokeParam) {\r\n\t\t\tif (!nodes) return (isSingle ? null : []);\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tresult = isSingle ? null : [];\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (tools.apply(filter, [nodes[i], invokeParam], false)) {\r\n\t\t\t\t\tif (isSingle) {return nodes[i];}\r\n\t\t\t\t\tresult.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tvar tmpResult = data.getNodesByFilter(setting, nodes[i][childKey], filter, isSingle, invokeParam);\r\n\t\t\t\tif (isSingle && !!tmpResult) {return tmpResult;}\r\n\t\t\t\tresult = isSingle ? tmpResult : result.concat(tmpResult);\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tgetPreNode: function(setting, node) {\r\n\t\t\tif (!node) return null;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tp = node.parentTId ? node.getParentNode() : data.getRoot(setting);\r\n\t\t\tfor (var i=0, l=p[childKey].length; i<l; i++) {\r\n\t\t\t\tif (p[childKey][i] === node) {\r\n\t\t\t\t\treturn (i==0 ? null : p[childKey][i-1]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tgetRoot: function(setting) {\r\n\t\t\treturn setting ? roots[setting.treeId] : null;\r\n\t\t},\r\n\t\tgetSetting: function(treeId) {\r\n\t\t\treturn settings[treeId];\r\n\t\t},\r\n\t\tgetSettings: function() {\r\n\t\t\treturn settings;\r\n\t\t},\r\n\t\tgetZTreeTools: function(treeId) {\r\n\t\t\tvar r = this.getRoot(this.getSetting(treeId));\r\n\t\t\treturn r ? r.treeTools : null;\r\n\t\t},\r\n\t\tinitCache: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.caches.length; i<j; i++) {\r\n\t\t\t\t_init.caches[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tinitNode: function(setting, level, node, parentNode, preNode, nextNode) {\r\n\t\t\tfor (var i=0, j=_init.nodes.length; i<j; i++) {\r\n\t\t\t\t_init.nodes[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tinitRoot: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.roots.length; i<j; i++) {\r\n\t\t\t\t_init.roots[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tisSelectedNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tfor (var i=0, j=root.curSelectedList.length; i<j; i++) {\r\n\t\t\t\tif(node === root.curSelectedList[i]) return true;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t},\r\n\t\tremoveNodeCache: function(setting, node) {\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (node[childKey]) {\r\n\t\t\t\tfor (var i=0, l=node[childKey].length; i<l; i++) {\r\n\t\t\t\t\targuments.callee(setting, node[childKey][i]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tdata.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null;\r\n\t\t},\r\n\t\tremoveSelectedNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tfor (var i=0, j=root.curSelectedList.length; i<j; i++) {\r\n\t\t\t\tif(node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) {\r\n\t\t\t\t\troot.curSelectedList.splice(i, 1);\r\n\t\t\t\t\ti--;j--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetCache: function(setting, cache) {\r\n\t\t\tcaches[setting.treeId] = cache;\r\n\t\t},\r\n\t\tsetRoot: function(setting, root) {\r\n\t\t\troots[setting.treeId] = root;\r\n\t\t},\r\n\t\tsetZTreeTools: function(setting, zTreeTools) {\r\n\t\t\tfor (var i=0, j=_init.zTreeTools.length; i<j; i++) {\r\n\t\t\t\t_init.zTreeTools[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\ttransformToArrayFormat: function (setting, nodes) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tr = [];\r\n\t\t\tif (tools.isArray(nodes)) {\r\n\t\t\t\tfor (var i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\tr.push(nodes[i]);\r\n\t\t\t\t\tif (nodes[i][childKey])\r\n\t\t\t\t\t\tr = r.concat(data.transformToArrayFormat(setting, nodes[i][childKey]));\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tr.push(nodes);\r\n\t\t\t\tif (nodes[childKey])\r\n\t\t\t\t\tr = r.concat(data.transformToArrayFormat(setting, nodes[childKey]));\r\n\t\t\t}\r\n\t\t\treturn r;\r\n\t\t},\r\n\t\ttransformTozTreeFormat: function(setting, sNodes) {\r\n\t\t\tvar i,l,\r\n\t\t\tkey = setting.data.simpleData.idKey,\r\n\t\t\tparentKey = setting.data.simpleData.pIdKey,\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tif (!key || key==\"\" || !sNodes) return [];\r\n\r\n\t\t\tif (tools.isArray(sNodes)) {\r\n\t\t\t\tvar r = [];\r\n\t\t\t\tvar tmpMap = [];\r\n\t\t\t\tfor (i=0, l=sNodes.length; i<l; i++) {\r\n\t\t\t\t\ttmpMap[sNodes[i][key]] = sNodes[i];\r\n\t\t\t\t}\r\n\t\t\t\tfor (i=0, l=sNodes.length; i<l; i++) {\r\n\t\t\t\t\tif (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] != sNodes[i][parentKey]) {\r\n\t\t\t\t\t\tif (!tmpMap[sNodes[i][parentKey]][childKey])\r\n\t\t\t\t\t\t\ttmpMap[sNodes[i][parentKey]][childKey] = [];\r\n\t\t\t\t\t\ttmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tr.push(sNodes[i]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn r;\r\n\t\t\t}else {\r\n\t\t\t\treturn [sNodes];\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of event proxy\r\n\tevent = {\r\n\t\tbindEvent: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.bind.length; i<j; i++) {\r\n\t\t\t\t_init.bind[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tunbindEvent: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.unbind.length; i<j; i++) {\r\n\t\t\t\t_init.unbind[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tbindTree: function(setting) {\r\n\t\t\tvar eventParam = {\r\n\t\t\t\ttreeId: setting.treeId\r\n\t\t\t},\r\n\t\t\to = setting.treeObj;\r\n\t\t\t// for can't select text\r\n\t\t\to.bind('selectstart', function(e){\r\n\t\t\t\t\tvar n = e.originalEvent.srcElement.nodeName.toLowerCase();\r\n\t\t\t\t\treturn (n === \"input\" || n === \"textarea\" );\r\n\t\t\t}).css({\r\n\t\t\t\t\"-moz-user-select\":\"-moz-none\"\r\n\t\t\t});\r\n\t\t\to.bind('click', eventParam, event.proxy);\r\n\t\t\to.bind('dblclick', eventParam, event.proxy);\r\n\t\t\to.bind('mouseover', eventParam, event.proxy);\r\n\t\t\to.bind('mouseout', eventParam, event.proxy);\r\n\t\t\to.bind('mousedown', eventParam, event.proxy);\r\n\t\t\to.bind('mouseup', eventParam, event.proxy);\r\n\t\t\to.bind('contextmenu', eventParam, event.proxy);\r\n\t\t},\r\n\t\tunbindTree: function(setting) {\r\n\t\t\tvar o = setting.treeObj;\r\n\t\t\to.unbind('click', event.proxy)\r\n\t\t\t.unbind('dblclick', event.proxy)\r\n\t\t\t.unbind('mouseover', event.proxy)\r\n\t\t\t.unbind('mouseout', event.proxy)\r\n\t\t\t.unbind('mousedown', event.proxy)\r\n\t\t\t.unbind('mouseup', event.proxy)\r\n\t\t\t.unbind('contextmenu', event.proxy);\r\n\t\t},\r\n\t\tdoProxy: function(e) {\r\n\t\t\tvar results = [];\r\n\t\t\tfor (var i=0, j=_init.proxys.length; i<j; i++) {\r\n\t\t\t\tvar proxyResult = _init.proxys[i].apply(this, arguments);\r\n\t\t\t\tresults.push(proxyResult);\r\n\t\t\t\tif (proxyResult.stop) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn results;\r\n\t\t},\r\n\t\tproxy: function(e) {\r\n\t\t\tvar setting = data.getSetting(e.data.treeId);\r\n\t\t\tif (!tools.uCanDo(setting, e)) return true;\r\n\t\t\tvar results = event.doProxy(e),\r\n\t\t\tr = true, x = false;\r\n\t\t\tfor (var i=0, l=results.length; i<l; i++) {\r\n\t\t\t\tvar proxyResult = results[i];\r\n\t\t\t\tif (proxyResult.nodeEventCallback) {\r\n\t\t\t\t\tx = true;\r\n\t\t\t\t\tr = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;\r\n\t\t\t\t}\r\n\t\t\t\tif (proxyResult.treeEventCallback) {\r\n\t\t\t\t\tx = true;\r\n\t\t\t\t\tr = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn r;\r\n\t\t}\r\n\t},\r\n\t//method of event handler\r\n\thandler = {\r\n\t\tonSwitchNode: function (event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (node.open) {\r\n\t\t\t\tif (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true;\r\n\t\t\t\tdata.getRoot(setting).expandTriggerFlag = true;\r\n\t\t\t\tview.switchNode(setting, node);\r\n\t\t\t} else {\r\n\t\t\t\tif (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true;\r\n\t\t\t\tdata.getRoot(setting).expandTriggerFlag = true;\r\n\t\t\t\tview.switchNode(setting, node);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonClickNode: function (event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tclickFlag = ( (setting.view.autoCancelSelected && event.ctrlKey) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && event.ctrlKey && setting.view.selectedMulti) ? 2 : 1;\r\n\t\t\tif (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true;\r\n\t\t\tif (clickFlag === 0) {\r\n\t\t\t\tview.cancelPreSelectedNode(setting, node);\r\n\t\t\t} else {\r\n\t\t\t\tview.selectNode(setting, node, clickFlag === 2);\r\n\t\t\t}\r\n\t\t\tsetting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]);\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeMousedown: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeMouseup: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeDblclick: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onDblClick, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeContextmenu: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onRightClick, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn (typeof setting.callback.onRightClick) != \"function\";\r\n\t\t}\r\n\t},\r\n\t//method of tools for zTree\r\n\ttools = {\r\n\t\tapply: function(fun, param, defaultValue) {\r\n\t\t\tif ((typeof fun) == \"function\") {\r\n\t\t\t\treturn fun.apply(zt, param?param:[]);\r\n\t\t\t}\r\n\t\t\treturn defaultValue;\r\n\t\t},\r\n\t\tcanAsync: function(setting, node) {\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\treturn (setting.async.enable && node && node.isParent && !(node.zAsync || (node[childKey] && node[childKey].length > 0)));\r\n\t\t},\r\n\t\tclone: function (obj){\r\n\t\t\tif (obj === null) return null;\r\n\t\t\tvar o = obj.constructor === Array ? [] : {};\r\n\t\t\tfor(var i in obj){\r\n\t\t\t\to[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === \"object\" ? arguments.callee(obj[i]) : obj[i]);\r\n\t\t\t}\r\n\t\t\treturn o;\r\n\t\t},\r\n\t\teqs: function(str1, str2) {\r\n\t\t\treturn str1.toLowerCase() === str2.toLowerCase();\r\n\t\t},\r\n\t\tisArray: function(arr) {\r\n\t\t\treturn Object.prototype.toString.apply(arr) === \"[object Array]\";\r\n\t\t},\r\n\t\tgetMDom: function (setting, curDom, targetExpr) {\r\n\t\t\tif (!curDom) return null;\r\n\t\t\twhile (curDom && curDom.id !== setting.treeId) {\r\n\t\t\t\tfor (var i=0, l=targetExpr.length; curDom.tagName && i<l; i++) {\r\n\t\t\t\t\tif (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) {\r\n\t\t\t\t\t\treturn curDom;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcurDom = curDom.parentNode;\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tuCanDo: function(setting, e) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t},\r\n\t//method of operate ztree dom\r\n\tview = {\r\n\t\taddNodes: function(setting, parentNode, newNodes, isSilent) {\r\n\t\t\tif (setting.data.keep.leaf && parentNode && !parentNode.isParent) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!tools.isArray(newNodes)) {\r\n\t\t\t\tnewNodes = [newNodes];\r\n\t\t\t}\r\n\t\t\tif (setting.data.simpleData.enable) {\r\n\t\t\t\tnewNodes = data.transformTozTreeFormat(setting, newNodes);\r\n\t\t\t}\r\n\t\t\tif (parentNode) {\r\n\t\t\t\tvar target_switchObj = $(\"#\" + parentNode.tId + consts.id.SWITCH),\r\n\t\t\t\ttarget_icoObj = $(\"#\" + parentNode.tId + consts.id.ICON),\r\n\t\t\t\ttarget_ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\r\n\t\t\t\tif (!parentNode.open) {\r\n\t\t\t\t\tview.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE);\r\n\t\t\t\t\tview.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE);\r\n\t\t\t\t\tparentNode.open = false;\r\n\t\t\t\t\ttarget_ulObj.css({\r\n\t\t\t\t\t\t\"display\": \"none\"\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdata.addNodesData(setting, parentNode, newNodes);\r\n\t\t\t\tview.createNodes(setting, parentNode.level + 1, newNodes, parentNode);\r\n\t\t\t\tif (!isSilent) {\r\n\t\t\t\t\tview.expandCollapseParentNode(setting, parentNode, true);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tdata.addNodesData(setting, data.getRoot(setting), newNodes);\r\n\t\t\t\tview.createNodes(setting, 0, newNodes, null);\r\n\t\t\t}\r\n\t\t},\r\n\t\tappendNodes: function(setting, level, nodes, parentNode, initFlag, openFlag) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar html = [],\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tvar node = nodes[i];\r\n\t\t\t\tif (initFlag) {\r\n\t\t\t\t\tvar tmpPNode = (parentNode) ? parentNode: data.getRoot(setting),\r\n\t\t\t\t\ttmpPChild = tmpPNode[childKey],\r\n\t\t\t\t\tisFirstNode = ((tmpPChild.length == nodes.length) && (i == 0)),\r\n\t\t\t\t\tisLastNode = (i == (nodes.length - 1));\r\n\t\t\t\t\tdata.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag);\r\n\t\t\t\t\tdata.addNodeCache(setting, node);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar childHtml = [];\r\n\t\t\t\tif (node[childKey] && node[childKey].length > 0) {\r\n\t\t\t\t\t//make child html first, because checkType\r\n\t\t\t\t\tchildHtml = view.appendNodes(setting, level + 1, node[childKey], node, initFlag, openFlag && node.open);\r\n\t\t\t\t}\r\n\t\t\t\tif (openFlag) {\r\n\t\t\t\t\t\r\n\t\t\t\t\tview.makeDOMNodeMainBefore(html, setting, node);\r\n\t\t\t\t\tview.makeDOMNodeLine(html, setting, node);\r\n\t\t\t\t\tdata.getBeforeA(setting, node, html);\r\n\t\t\t\t\tview.makeDOMNodeNameBefore(html, setting, node);\r\n\t\t\t\t\tdata.getInnerBeforeA(setting, node, html);\r\n\t\t\t\t\tview.makeDOMNodeIcon(html, setting, node);\r\n\t\t\t\t\tdata.getInnerAfterA(setting, node, html);\r\n\t\t\t\t\tview.makeDOMNodeNameAfter(html, setting, node);\r\n\t\t\t\t\tdata.getAfterA(setting, node, html);\r\n\t\t\t\t\tif (node.isParent && node.open) {\r\n\t\t\t\t\t\tview.makeUlHtml(setting, node, html, childHtml.join(''));\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.makeDOMNodeMainAfter(html, setting, node);\r\n\t\t\t\t\tdata.addCreatedNode(setting, node);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn html;\r\n\t\t},\r\n\t\tappendParentULDom: function(setting, node) {\r\n\t\t\tvar html = [],\r\n\t\t\tnObj = $(\"#\" + node.tId),\r\n\t\t\tulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\tchildHtml = view.appendNodes(setting, node.level+1, node[childKey], node, false, true);\r\n\t\t\tview.makeUlHtml(setting, node, html, childHtml.join(''));\r\n\t\t\tif (!nObj.get(0) && !!node.parentTId) {\r\n\t\t\t\tview.appendParentULDom(setting, node.getParentNode());\r\n\t\t\t\tnObj = $(\"#\" + node.tId);\r\n\t\t\t}\r\n\t\t\tif (ulObj.get(0)) {\r\n\t\t\t\tulObj.remove();\r\n\t\t\t}\r\n\t\t\tnObj.append(html.join(''));\r\n\t\t},\r\n\t\tasyncNode: function(setting, node, isSilent, callback) {\r\n\t\t\tvar i, l;\r\n\t\t\tif (node && !node.isParent) {\r\n\t\t\t\ttools.apply(callback);\r\n\t\t\t\treturn false;\r\n\t\t\t} else if (node && node.isAjaxing) {\r\n\t\t\t\treturn false;\r\n\t\t\t} else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) {\r\n\t\t\t\ttools.apply(callback);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tif (node) {\r\n\t\t\t\tnode.isAjaxing = true;\r\n\t\t\t\tvar icoObj = $(\"#\" + node.tId + consts.id.ICON);\r\n\t\t\t\ticoObj.attr({\"style\":\"\", \"class\":consts.className.BUTTON + \" \" + consts.className.ICO_LOADING});\r\n\t\t\t}\r\n\r\n\t\t\tvar tmpParam = {};\r\n\t\t\tfor (i = 0, l = setting.async.autoParam.length; node && i < l; i++) {\r\n\t\t\t\tvar pKey = setting.async.autoParam[i].split(\"=\"), spKey = pKey;\r\n\t\t\t\tif (pKey.length>1) {\r\n\t\t\t\t\tspKey = pKey[1];\r\n\t\t\t\t\tpKey = pKey[0];\r\n\t\t\t\t}\r\n\t\t\t\ttmpParam[spKey] = node[pKey];\r\n\t\t\t}\r\n\t\t\tif (tools.isArray(setting.async.otherParam)) {\r\n\t\t\t\tfor (i = 0, l = setting.async.otherParam.length; i < l; i += 2) {\r\n\t\t\t\t\ttmpParam[setting.async.otherParam[i]] = setting.async.otherParam[i + 1];\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tfor (var p in setting.async.otherParam) {\r\n\t\t\t\t\ttmpParam[p] = setting.async.otherParam[p];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar _tmpV = data.getRoot(setting)._ver;\r\n\t\t\t$.ajax({\r\n\t\t\t\tcontentType: setting.async.contentType,\r\n\t\t\t\ttype: setting.async.type,\r\n\t\t\t\turl: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url),\r\n\t\t\t\tdata: tmpParam,\r\n\t\t\t\tdataType: setting.async.dataType,\r\n\t\t\t\tsuccess: function(msg) {\r\n\t\t\t\t\tif (_tmpV != data.getRoot(setting)._ver) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tvar newNodes = [];\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (!msg || msg.length == 0) {\r\n\t\t\t\t\t\t\tnewNodes = [];\r\n\t\t\t\t\t\t} else if (typeof msg == \"string\") {\r\n\t\t\t\t\t\t\tnewNodes = eval(\"(\" + msg + \")\");\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tnewNodes = msg;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} catch(err) {\r\n\t\t\t\t\t\tnewNodes = msg;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (node) {\r\n\t\t\t\t\t\tnode.isAjaxing = null;\r\n\t\t\t\t\t\tnode.zAsync = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.setNodeLineIcos(setting, node);\r\n\t\t\t\t\tif (newNodes && newNodes !== \"\") {\r\n\t\t\t\t\t\tnewNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes);\r\n\t\t\t\t\t\tview.addNodes(setting, node, !!newNodes ? tools.clone(newNodes) : [], !!isSilent);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tview.addNodes(setting, node, [], !!isSilent);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]);\r\n\t\t\t\t\ttools.apply(callback);\r\n\t\t\t\t},\r\n\t\t\t\terror: function(XMLHttpRequest, textStatus, errorThrown) {\r\n\t\t\t\t\tif (_tmpV != data.getRoot(setting)._ver) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (node) node.isAjaxing = null;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, node);\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tcancelPreSelectedNode: function (setting, node) {\r\n\t\t\tvar list = data.getRoot(setting).curSelectedList;\r\n\t\t\tfor (var i=0, j=list.length-1; j>=i; j--) {\r\n\t\t\t\tif (!node || node === list[j]) {\r\n\t\t\t\t\t$(\"#\" + list[j].tId + consts.id.A).removeClass(consts.node.CURSELECTED);\r\n\t\t\t\t\tif (node) {\r\n\t\t\t\t\t\tdata.removeSelectedNode(setting, node);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!node) data.getRoot(setting).curSelectedList = [];\r\n\t\t},\r\n\t\tcreateNodeCallback: function(setting) {\r\n\t\t\tif (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {\r\n\t\t\t\tvar root = data.getRoot(setting);\r\n\t\t\t\twhile (root.createdNodes.length>0) {\r\n\t\t\t\t\tvar node = root.createdNodes.shift();\r\n\t\t\t\t\ttools.apply(setting.view.addDiyDom, [setting.treeId, node]);\r\n\t\t\t\t\tif (!!setting.callback.onNodeCreated) {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tcreateNodes: function(setting, level, nodes, parentNode) {\r\n\t\t\tif (!nodes || nodes.length == 0) return;\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\topenFlag = !parentNode || parentNode.open || !!$(\"#\" + parentNode[childKey][0].tId).get(0);\r\n\t\t\troot.createdNodes = [];\r\n\t\t\tvar zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, true, openFlag);\r\n\t\t\tif (!parentNode) {\r\n\t\t\t\tsetting.treeObj.append(zTreeHtml.join(''));\r\n\t\t\t} else {\r\n\t\t\t\tvar ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\t\t\t\tif (ulObj.get(0)) {\r\n\t\t\t\t\tulObj.append(zTreeHtml.join(''));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tview.createNodeCallback(setting);\r\n\t\t},\r\n\t\tdestroy: function(setting) {\r\n\t\t\tif (!setting) return;\r\n\t\t\tdata.initCache(setting);\r\n\t\t\tdata.initRoot(setting);\r\n\t\t\tevent.unbindTree(setting);\r\n\t\t\tevent.unbindEvent(setting);\r\n\t\t\tsetting.treeObj.empty();\r\n\t\t},\r\n\t\texpandCollapseNode: function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tif (!node) {\r\n\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (root.expandTriggerFlag) {\r\n\t\t\t\tvar _callback = callback;\r\n\t\t\t\tcallback = function(){\r\n\t\t\t\t\tif (_callback) _callback();\r\n\t\t\t\t\tif (node.open) {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\t\t\t\troot.expandTriggerFlag = false;\r\n\t\t\t}\r\n\t\t\tif (!node.open && node.isParent && ((!$(\"#\" + node.tId + consts.id.UL).get(0)) || (node[childKey] && node[childKey].length>0 && !$(\"#\" + node[childKey][0].tId).get(0)))) {\r\n\t\t\t\tview.appendParentULDom(setting, node);\r\n\t\t\t\tview.createNodeCallback(setting);\r\n\t\t\t}\r\n\t\t\tif (node.open == expandFlag) {\r\n\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar ulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\tswitchObj = $(\"#\" + node.tId + consts.id.SWITCH),\r\n\t\t\ticoObj = $(\"#\" + node.tId + consts.id.ICON);\r\n\r\n\t\t\tif (node.isParent) {\r\n\t\t\t\tnode.open = !node.open;\r\n\t\t\t\tif (node.iconOpen && node.iconClose) {\r\n\t\t\t\t\ticoObj.attr(\"style\", view.makeNodeIcoStyle(setting, node));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (node.open) {\r\n\t\t\t\t\tview.replaceSwitchClass(node, switchObj, consts.folder.OPEN);\r\n\t\t\t\t\tview.replaceIcoClass(node, icoObj, consts.folder.OPEN);\r\n\t\t\t\t\tif (animateFlag == false || setting.view.expandSpeed == \"\") {\r\n\t\t\t\t\t\tulObj.show();\r\n\t\t\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (node[childKey] && node[childKey].length > 0) {\r\n\t\t\t\t\t\t\tulObj.slideDown(setting.view.expandSpeed, callback);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tulObj.show();\r\n\t\t\t\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tview.replaceSwitchClass(node, switchObj, consts.folder.CLOSE);\r\n\t\t\t\t\tview.replaceIcoClass(node, icoObj, consts.folder.CLOSE);\r\n\t\t\t\t\tif (animateFlag == false || setting.view.expandSpeed == \"\" || !(node[childKey] && node[childKey].length > 0)) {\r\n\t\t\t\t\t\tulObj.hide();\r\n\t\t\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tulObj.slideUp(setting.view.expandSpeed, callback);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\ttools.apply(callback, []);\r\n\t\t\t}\r\n\t\t},\r\n\t\texpandCollapseParentNode: function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tif (!node) return;\r\n\t\t\tif (!node.parentTId) {\r\n\t\t\t\tview.expandCollapseNode(setting, node, expandFlag, animateFlag, callback);\r\n\t\t\t\treturn;\r\n\t\t\t} else {\r\n\t\t\t\tview.expandCollapseNode(setting, node, expandFlag, animateFlag);\r\n\t\t\t}\r\n\t\t\tif (node.parentTId) {\r\n\t\t\t\tview.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback);\r\n\t\t\t}\r\n\t\t},\r\n\t\texpandCollapseSonNode: function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\ttreeNodes = (node) ? node[childKey]: root[childKey],\r\n\t\t\tselfAnimateSign = (node) ? false : animateFlag,\r\n\t\t\texpandTriggerFlag = data.getRoot(setting).expandTriggerFlag;\r\n\t\t\tdata.getRoot(setting).expandTriggerFlag = false;\r\n\t\t\tif (treeNodes) {\r\n\t\t\t\tfor (var i = 0, l = treeNodes.length; i < l; i++) {\r\n\t\t\t\t\tif (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tdata.getRoot(setting).expandTriggerFlag = expandTriggerFlag;\r\n\t\t\tview.expandCollapseNode(setting, node, expandFlag, animateFlag, callback );\r\n\t\t},\r\n\t\tmakeDOMNodeIcon: function(html, setting, node) {\r\n\t\t\tvar nameStr = data.getNodeName(setting, node),\r\n\t\t\tname = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\r\n\t\t\thtml.push(\"<span id='\", node.tId, consts.id.ICON,\r\n\t\t\t\t\"' title='' treeNode\", consts.id.ICON,\" class='\", view.makeNodeIcoClass(setting, node),\r\n\t\t\t\t\"' style='\", view.makeNodeIcoStyle(setting, node), \"'></span><span id='\", node.tId, consts.id.SPAN,\r\n\t\t\t\t\"'>\",name,\"</span>\");\r\n\t\t},\r\n\t\tmakeDOMNodeLine: function(html, setting, node) {\r\n\t\t\thtml.push(\"<span id='\", node.tId, consts.id.SWITCH,\t\"' title='' class='\", view.makeNodeLineClass(setting, node), \"' treeNode\", consts.id.SWITCH,\"></span>\");\r\n\t\t},\r\n\t\tmakeDOMNodeMainAfter: function(html, setting, node) {\r\n\t\t\thtml.push(\"</li>\");\r\n\t\t},\r\n\t\tmakeDOMNodeMainBefore: function(html, setting, node) {\r\n\t\t\thtml.push(\"<li id='\", node.tId, \"' class='\", consts.className.LEVEL, node.level,\"' tabindex='0' hidefocus='true' treenode>\");\r\n\t\t},\r\n\t\tmakeDOMNodeNameAfter: function(html, setting, node) {\r\n\t\t\thtml.push(\"</a>\");\r\n\t\t},\r\n\t\tmakeDOMNodeNameBefore: function(html, setting, node) {\r\n\t\t\tvar title = data.getNodeTitle(setting, node),\r\n\t\t\turl = view.makeNodeUrl(setting, node),\r\n\t\t\tfontcss = view.makeNodeFontCss(setting, node),\r\n\t\t\tfontStyle = [];\r\n\t\t\tfor (var f in fontcss) {\r\n\t\t\t\tfontStyle.push(f, \":\", fontcss[f], \";\");\r\n\t\t\t}\r\n\t\t\thtml.push(\"<a id='\", node.tId, consts.id.A, \"' class='\", consts.className.LEVEL, node.level,\"' treeNode\", consts.id.A,\" onclick=\\\"\", (node.click || ''),\r\n\t\t\t\t\"\\\" \", ((url != null && url.length > 0) ? \"href='\" + url + \"'\" : \"\"), \" target='\",view.makeNodeTarget(node),\"' style='\", fontStyle.join(''),\r\n\t\t\t\t\"'\");\r\n\t\t\tif (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) {html.push(\"title='\", title.replace(/'/g,\"&#39;\").replace(/</g,'&lt;').replace(/>/g,'&gt;'),\"'\");}\r\n\t\t\thtml.push(\">\");\r\n\t\t},\r\n\t\tmakeNodeFontCss: function(setting, node) {\r\n\t\t\tvar fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss);\r\n\t\t\treturn (fontCss && ((typeof fontCss) != \"function\")) ? fontCss : {};\r\n\t\t},\r\n\t\tmakeNodeIcoClass: function(setting, node) {\r\n\t\t\tvar icoCss = [\"ico\"];\r\n\t\t\tif (!node.isAjaxing) {\r\n\t\t\t\ticoCss[0] = (node.iconSkin ? node.iconSkin + \"_\" : \"\") + icoCss[0];\r\n\t\t\t\tif (node.isParent) {\r\n\t\t\t\t\ticoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);\r\n\t\t\t\t} else {\r\n\t\t\t\t\ticoCss.push(consts.folder.DOCU);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn consts.className.BUTTON + \" \" + icoCss.join('_');\r\n\t\t},\r\n\t\tmakeNodeIcoStyle: function(setting, node) {\r\n\t\t\tvar icoStyle = [];\r\n\t\t\tif (!node.isAjaxing) {\r\n\t\t\t\tvar icon = (node.isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node.icon;\r\n\t\t\t\tif (icon) icoStyle.push(\"background:url(\", icon, \") 0 0 no-repeat;\");\r\n\t\t\t\tif (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) {\r\n\t\t\t\t\ticoStyle.push(\"width:0px;height:0px;\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn icoStyle.join('');\r\n\t\t},\r\n\t\tmakeNodeLineClass: function(setting, node) {\r\n\t\t\tvar lineClass = [];\r\n\t\t\tif (setting.view.showLine) {\r\n\t\t\t\tif (node.level == 0 && node.isFirstNode && node.isLastNode) {\r\n\t\t\t\t\tlineClass.push(consts.line.ROOT);\r\n\t\t\t\t} else if (node.level == 0 && node.isFirstNode) {\r\n\t\t\t\t\tlineClass.push(consts.line.ROOTS);\r\n\t\t\t\t} else if (node.isLastNode) {\r\n\t\t\t\t\tlineClass.push(consts.line.BOTTOM);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineClass.push(consts.line.CENTER);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tlineClass.push(consts.line.NOLINE);\r\n\t\t\t}\r\n\t\t\tif (node.isParent) {\r\n\t\t\t\tlineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);\r\n\t\t\t} else {\r\n\t\t\t\tlineClass.push(consts.folder.DOCU);\r\n\t\t\t}\r\n\t\t\treturn view.makeNodeLineClassEx(node) + lineClass.join('_');\r\n\t\t},\r\n\t\tmakeNodeLineClassEx: function(node) {\r\n\t\t\treturn consts.className.BUTTON + \" \" + consts.className.LEVEL + node.level + \" \" + consts.className.SWITCH + \" \";\r\n\t\t},\r\n\t\tmakeNodeTarget: function(node) {\r\n\t\t\treturn (node.target || \"_blank\");\r\n\t\t},\r\n\t\tmakeNodeUrl: function(setting, node) {\r\n\t\t\tvar urlKey = setting.data.key.url;\r\n\t\t\treturn node[urlKey] ? node[urlKey] : null;\r\n\t\t},\r\n\t\tmakeUlHtml: function(setting, node, html, content) {\r\n\t\t\thtml.push(\"<ul id='\", node.tId, consts.id.UL, \"' class='\", consts.className.LEVEL, node.level, \" \", view.makeUlLineClass(setting, node), \"' style='display:\", (node.open ? \"block\": \"none\"),\"'>\");\r\n\t\t\thtml.push(content);\r\n\t\t\thtml.push(\"</ul>\");\r\n\t\t},\r\n\t\tmakeUlLineClass: function(setting, node) {\r\n\t\t\treturn ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : \"\");\r\n\t\t},\r\n\t\tremoveChildNodes: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tnodes = node[childKey];\r\n\t\t\tif (!nodes) return;\r\n\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tdata.removeNodeCache(setting, nodes[i]);\r\n\t\t\t}\r\n\t\t\tdata.removeSelectedNode(setting);\r\n\t\t\tdelete node[childKey];\r\n\r\n\t\t\tif (!setting.data.keep.parent) {\r\n\t\t\t\tnode.isParent = false;\r\n\t\t\t\tnode.open = false;\r\n\t\t\t\tvar tmp_switchObj = $(\"#\" + node.tId + consts.id.SWITCH),\r\n\t\t\t\ttmp_icoObj = $(\"#\" + node.tId + consts.id.ICON);\r\n\t\t\t\tview.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU);\r\n\t\t\t\tview.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU);\r\n\t\t\t\t$(\"#\" + node.tId + consts.id.UL).remove();\r\n\t\t\t} else {\r\n\t\t\t\t$(\"#\" + node.tId + consts.id.UL).empty();\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetFirstNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif ( childLength > 0) {\r\n\t\t\t\tparentNode[childKey][0].isFirstNode = true;\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetLastNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif ( childLength > 0) {\r\n\t\t\t\tparentNode[childKey][childLength - 1].isLastNode = true;\r\n\t\t\t}\r\n\t\t},\r\n\t\tremoveNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\tparentNode = (node.parentTId) ? node.getParentNode() : root;\r\n\r\n\t\t\tnode.isFirstNode = false;\r\n\t\t\tnode.isLastNode = false;\r\n\t\t\tnode.getPreNode = function() {return null;};\r\n\t\t\tnode.getNextNode = function() {return null;};\r\n\r\n\t\t\tif (!data.getNodeCache(setting, node.tId)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n                        \r\n\t\t\t$(\"#\" + node.tId).remove();\r\n\t\t\tdata.removeNodeCache(setting, node);\r\n\t\t\tdata.removeSelectedNode(setting, node);\r\n\r\n\t\t\tfor (var i = 0, l = parentNode[childKey].length; i < l; i++) {\r\n\t\t\t\tif (parentNode[childKey][i].tId == node.tId) {\r\n\t\t\t\t\tparentNode[childKey].splice(i, 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tview.setFirstNode(setting, parentNode);\r\n\t\t\tview.setLastNode(setting, parentNode);\r\n                                                \r\n\t\t\tvar tmp_ulObj,tmp_switchObj,tmp_icoObj,\r\n\t\t\tchildLength = parentNode[childKey].length;\r\n\r\n\t\t\t//repair nodes old parent\r\n\t\t\tif (!setting.data.keep.parent && childLength == 0) {\r\n\t\t\t\t//old parentNode has no child nodes\r\n\t\t\t\tparentNode.isParent = false;\r\n\t\t\t\tparentNode.open = false;\r\n\t\t\t\ttmp_ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\t\t\t\ttmp_switchObj = $(\"#\" + parentNode.tId + consts.id.SWITCH);\r\n\t\t\t\ttmp_icoObj = $(\"#\" + parentNode.tId + consts.id.ICON);\r\n\t\t\t\tview.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU);\r\n\t\t\t\tview.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU);\r\n\t\t\t\ttmp_ulObj.css(\"display\", \"none\");\r\n\r\n\t\t\t} else if (setting.view.showLine && childLength > 0) {\r\n\t\t\t\t//old parentNode has child nodes\r\n\t\t\t\tvar newLast = parentNode[childKey][childLength - 1];\r\n\t\t\t\ttmp_ulObj = $(\"#\" + newLast.tId + consts.id.UL);\r\n\t\t\t\ttmp_switchObj = $(\"#\" + newLast.tId + consts.id.SWITCH);\r\n\t\t\t\ttmp_icoObj = $(\"#\" + newLast.tId + consts.id.ICON);\r\n\t\t\t\tif (parentNode == root) {\r\n\t\t\t\t\tif (parentNode[childKey].length == 1) {\r\n\t\t\t\t\t\t//node was root, and ztree has only one root after move node\r\n\t\t\t\t\t\tview.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tvar tmp_first_switchObj = $(\"#\" + parentNode[childKey][0].tId + consts.id.SWITCH);\r\n\t\t\t\t\t\tview.replaceSwitchClass(parentNode[childKey][0], tmp_first_switchObj, consts.line.ROOTS);\r\n\t\t\t\t\t\tview.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tview.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);\r\n\t\t\t\t}\r\n\t\t\t\ttmp_ulObj.removeClass(consts.line.LINE);\r\n\t\t\t}\r\n\t\t},\r\n\t\treplaceIcoClass: function(node, obj, newName) {\r\n\t\t\tif (!obj || node.isAjaxing) return;\r\n\t\t\tvar tmpName = obj.attr(\"class\");\r\n\t\t\tif (tmpName == undefined) return;\r\n\t\t\tvar tmpList = tmpName.split(\"_\");\r\n\t\t\tswitch (newName) {\r\n\t\t\t\tcase consts.folder.OPEN:\r\n\t\t\t\tcase consts.folder.CLOSE:\r\n\t\t\t\tcase consts.folder.DOCU:\r\n\t\t\t\t\ttmpList[tmpList.length-1] = newName;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tobj.attr(\"class\", tmpList.join(\"_\"));\r\n\t\t},\r\n\t\treplaceSwitchClass: function(node, obj, newName) {\r\n\t\t\tif (!obj) return;\r\n\t\t\tvar tmpName = obj.attr(\"class\");\r\n\t\t\tif (tmpName == undefined) return;\r\n\t\t\tvar tmpList = tmpName.split(\"_\");\r\n\t\t\tswitch (newName) {\r\n\t\t\t\tcase consts.line.ROOT:\r\n\t\t\t\tcase consts.line.ROOTS:\r\n\t\t\t\tcase consts.line.CENTER:\r\n\t\t\t\tcase consts.line.BOTTOM:\r\n\t\t\t\tcase consts.line.NOLINE:\r\n\t\t\t\t\ttmpList[0] = view.makeNodeLineClassEx(node) + newName;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase consts.folder.OPEN:\r\n\t\t\t\tcase consts.folder.CLOSE:\r\n\t\t\t\tcase consts.folder.DOCU:\r\n\t\t\t\t\ttmpList[1] = newName;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tobj.attr(\"class\", tmpList.join(\"_\"));\r\n\t\t\tif (newName !== consts.folder.DOCU) {\r\n\t\t\t\tobj.removeAttr(\"disabled\");\r\n\t\t\t} else {\r\n\t\t\t\tobj.attr(\"disabled\", \"disabled\");\r\n\t\t\t}\r\n\t\t},\r\n\t\tselectNode: function(setting, node, addFlag) {\r\n\t\t\tif (!addFlag) {\r\n\t\t\t\tview.cancelPreSelectedNode(setting);\r\n\t\t\t}\r\n\t\t\t$(\"#\" + node.tId + consts.id.A).addClass(consts.node.CURSELECTED);\r\n\t\t\tdata.addSelectedNode(setting, node);\r\n\t\t},\r\n\t\tsetNodeFontCss: function(setting, treeNode) {\r\n\t\t\tvar aObj = $(\"#\" + treeNode.tId + consts.id.A),\r\n\t\t\tfontCss = view.makeNodeFontCss(setting, treeNode);\r\n\t\t\tif (fontCss) {\r\n\t\t\t\taObj.css(fontCss);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetNodeLineIcos: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar switchObj = $(\"#\" + node.tId + consts.id.SWITCH),\r\n\t\t\tulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\ticoObj = $(\"#\" + node.tId + consts.id.ICON),\r\n\t\t\tulLine = view.makeUlLineClass(setting, node);\r\n\t\t\tif (ulLine.length==0) {\r\n\t\t\t\tulObj.removeClass(consts.line.LINE);\r\n\t\t\t} else {\r\n\t\t\t\tulObj.addClass(ulLine);\r\n\t\t\t}\r\n\t\t\tswitchObj.attr(\"class\", view.makeNodeLineClass(setting, node));\r\n\t\t\tif (node.isParent) {\r\n\t\t\t\tswitchObj.removeAttr(\"disabled\");\r\n\t\t\t} else {\r\n\t\t\t\tswitchObj.attr(\"disabled\", \"disabled\");\r\n\t\t\t}\r\n\t\t\ticoObj.removeAttr(\"style\");\r\n\t\t\ticoObj.attr(\"style\", view.makeNodeIcoStyle(setting, node));\r\n\t\t\ticoObj.attr(\"class\", view.makeNodeIcoClass(setting, node));\r\n\t\t},\r\n\t\tsetNodeName: function(setting, node) {\r\n\t\t\tvar title = data.getNodeTitle(setting, node),\r\n\t\t\tnObj = $(\"#\" + node.tId + consts.id.SPAN);\r\n\t\t\tnObj.empty();\r\n\t\t\tif (setting.view.nameIsHTML) {\r\n\t\t\t\tnObj.html(data.getNodeName(setting, node));\r\n\t\t\t} else {\r\n\t\t\t\tnObj.text(data.getNodeName(setting, node));\r\n\t\t\t}\r\n\t\t\tif (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) {\r\n\t\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A);\r\n\t\t\t\taObj.attr(\"title\", !title ? \"\" : title);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetNodeTarget: function(node) {\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A);\r\n\t\t\taObj.attr(\"target\", view.makeNodeTarget(node));\r\n\t\t},\r\n\t\tsetNodeUrl: function(setting, node) {\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\turl = view.makeNodeUrl(setting, node);\r\n\t\t\tif (url == null || url.length == 0) {\r\n\t\t\t\taObj.removeAttr(\"href\");\r\n\t\t\t} else {\r\n\t\t\t\taObj.attr(\"href\", url);\r\n\t\t\t}\r\n\t\t},\r\n\t\tswitchNode: function(setting, node) {\r\n\t\t\tif (node.open || !tools.canAsync(setting, node)) {\r\n\t\t\t\tview.expandCollapseNode(setting, node, !node.open);\r\n\t\t\t} else if (setting.async.enable) {\r\n\t\t\t\tif (!view.asyncNode(setting, node)) {\r\n\t\t\t\t\tview.expandCollapseNode(setting, node, !node.open);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t} else if (node) {\r\n\t\t\t\tview.expandCollapseNode(setting, node, !node.open);\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\t// zTree defind\r\n\t$.fn.zTree = {\r\n\t\tconsts : _consts,\r\n\t\t_z : {\r\n\t\t\ttools: tools,\r\n\t\t\tview: view,\r\n\t\t\tevent: event,\r\n\t\t\tdata: data\r\n\t\t},\r\n\t\tgetZTreeObj: function(treeId) {\r\n\t\t\tvar o = data.getZTreeTools(treeId);\r\n\t\t\treturn o ? o : null;\r\n\t\t},\r\n\t\tdestroy: function(treeId) {\r\n\t\t\tif (!!treeId && treeId.length > 0) {\r\n\t\t\t\tview.destroy(data.getSetting(treeId));\r\n\t\t\t} else {\r\n\t\t\t\tfor(var s in settings) {\r\n\t\t\t\t\tview.destroy(settings[s]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tinit: function(obj, zSetting, zNodes) {\r\n\t\t\tvar setting = tools.clone(_setting);\r\n\t\t\t$.extend(true, setting, zSetting);\r\n\t\t\tsetting.treeId = obj.attr(\"id\");\r\n\t\t\tsetting.treeObj = obj;\r\n\t\t\tsetting.treeObj.empty();\r\n\t\t\tsettings[setting.treeId] = setting;\r\n\t\t\t//For some older browser,(e.g., ie6)\r\n\t\t\tif(typeof document.body.style.maxHeight === \"undefined\") {\r\n\t\t\t\tsetting.view.expandSpeed = \"\";\r\n\t\t\t}\r\n\t\t\tdata.initRoot(setting);\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tzNodes = zNodes ? tools.clone(tools.isArray(zNodes)? zNodes : [zNodes]) : [];\r\n\t\t\tif (setting.data.simpleData.enable) {\r\n\t\t\t\troot[childKey] = data.transformTozTreeFormat(setting, zNodes);\r\n\t\t\t} else {\r\n\t\t\t\troot[childKey] = zNodes;\r\n\t\t\t}\r\n\r\n\t\t\tdata.initCache(setting);\r\n\t\t\tevent.unbindTree(setting);\r\n\t\t\tevent.bindTree(setting);\r\n\t\t\tevent.unbindEvent(setting);\r\n\t\t\tevent.bindEvent(setting);\r\n\t\t\t\r\n\t\t\tvar zTreeTools = {\r\n\t\t\t\tsetting : setting,\r\n\t\t\t\taddNodes : function(parentNode, newNodes, isSilent) {\r\n\t\t\t\t\tif (!newNodes) return null;\r\n\t\t\t\t\tif (!parentNode) parentNode = null;\r\n\t\t\t\t\tif (parentNode && !parentNode.isParent && setting.data.keep.leaf) return null;\r\n\t\t\t\t\tvar xNewNodes = tools.clone(tools.isArray(newNodes)? newNodes: [newNodes]);\r\n\t\t\t\t\tfunction addCallback() {\r\n\t\t\t\t\t\tview.addNodes(setting, parentNode, xNewNodes, (isSilent==true));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (tools.canAsync(setting, parentNode)) {\r\n\t\t\t\t\t\tview.asyncNode(setting, parentNode, isSilent, addCallback);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\taddCallback();\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn xNewNodes;\r\n\t\t\t\t},\r\n\t\t\t\tcancelSelectedNode : function(node) {\r\n\t\t\t\t\tview.cancelPreSelectedNode(this.setting, node);\r\n\t\t\t\t},\r\n\t\t\t\tdestroy : function() {\r\n\t\t\t\t\tview.destroy(this.setting);\r\n\t\t\t\t},\r\n\t\t\t\texpandAll : function(expandFlag) {\r\n\t\t\t\t\texpandFlag = !!expandFlag;\r\n\t\t\t\t\tview.expandCollapseSonNode(this.setting, null, expandFlag, true);\r\n\t\t\t\t\treturn expandFlag;\r\n\t\t\t\t},\r\n\t\t\t\texpandNode : function(node, expandFlag, sonSign, focus, callbackFlag) {\r\n\t\t\t\t\tif (!node || !node.isParent) return null;\r\n\t\t\t\t\tif (expandFlag !== true && expandFlag !== false) {\r\n\t\t\t\t\t\texpandFlag = !node.open;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcallbackFlag = !!callbackFlag;\r\n\r\n\t\t\t\t\tif (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) {\r\n\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t} else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) {\r\n\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (expandFlag && node.parentTId) {\r\n\t\t\t\t\t\tview.expandCollapseParentNode(this.setting, node.getParentNode(), expandFlag, false);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (expandFlag === node.open && !sonSign) {\r\n\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tdata.getRoot(setting).expandTriggerFlag = callbackFlag;\r\n\t\t\t\t\tif (sonSign) {\r\n\t\t\t\t\t\tview.expandCollapseSonNode(this.setting, node, expandFlag, true, function() {\r\n\t\t\t\t\t\t\tif (focus !== false) {try{$(\"#\" + node.tId).focus().blur();}catch(e){}}\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tnode.open = !expandFlag;\r\n\t\t\t\t\t\tview.switchNode(this.setting, node);\r\n\t\t\t\t\t\tif (focus !== false) {try{$(\"#\" + node.tId).focus().blur();}catch(e){}}\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn expandFlag;\r\n\t\t\t\t},\r\n\t\t\t\tgetNodes : function() {\r\n\t\t\t\t\treturn data.getNodes(this.setting);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodeByParam : function(key, value, parentNode) {\r\n\t\t\t\t\tif (!key) return null;\r\n\t\t\t\t\treturn data.getNodeByParam(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), key, value);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodeByTId : function(tId) {\r\n\t\t\t\t\treturn data.getNodeCache(this.setting, tId);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodesByParam : function(key, value, parentNode) {\r\n\t\t\t\t\tif (!key) return null;\r\n\t\t\t\t\treturn data.getNodesByParam(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), key, value);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodesByParamFuzzy : function(key, value, parentNode) {\r\n\t\t\t\t\tif (!key) return null;\r\n\t\t\t\t\treturn data.getNodesByParamFuzzy(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), key, value);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodesByFilter: function(filter, isSingle, parentNode, invokeParam) {\r\n\t\t\t\t\tisSingle = !!isSingle;\r\n\t\t\t\t\tif (!filter || (typeof filter != \"function\")) return (isSingle ? null : []);\r\n\t\t\t\t\treturn data.getNodesByFilter(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), filter, isSingle, invokeParam);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodeIndex : function(node) {\r\n\t\t\t\t\tif (!node) return null;\r\n\t\t\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\t\t\tparentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(this.setting);\r\n\t\t\t\t\tfor (var i=0, l = parentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\t\tif (parentNode[childKey][i] == node) return i;\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn -1;\r\n\t\t\t\t},\r\n\t\t\t\tgetSelectedNodes : function() {\r\n\t\t\t\t\tvar r = [], list = data.getRoot(this.setting).curSelectedList;\r\n\t\t\t\t\tfor (var i=0, l=list.length; i<l; i++) {\r\n\t\t\t\t\t\tr.push(list[i]);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn r;\r\n\t\t\t\t},\r\n\t\t\t\tisSelectedNode : function(node) {\r\n\t\t\t\t\treturn data.isSelectedNode(this.setting, node);\r\n\t\t\t\t},\r\n\t\t\t\treAsyncChildNodes : function(parentNode, reloadType, isSilent) {\r\n\t\t\t\t\tif (!this.setting.async.enable) return;\r\n\t\t\t\t\tvar isRoot = !parentNode;\r\n\t\t\t\t\tif (isRoot) {\r\n\t\t\t\t\t\tparentNode = data.getRoot(this.setting);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (reloadType==\"refresh\") {\r\n\t\t\t\t\t\tvar childKey = this.setting.data.key.children;\r\n\t\t\t\t\t\tfor (var i = 0, l = parentNode[childKey] ? parentNode[childKey].length : 0; i < l; i++) {\r\n\t\t\t\t\t\t\tdata.removeNodeCache(setting, parentNode[childKey][i]);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdata.removeSelectedNode(setting);\r\n\t\t\t\t\t\tparentNode[childKey] = [];\r\n\t\t\t\t\t\tif (isRoot) {\r\n\t\t\t\t\t\t\tthis.setting.treeObj.empty();\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tvar ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\t\t\t\t\t\t\tulObj.empty();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.asyncNode(this.setting, isRoot? null:parentNode, !!isSilent);\r\n\t\t\t\t},\r\n\t\t\t\trefresh : function() {\r\n\t\t\t\t\tthis.setting.treeObj.empty();\r\n\t\t\t\t\tvar root = data.getRoot(this.setting),\r\n\t\t\t\t\tnodes = root[this.setting.data.key.children]\r\n\t\t\t\t\tdata.initRoot(this.setting);\r\n\t\t\t\t\troot[this.setting.data.key.children] = nodes\r\n\t\t\t\t\tdata.initCache(this.setting);\r\n\t\t\t\t\tview.createNodes(this.setting, 0, root[this.setting.data.key.children]);\r\n\t\t\t\t},\r\n\t\t\t\tremoveChildNodes : function(node) {\r\n\t\t\t\t\tif (!node) return null;\r\n\t\t\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\t\t\tnodes = node[childKey];\r\n\t\t\t\t\tview.removeChildNodes(setting, node);\r\n\t\t\t\t\treturn nodes ? nodes : null;\r\n\t\t\t\t},\r\n\t\t\t\tremoveNode : function(node, callbackFlag) {\r\n\t\t\t\t\tif (!node) return;\r\n\t\t\t\t\tcallbackFlag = !!callbackFlag;\r\n\t\t\t\t\tif (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return;\r\n\t\t\t\t\tview.removeNode(setting, node);\r\n\t\t\t\t\tif (callbackFlag) {\r\n\t\t\t\t\t\tthis.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t\tselectNode : function(node, addFlag) {\r\n\t\t\t\t\tif (!node) return;\r\n\t\t\t\t\tif (tools.uCanDo(this.setting)) {\r\n\t\t\t\t\t\taddFlag = setting.view.selectedMulti && addFlag;\r\n\t\t\t\t\t\tif (node.parentTId) {\r\n\t\t\t\t\t\t\tview.expandCollapseParentNode(this.setting, node.getParentNode(), true, false, function() {\r\n\t\t\t\t\t\t\t\ttry{$(\"#\" + node.tId).focus().blur();}catch(e){}\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttry{$(\"#\" + node.tId).focus().blur();}catch(e){}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tview.selectNode(this.setting, node, addFlag);\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t\ttransformTozTreeNodes : function(simpleNodes) {\r\n\t\t\t\t\treturn data.transformTozTreeFormat(this.setting, simpleNodes);\r\n\t\t\t\t},\r\n\t\t\t\ttransformToArray : function(nodes) {\r\n\t\t\t\t\treturn data.transformToArrayFormat(this.setting, nodes);\r\n\t\t\t\t},\r\n\t\t\t\tupdateNode : function(node, checkTypeFlag) {\r\n\t\t\t\t\tif (!node) return;\r\n\t\t\t\t\tvar nObj = $(\"#\" + node.tId);\r\n\t\t\t\t\tif (nObj.get(0) && tools.uCanDo(this.setting)) {\r\n\t\t\t\t\t\tview.setNodeName(this.setting, node);\r\n\t\t\t\t\t\tview.setNodeTarget(node);\r\n\t\t\t\t\t\tview.setNodeUrl(this.setting, node);\r\n\t\t\t\t\t\tview.setNodeLineIcos(this.setting, node);\r\n\t\t\t\t\t\tview.setNodeFontCss(this.setting, node);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\troot.treeTools = zTreeTools;\r\n\t\t\tdata.setZTreeTools(setting, zTreeTools);\r\n\r\n\t\t\tif (root[childKey] && root[childKey].length > 0) {\r\n\t\t\t\tview.createNodes(setting, 0, root[childKey]);\r\n\t\t\t} else if (setting.async.enable && setting.async.url && setting.async.url !== '') {\r\n\t\t\t\tview.asyncNode(setting);\r\n\t\t\t}\r\n\t\t\treturn zTreeTools;\r\n\t\t}\r\n\t};\r\n\r\n\tvar zt = $.fn.zTree,\r\n\tconsts = zt.consts;\r\n})(jQuery);\r\n/*\r\n * JQuery zTree excheck 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\t//default consts of excheck\r\n\tvar _consts = {\r\n\t\tevent: {\r\n\t\t\tCHECK: \"ztree_check\"\r\n\t\t},\r\n\t\tid: {\r\n\t\t\tCHECK: \"_check\"\r\n\t\t},\r\n\t\tcheckbox: {\r\n\t\t\tSTYLE: \"checkbox\",\r\n\t\t\tDEFAULT: \"chk\",\r\n\t\t\tDISABLED: \"disable\",\r\n\t\t\tFALSE: \"false\",\r\n\t\t\tTRUE: \"true\",\r\n\t\t\tFULL: \"full\",\r\n\t\t\tPART: \"part\",\r\n\t\t\tFOCUS: \"focus\"\r\n\t\t},\r\n\t\tradio: {\r\n\t\t\tSTYLE: \"radio\",\r\n\t\t\tTYPE_ALL: \"all\",\r\n\t\t\tTYPE_LEVEL: \"level\"\r\n\t\t}\r\n\t},\r\n\t//default setting of excheck\r\n\t_setting = {\r\n\t\tcheck: {\r\n\t\t\tenable: false,\r\n\t\t\tautoCheckTrigger: false,\r\n\t\t\tchkStyle: _consts.checkbox.STYLE,\r\n\t\t\tnocheckInherit: false,\r\n\t\t\tchkDisabledInherit: false,\r\n\t\t\tradioType: _consts.radio.TYPE_LEVEL,\r\n\t\t\tchkboxType: {\r\n\t\t\t\t\"Y\": \"ps\",\r\n\t\t\t\t\"N\": \"ps\"\r\n\t\t\t}\r\n\t\t},\r\n\t\tdata: {\r\n\t\t\tkey: {\r\n\t\t\t\tchecked: \"checked\"\r\n\t\t\t}\r\n\t\t},\r\n\t\tcallback: {\r\n\t\t\tbeforeCheck:null,\r\n\t\t\tonCheck:null\r\n\t\t}\r\n\t},\r\n\t//default root of excheck\r\n\t_initRoot = function (setting) {\r\n\t\tvar r = data.getRoot(setting);\r\n\t\tr.radioCheckedList = [];\r\n\t},\r\n\t//default cache of excheck\r\n\t_initCache = function(treeId) {},\r\n\t//default bind event of excheck\r\n\t_bindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.bind(c.CHECK, function (event, srcEvent, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onCheck, [!!srcEvent?srcEvent : event, treeId, node]);\r\n\t\t});\r\n\t},\r\n\t_unbindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.unbind(c.CHECK);\r\n\t},\r\n\t//default event proxy of excheck\r\n\t_eventProxy = function(e) {\r\n\t\tvar target = e.target,\r\n\t\tsetting = data.getSetting(e.data.treeId),\r\n\t\ttId = \"\", node = null,\r\n\t\tnodeEventType = \"\", treeEventType = \"\",\r\n\t\tnodeEventCallback = null, treeEventCallback = null;\r\n\r\n\t\tif (tools.eqs(e.type, \"mouseover\")) {\r\n\t\t\tif (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.CHECK) !== null) {\r\n\t\t\t\ttId = target.parentNode.id;\r\n\t\t\t\tnodeEventType = \"mouseoverCheck\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"mouseout\")) {\r\n\t\t\tif (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.CHECK) !== null) {\r\n\t\t\t\ttId = target.parentNode.id;\r\n\t\t\t\tnodeEventType = \"mouseoutCheck\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"click\")) {\r\n\t\t\tif (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.CHECK) !== null) {\r\n\t\t\t\ttId = target.parentNode.id;\r\n\t\t\t\tnodeEventType = \"checkNode\";\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (tId.length>0) {\r\n\t\t\tnode = data.getNodeCache(setting, tId);\r\n\t\t\tswitch (nodeEventType) {\r\n\t\t\t\tcase \"checkNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onCheckNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"mouseoverCheck\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onMouseoverCheck;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"mouseoutCheck\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onMouseoutCheck;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tvar proxyResult = {\r\n\t\t\tstop: false,\r\n\t\t\tnode: node,\r\n\t\t\tnodeEventType: nodeEventType,\r\n\t\t\tnodeEventCallback: nodeEventCallback,\r\n\t\t\ttreeEventType: treeEventType,\r\n\t\t\ttreeEventCallback: treeEventCallback\r\n\t\t};\r\n\t\treturn proxyResult\r\n\t},\r\n\t//default init node of excheck\r\n\t_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (!n) return;\r\n\t\tvar checkedKey = setting.data.key.checked;\r\n\t\tif (typeof n[checkedKey] == \"string\") n[checkedKey] = tools.eqs(n[checkedKey], \"true\");\r\n\t\tn[checkedKey] = !!n[checkedKey];\r\n\t\tn.checkedOld = n[checkedKey];\r\n\t\tif (typeof n.nocheck == \"string\") n.nocheck = tools.eqs(n.nocheck, \"true\");\r\n\t\tn.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck);\r\n\t\tif (typeof n.chkDisabled == \"string\") n.chkDisabled = tools.eqs(n.chkDisabled, \"true\");\r\n\t\tn.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled);\r\n\t\tif (typeof n.halfCheck == \"string\") n.halfCheck = tools.eqs(n.halfCheck, \"true\");\r\n\t\tn.halfCheck = !!n.halfCheck;\r\n\t\tn.check_Child_State = -1;\r\n\t\tn.check_Focus = false;\r\n\t\tn.getCheckStatus = function() {return data.getCheckStatus(setting, n);};\r\n\t},\r\n\t//add dom for check\r\n\t_beforeA = function(setting, node, html) {\r\n\t\tvar checkedKey = setting.data.key.checked;\r\n\t\tif (setting.check.enable) {\r\n\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\tif (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && node[checkedKey] ) {\r\n\t\t\t\tvar r = data.getRoot(setting);\r\n\t\t\t\tr.radioCheckedList.push(node);\r\n\t\t\t}\r\n\t\t\thtml.push(\"<span ID='\", node.tId, consts.id.CHECK, \"' class='\", view.makeChkClass(setting, node), \"' treeNode\", consts.id.CHECK, (node.nocheck === true?\" style='display:none;'\":\"\"),\"></span>\");\r\n\t\t}\r\n\t},\r\n\t//update zTreeObj, add method of check\r\n\t_zTreeTools = function(setting, zTreeTools) {\r\n\t\tzTreeTools.checkNode = function(node, checked, checkTypeFlag, callbackFlag) {\r\n\t\t\tvar checkedKey = this.setting.data.key.checked;\r\n\t\t\tif (node.chkDisabled === true) return;\r\n\t\t\tif (checked !== true && checked !== false) {\r\n\t\t\t\tchecked = !node[checkedKey];\r\n\t\t\t}\r\n\t\t\tcallbackFlag = !!callbackFlag;\r\n\t\t\t\r\n\t\t\tif (node[checkedKey] === checked && !checkTypeFlag) {\r\n\t\t\t\treturn;\r\n\t\t\t} else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) {\r\n\t\t\t\tnode[checkedKey] = checked;\r\n\t\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\t\tif (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);\r\n\t\t\t\tview.setChkClass(this.setting, checkObj, node);\r\n\t\t\t\tview.repairParentChkClassWithSelf(this.setting, node);\r\n\t\t\t\tif (callbackFlag) {\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tzTreeTools.checkAllNodes = function(checked) {\r\n\t\t\tview.repairAllChk(this.setting, !!checked);\r\n\t\t}\r\n\r\n\t\tzTreeTools.getCheckedNodes = function(checked) {\r\n\t\t\tvar childKey = this.setting.data.key.children;\r\n\t\t\tchecked = (checked !== false);\r\n\t\t\treturn data.getTreeCheckedNodes(this.setting, data.getRoot(setting)[childKey], checked);\r\n\t\t}\r\n\r\n\t\tzTreeTools.getChangeCheckedNodes = function() {\r\n\t\t\tvar childKey = this.setting.data.key.children;\r\n\t\t\treturn data.getTreeChangeCheckedNodes(this.setting, data.getRoot(setting)[childKey]);\r\n\t\t}\r\n\r\n\t\tzTreeTools.setChkDisabled = function(node, disabled, inheritParent, inheritChildren) {\r\n\t\t\tdisabled = !!disabled;\r\n\t\t\tinheritParent = !!inheritParent;\r\n\t\t\tinheritChildren = !!inheritChildren;\r\n\t\t\tview.repairSonChkDisabled(this.setting, node, disabled, inheritChildren);\r\n\t\t\tview.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent);\r\n\t\t}\r\n\r\n\t\tvar _updateNode = zTreeTools.updateNode;\r\n\t\tzTreeTools.updateNode = function(node, checkTypeFlag) {\r\n\t\t\tif (_updateNode) _updateNode.apply(zTreeTools, arguments);\r\n\t\t\tif (!node || !this.setting.check.enable) return;\r\n\t\t\tvar nObj = $(\"#\" + node.tId);\r\n\t\t\tif (nObj.get(0) && tools.uCanDo(this.setting)) {\r\n\t\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\t\tif (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);\r\n\t\t\t\tview.setChkClass(this.setting, checkObj, node);\r\n\t\t\t\tview.repairParentChkClassWithSelf(this.setting, node);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate data\r\n\t_data = {\r\n\t\tgetRadioCheckedList: function(setting) {\r\n\t\t\tvar checkedList = data.getRoot(setting).radioCheckedList;\r\n\t\t\tfor (var i=0, j=checkedList.length; i<j; i++) {\r\n\t\t\t\tif(!data.getNodeCache(setting, checkedList[i].tId)) {\r\n\t\t\t\t\tcheckedList.splice(i, 1);\r\n\t\t\t\t\ti--; j--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn checkedList;\r\n\t\t},\r\n\t\tgetCheckStatus: function(setting, node) {\r\n\t\t\tif (!setting.check.enable || node.nocheck || node.chkDisabled) return null;\r\n\t\t\tvar checkedKey = setting.data.key.checked,\r\n\t\t\tr = {\r\n\t\t\t\tchecked: node[checkedKey],\r\n\t\t\t\thalf: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (node[checkedKey] ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0)))\r\n\t\t\t};\r\n\t\t\treturn r;\r\n\t\t},\r\n\t\tgetTreeCheckedNodes: function(setting, nodes, checked, results) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tonlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL);\r\n\t\t\tresults = !results ? [] : results;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] == checked) {\r\n\t\t\t\t\tresults.push(nodes[i]);\r\n\t\t\t\t\tif(onlyOne) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tdata.getTreeCheckedNodes(setting, nodes[i][childKey], checked, results);\r\n\t\t\t\tif(onlyOne && results.length > 0) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn results;\r\n\t\t},\r\n\t\tgetTreeChangeCheckedNodes: function(setting, nodes, results) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked;\r\n\t\t\tresults = !results ? [] : results;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] != nodes[i].checkedOld) {\r\n\t\t\t\t\tresults.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tdata.getTreeChangeCheckedNodes(setting, nodes[i][childKey], results);\r\n\t\t\t}\r\n\t\t\treturn results;\r\n\t\t},\r\n\t\tmakeChkFlag: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tchkFlag = -1;\r\n\t\t\tif (node[childKey]) {\r\n\t\t\t\tfor (var i = 0, l = node[childKey].length; i < l; i++) {\r\n\t\t\t\t\tvar cNode = node[childKey][i];\r\n\t\t\t\t\tvar tmp = -1;\r\n\t\t\t\t\tif (setting.check.chkStyle == consts.radio.STYLE) {\r\n\t\t\t\t\t\tif (cNode.nocheck === true || cNode.chkDisabled === true) {\r\n\t\t\t\t\t\t\ttmp = cNode.check_Child_State;\r\n\t\t\t\t\t\t} else if (cNode.halfCheck === true) {\r\n\t\t\t\t\t\t\ttmp = 2;\r\n\t\t\t\t\t\t} else if (cNode[checkedKey]) {\r\n\t\t\t\t\t\t\ttmp = 2;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttmp = cNode.check_Child_State > 0 ? 2:0;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (tmp == 2) {\r\n\t\t\t\t\t\t\tchkFlag = 2; break;\r\n\t\t\t\t\t\t} else if (tmp == 0){\r\n\t\t\t\t\t\t\tchkFlag = 0;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (setting.check.chkStyle == consts.checkbox.STYLE) {\r\n\t\t\t\t\t\tif (cNode.nocheck === true || cNode.chkDisabled === true) {\r\n\t\t\t\t\t\t\ttmp = cNode.check_Child_State;\r\n\t\t\t\t\t\t} else if (cNode.halfCheck === true) {\r\n\t\t\t\t\t\t\ttmp = 1;\r\n\t\t\t\t\t\t} else if (cNode[checkedKey] ) {\r\n\t\t\t\t\t\t\ttmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttmp = (cNode.check_Child_State > 0) ? 1 : 0;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (tmp === 1) {\r\n\t\t\t\t\t\t\tchkFlag = 1; break;\r\n\t\t\t\t\t\t} else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) {\r\n\t\t\t\t\t\t\tchkFlag = 1; break;\r\n\t\t\t\t\t\t} else if (chkFlag === 2 && tmp > -1 && tmp < 2) {\r\n\t\t\t\t\t\t\tchkFlag = 1; break;\r\n\t\t\t\t\t\t} else if (tmp > -1) {\r\n\t\t\t\t\t\t\tchkFlag = tmp;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tnode.check_Child_State = chkFlag;\r\n\t\t}\r\n\t},\r\n\t//method of event proxy\r\n\t_event = {\r\n\r\n\t},\r\n\t//method of event handler\r\n\t_handler = {\r\n\t\tonCheckNode: function (event, node) {\r\n\t\t\tif (node.chkDisabled === true) return false;\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tcheckedKey = setting.data.key.checked;\r\n\t\t\tif (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true;\r\n\t\t\tnode[checkedKey] = !node[checkedKey];\r\n\t\t\tview.checkNodeRelation(setting, node);\r\n\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\tview.repairParentChkClassWithSelf(setting, node);\r\n\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]);\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonMouseoverCheck: function(event, node) {\r\n\t\t\tif (node.chkDisabled === true) return false;\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tnode.check_Focus = true;\r\n\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonMouseoutCheck: function(event, node) {\r\n\t\t\tif (node.chkDisabled === true) return false;\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tnode.check_Focus = false;\r\n\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t},\r\n\t//method of tools for zTree\r\n\t_tools = {\r\n\r\n\t},\r\n\t//method of operate ztree dom\r\n\t_view = {\r\n\t\tcheckNodeRelation: function(setting, node) {\r\n\t\t\tvar pNode, i, l,\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tr = consts.radio;\r\n\t\t\tif (setting.check.chkStyle == r.STYLE) {\r\n\t\t\t\tvar checkedList = data.getRadioCheckedList(setting);\r\n\t\t\t\tif (node[checkedKey]) {\r\n\t\t\t\t\tif (setting.check.radioType == r.TYPE_ALL) {\r\n\t\t\t\t\t\tfor (i = checkedList.length-1; i >= 0; i--) {\r\n\t\t\t\t\t\t\tpNode = checkedList[i];\r\n\t\t\t\t\t\t\tpNode[checkedKey] = false;\r\n\t\t\t\t\t\t\tcheckedList.splice(i, 1);\r\n\r\n\t\t\t\t\t\t\tview.setChkClass(setting, $(\"#\" + pNode.tId + consts.id.CHECK), pNode);\r\n\t\t\t\t\t\t\tif (pNode.parentTId != node.parentTId) {\r\n\t\t\t\t\t\t\t\tview.repairParentChkClassWithSelf(setting, pNode);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcheckedList.push(node);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tvar parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);\r\n\t\t\t\t\t\tfor (i = 0, l = parentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\t\t\tpNode = parentNode[childKey][i];\r\n\t\t\t\t\t\t\tif (pNode[checkedKey] && pNode != node) {\r\n\t\t\t\t\t\t\t\tpNode[checkedKey] = false;\r\n\t\t\t\t\t\t\t\tview.setChkClass(setting, $(\"#\" + pNode.tId + consts.id.CHECK), pNode);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (setting.check.radioType == r.TYPE_ALL) {\r\n\t\t\t\t\tfor (i = 0, l = checkedList.length; i < l; i++) {\r\n\t\t\t\t\t\tif (node == checkedList[i]) {\r\n\t\t\t\t\t\t\tcheckedList.splice(i, 1);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.Y.indexOf(\"s\") > -1)) {\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, node, true);\r\n\t\t\t\t}\r\n\t\t\t\tif (!node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.N.indexOf(\"s\") > -1)) {\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, node, false);\r\n\t\t\t\t}\r\n\t\t\t\tif (node[checkedKey] && setting.check.chkboxType.Y.indexOf(\"p\") > -1) {\r\n\t\t\t\t\tview.setParentNodeCheckBox(setting, node, true);\r\n\t\t\t\t}\r\n\t\t\t\tif (!node[checkedKey] && setting.check.chkboxType.N.indexOf(\"p\") > -1) {\r\n\t\t\t\t\tview.setParentNodeCheckBox(setting, node, false);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tmakeChkClass: function(setting, node) {\r\n\t\t\tvar checkedKey = setting.data.key.checked,\r\n\t\t\tc = consts.checkbox, r = consts.radio,\r\n\t\t\tfullStyle = \"\";\r\n\t\t\tif (node.chkDisabled === true) {\r\n\t\t\t\tfullStyle = c.DISABLED;\r\n\t\t\t} else if (node.halfCheck) {\r\n\t\t\t\tfullStyle = c.PART;\r\n\t\t\t} else if (setting.check.chkStyle == r.STYLE) {\r\n\t\t\t\tfullStyle = (node.check_Child_State < 1)? c.FULL:c.PART;\r\n\t\t\t} else {\r\n\t\t\t\tfullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART);\r\n\t\t\t}\r\n\t\t\tvar chkName = setting.check.chkStyle + \"_\" + (node[checkedKey] ? c.TRUE : c.FALSE) + \"_\" + fullStyle;\r\n\t\t\tchkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + \"_\" + c.FOCUS : chkName;\r\n\t\t\treturn consts.className.BUTTON + \" \" + c.DEFAULT + \" \" + chkName;\r\n\t\t},\r\n\t\trepairAllChk: function(setting, checked) {\r\n\t\t\tif (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) {\r\n\t\t\t\tvar checkedKey = setting.data.key.checked,\r\n\t\t\t\tchildKey = setting.data.key.children,\r\n\t\t\t\troot = data.getRoot(setting);\r\n\t\t\t\tfor (var i = 0, l = root[childKey].length; i<l ; i++) {\r\n\t\t\t\t\tvar node = root[childKey][i];\r\n\t\t\t\t\tif (node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\t\t\tnode[checkedKey] = checked;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, node, checked);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairChkClass: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\tif (node.nocheck !== true) {\r\n\t\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairParentChkClass: function(setting, node) {\r\n\t\t\tif (!node || !node.parentTId) return;\r\n\t\t\tvar pNode = node.getParentNode();\r\n\t\t\tview.repairChkClass(setting, pNode);\r\n\t\t\tview.repairParentChkClass(setting, pNode);\r\n\t\t},\r\n\t\trepairParentChkClassWithSelf: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (node[childKey] && node[childKey].length > 0) {\r\n\t\t\t\tview.repairParentChkClass(setting, node[childKey][0]);\r\n\t\t\t} else {\r\n\t\t\t\tview.repairParentChkClass(setting, node);\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairSonChkDisabled: function(setting, node, chkDisabled, inherit) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (node.chkDisabled != chkDisabled) {\r\n\t\t\t\tnode.chkDisabled = chkDisabled;\r\n\t\t\t}\r\n\t\t\tview.repairChkClass(setting, node);\r\n\t\t\tif (node[childKey] && inherit) {\r\n\t\t\t\tfor (var i = 0, l = node[childKey].length; i < l; i++) {\r\n\t\t\t\t\tvar sNode = node[childKey][i];\r\n\t\t\t\t\tview.repairSonChkDisabled(setting, sNode, chkDisabled, inherit);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairParentChkDisabled: function(setting, node, chkDisabled, inherit) {\r\n\t\t\tif (!node) return;\r\n\t\t\tif (node.chkDisabled != chkDisabled && inherit) {\r\n\t\t\t\tnode.chkDisabled = chkDisabled;\r\n\t\t\t}\r\n\t\t\tview.repairChkClass(setting, node);\r\n\t\t\tview.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit);\r\n\t\t},\r\n\t\tsetChkClass: function(setting, obj, node) {\r\n\t\t\tif (!obj) return;\r\n\t\t\tif (node.nocheck === true) {\r\n\t\t\t\tobj.hide();\r\n\t\t\t} else {\r\n\t\t\t\tobj.show();\r\n\t\t\t}\r\n\t\t\tobj.removeClass();\r\n\t\t\tobj.addClass(view.makeChkClass(setting, node));\r\n\t\t},\r\n\t\tsetParentNodeCheckBox: function(setting, node, value, srcNode) {\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tif (!srcNode) srcNode = node;\r\n\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\tif (node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\tnode[checkedKey] = value;\r\n\t\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\t\tif (setting.check.autoCheckTrigger && node != srcNode) {\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (node.parentTId) {\r\n\t\t\t\tvar pSign = true;\r\n\t\t\t\tif (!value) {\r\n\t\t\t\t\tvar pNodes = node.getParentNode()[childKey];\r\n\t\t\t\t\tfor (var i = 0, l = pNodes.length; i < l; i++) {\r\n\t\t\t\t\t\tif ((pNodes[i].nocheck !== true && pNodes[i].chkDisabled !== true && pNodes[i][checkedKey])\r\n\t\t\t\t\t\t|| ((pNodes[i].nocheck === true || pNodes[i].chkDisabled === true) && pNodes[i].check_Child_State > 0)) {\r\n\t\t\t\t\t\t\tpSign = false;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (pSign) {\r\n\t\t\t\t\tview.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetSonNodeCheckBox: function(setting, node, value, srcNode) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tif (!srcNode) srcNode = node;\r\n\r\n\t\t\tvar hasDisable = false;\r\n\t\t\tif (node[childKey]) {\r\n\t\t\t\tfor (var i = 0, l = node[childKey].length; i < l && node.chkDisabled !== true; i++) {\r\n\t\t\t\t\tvar sNode = node[childKey][i];\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, sNode, value, srcNode);\r\n\t\t\t\t\tif (sNode.chkDisabled === true) hasDisable = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (node != data.getRoot(setting) && node.chkDisabled !== true) {\r\n\t\t\t\tif (hasDisable && node.nocheck !== true) {\r\n\t\t\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\t\t}\r\n\t\t\t\tif (node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\t\tnode[checkedKey] = value;\r\n\t\t\t\t\tif (!hasDisable) node.check_Child_State = (node[childKey] && node[childKey].length > 0) ? (value ? 2 : 0) : -1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnode.check_Child_State = -1;\r\n\t\t\t\t}\r\n\t\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\t\tif (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t}\r\n\t},\r\n\r\n\t_z = {\r\n\t\ttools: _tools,\r\n\t\tview: _view,\r\n\t\tevent: _event,\r\n\t\tdata: _data\r\n\t};\r\n\t$.extend(true, $.fn.zTree.consts, _consts);\r\n\t$.extend(true, $.fn.zTree._z, _z);\r\n\r\n\tvar zt = $.fn.zTree,\r\n\ttools = zt._z.tools,\r\n\tconsts = zt.consts,\r\n\tview = zt._z.view,\r\n\tdata = zt._z.data,\r\n\tevent = zt._z.event;\r\n\r\n\tdata.exSetting(_setting);\r\n\tdata.addInitBind(_bindEvent);\r\n\tdata.addInitUnBind(_unbindEvent);\r\n\tdata.addInitCache(_initCache);\r\n\tdata.addInitNode(_initNode);\r\n\tdata.addInitProxy(_eventProxy);\r\n\tdata.addInitRoot(_initRoot);\r\n\tdata.addBeforeA(_beforeA);\r\n\tdata.addZTreeTools(_zTreeTools);\r\n\r\n\tvar _createNodes = view.createNodes;\r\n\tview.createNodes = function(setting, level, nodes, parentNode) {\r\n\t\tif (_createNodes) _createNodes.apply(view, arguments);\r\n\t\tif (!nodes) return;\r\n\t\tview.repairParentChkClassWithSelf(setting, parentNode);\r\n\t}\r\n\tvar _removeNode = view.removeNode;\r\n\tview.removeNode = function(setting, node) {\r\n\t\tvar parentNode = node.getParentNode();\r\n\t\tif (_removeNode) _removeNode.apply(view, arguments);\r\n\t\tif (!node || !parentNode) return;\r\n\t\tview.repairChkClass(setting, parentNode);\r\n\t\tview.repairParentChkClass(setting, parentNode);\r\n\t}\r\n\r\n\tvar _appendNodes = view.appendNodes;\r\n\tview.appendNodes = function(setting, level, nodes, parentNode, initFlag, openFlag) {\r\n\t\tvar html = \"\";\r\n\t\tif (_appendNodes) {\r\n\t\t\thtml = _appendNodes.apply(view, arguments);\r\n\t\t}\r\n\t\tif (parentNode) {\r\n\t\t\tdata.makeChkFlag(setting, parentNode);\r\n\t\t}\r\n\t\treturn html;\r\n\t}\r\n})(jQuery);\r\n/*\r\n * JQuery zTree exedit 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\t//default consts of exedit\r\n\tvar _consts = {\r\n\t\tevent: {\r\n\t\t\tDRAG: \"ztree_drag\",\r\n\t\t\tDROP: \"ztree_drop\",\r\n\t\t\tREMOVE: \"ztree_remove\",\r\n\t\t\tRENAME: \"ztree_rename\"\r\n\t\t},\r\n\t\tid: {\r\n\t\t\tEDIT: \"_edit\",\r\n\t\t\tINPUT: \"_input\",\r\n\t\t\tREMOVE: \"_remove\"\r\n\t\t},\r\n\t\tmove: {\r\n\t\t\tTYPE_INNER: \"inner\",\r\n\t\t\tTYPE_PREV: \"prev\",\r\n\t\t\tTYPE_NEXT: \"next\"\r\n\t\t},\r\n\t\tnode: {\r\n\t\t\tCURSELECTED_EDIT: \"curSelectedNode_Edit\",\r\n\t\t\tTMPTARGET_TREE: \"tmpTargetzTree\",\r\n\t\t\tTMPTARGET_NODE: \"tmpTargetNode\"\r\n\t\t}\r\n\t},\r\n\t//default setting of exedit\r\n\t_setting = {\r\n\t\tedit: {\r\n\t\t\tenable: false,\r\n\t\t\teditNameSelectAll: false,\r\n\t\t\tshowRemoveBtn: true,\r\n\t\t\tshowRenameBtn: true,\r\n\t\t\tremoveTitle: \"remove\",\r\n\t\t\trenameTitle: \"rename\",\r\n\t\t\tdrag: {\r\n\t\t\t\tautoExpandTrigger: false,\r\n\t\t\t\tisCopy: true,\r\n\t\t\t\tisMove: true,\r\n\t\t\t\tprev: true,\r\n\t\t\t\tnext: true,\r\n\t\t\t\tinner: true,\r\n\t\t\t\tminMoveSize: 5,\r\n\t\t\t\tborderMax: 10,\r\n\t\t\t\tborderMin: -5,\r\n\t\t\t\tmaxShowNodeNum: 5,\r\n\t\t\t\tautoOpenTime: 500\r\n\t\t\t}\r\n\t\t},\r\n\t\tview: {\r\n\t\t\taddHoverDom: null,\r\n\t\t\tremoveHoverDom: null\r\n\t\t},\r\n\t\tcallback: {\r\n\t\t\tbeforeDrag:null,\r\n\t\t\tbeforeDragOpen:null,\r\n\t\t\tbeforeDrop:null,\r\n\t\t\tbeforeEditName:null,\r\n\t\t\tbeforeRename:null,\r\n\t\t\tonDrag:null,\r\n\t\t\tonDrop:null,\r\n\t\t\tonRename:null\r\n\t\t}\r\n\t},\r\n\t//default root of exedit\r\n\t_initRoot = function (setting) {\r\n\t\tvar r = data.getRoot(setting);\r\n\t\tr.curEditNode = null;\r\n\t\tr.curEditInput = null;\r\n\t\tr.curHoverNode = null;\r\n\t\tr.dragFlag = 0;\r\n\t\tr.dragNodeShowBefore = [];\r\n\t\tr.dragMaskList = new Array();\r\n\t\tr.showHoverDom = true;\r\n\t},\r\n\t//default cache of exedit\r\n\t_initCache = function(treeId) {},\r\n\t//default bind event of exedit\r\n\t_bindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj;\r\n\t\tvar c = consts.event;\r\n\t\to.bind(c.RENAME, function (event, treeId, treeNode) {\r\n\t\t\ttools.apply(setting.callback.onRename, [event, treeId, treeNode]);\r\n\t\t});\r\n\r\n\t\to.bind(c.REMOVE, function (event, treeId, treeNode) {\r\n\t\t\ttools.apply(setting.callback.onRemove, [event, treeId, treeNode]);\r\n\t\t});\r\n\r\n\t\to.bind(c.DRAG, function (event, srcEvent, treeId, treeNodes) {\r\n\t\t\ttools.apply(setting.callback.onDrag, [srcEvent, treeId, treeNodes]);\r\n\t\t});\r\n\r\n\t\to.bind(c.DROP, function (event, srcEvent, treeId, treeNodes, targetNode, moveType, isCopy) {\r\n\t\t\ttools.apply(setting.callback.onDrop, [srcEvent, treeId, treeNodes, targetNode, moveType, isCopy]);\r\n\t\t});\r\n\t},\r\n\t_unbindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj;\r\n\t\tvar c = consts.event;\r\n\t\to.unbind(c.RENAME);\r\n\t\to.unbind(c.REMOVE);\r\n\t\to.unbind(c.DRAG);\r\n\t\to.unbind(c.DROP);\r\n\t},\r\n\t//default event proxy of exedit\r\n\t_eventProxy = function(e) {\r\n\t\tvar target = e.target,\r\n\t\tsetting = data.getSetting(e.data.treeId),\r\n\t\trelatedTarget = e.relatedTarget,\r\n\t\ttId = \"\", node = null,\r\n\t\tnodeEventType = \"\", treeEventType = \"\",\r\n\t\tnodeEventCallback = null, treeEventCallback = null,\r\n\t\ttmp = null;\r\n\r\n\t\tif (tools.eqs(e.type, \"mouseover\")) {\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {\r\n\t\t\t\ttId = tmp.parentNode.id;\r\n\t\t\t\tnodeEventType = \"hoverOverNode\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"mouseout\")) {\r\n\t\t\ttmp = tools.getMDom(setting, relatedTarget, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (!tmp) {\r\n\t\t\t\ttId = \"remove\";\r\n\t\t\t\tnodeEventType = \"hoverOutNode\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"mousedown\")) {\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {\r\n\t\t\t\ttId = tmp.parentNode.id;\r\n\t\t\t\tnodeEventType = \"mousedownNode\";\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (tId.length>0) {\r\n\t\t\tnode = data.getNodeCache(setting, tId);\r\n\t\t\tswitch (nodeEventType) {\r\n\t\t\t\tcase \"mousedownNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onMousedownNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"hoverOverNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onHoverOverNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"hoverOutNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onHoverOutNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tvar proxyResult = {\r\n\t\t\tstop: false,\r\n\t\t\tnode: node,\r\n\t\t\tnodeEventType: nodeEventType,\r\n\t\t\tnodeEventCallback: nodeEventCallback,\r\n\t\t\ttreeEventType: treeEventType,\r\n\t\t\ttreeEventCallback: treeEventCallback\r\n\t\t};\r\n\t\treturn proxyResult\r\n\t},\r\n\t//default init node of exedit\r\n\t_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (!n) return;\r\n\t\tn.isHover = false;\r\n\t\tn.editNameFlag = false;\r\n\t},\r\n\t//update zTreeObj, add method of edit\r\n\t_zTreeTools = function(setting, zTreeTools) {\r\n\t\tzTreeTools.cancelEditName = function(newName) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tnameKey = setting.data.key.name,\r\n\t\t\tnode = root.curEditNode;\r\n\t\t\tif (!root.curEditNode) return;\r\n\t\t\tview.cancelCurEditNode(setting, newName?newName:node[nameKey]);\r\n\t\t}\r\n\t\tzTreeTools.copyNode = function(targetNode, node, moveType, isSilent) {\r\n\t\t\tif (!node) return null;\r\n\t\t\tif (targetNode && !targetNode.isParent && setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) return null;\r\n\t\t\tvar newNode = tools.clone(node);\r\n\t\t\tif (!targetNode) {\r\n\t\t\t\ttargetNode = null;\r\n\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t}\r\n\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\tfunction copyCallback() {\r\n\t\t\t\t\tview.addNodes(setting, targetNode, [newNode], isSilent);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (tools.canAsync(setting, targetNode)) {\r\n\t\t\t\t\tview.asyncNode(setting, targetNode, isSilent, copyCallback);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcopyCallback();\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tview.addNodes(setting, targetNode.parentNode, [newNode], isSilent);\r\n\t\t\t\tview.moveNode(setting, targetNode, newNode, moveType, false, isSilent);\r\n\t\t\t}\r\n\t\t\treturn newNode;\r\n\t\t}\r\n\t\tzTreeTools.editName = function(node) {\r\n\t\t\tif (!node || !node.tId || node !== data.getNodeCache(setting, node.tId)) return;\r\n\t\t\tif (node.parentTId) view.expandCollapseParentNode(setting, node.getParentNode(), true);\r\n\t\t\tview.editNode(setting, node)\r\n\t\t}\r\n\t\tzTreeTools.moveNode = function(targetNode, node, moveType, isSilent) {\r\n\t\t\tif (!node) return node;\r\n\t\t\tif (targetNode && !targetNode.isParent && setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) {\r\n\t\t\t\treturn null;\r\n\t\t\t} else if (targetNode && ((node.parentTId == targetNode.tId && moveType == consts.move.TYPE_INNER) || $(\"#\" + node.tId).find(\"#\" + targetNode.tId).length > 0)) {\r\n\t\t\t\treturn null;\r\n\t\t\t} else if (!targetNode) {\r\n\t\t\t\ttargetNode = null;\r\n\t\t\t}\r\n\t\t\tfunction moveCallback() {\r\n\t\t\t\tview.moveNode(setting, targetNode, node, moveType, false, isSilent);\r\n\t\t\t}\r\n\t\t\tif (tools.canAsync(setting, targetNode) && moveType === consts.move.TYPE_INNER) {\r\n\t\t\t\tview.asyncNode(setting, targetNode, isSilent, moveCallback);\r\n\t\t\t} else {\r\n\t\t\t\tmoveCallback();\r\n\t\t\t}\r\n\t\t\treturn node;\r\n\t\t}\r\n\t\tzTreeTools.setEditable = function(editable) {\r\n\t\t\tsetting.edit.enable = editable;\r\n\t\t\treturn this.refresh();\r\n\t\t}\r\n\t},\r\n\t//method of operate data\r\n\t_data = {\r\n\t\tsetSonNodeLevel: function(setting, parentNode, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tnode.level = (parentNode)? parentNode.level + 1 : 0;\r\n\t\t\tif (!node[childKey]) return;\r\n\t\t\tfor (var i = 0, l = node[childKey].length; i < l; i++) {\r\n\t\t\t\tif (node[childKey][i]) data.setSonNodeLevel(setting, node, node[childKey][i]);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of event proxy\r\n\t_event = {\r\n\r\n\t},\r\n\t//method of event handler\r\n\t_handler = {\r\n\t\tonHoverOverNode: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\troot = data.getRoot(setting);\r\n\t\t\tif (root.curHoverNode != node) {\r\n\t\t\t\t_handler.onHoverOutNode(event);\r\n\t\t\t}\r\n\t\t\troot.curHoverNode = node;\r\n\t\t\tview.addHoverDom(setting, node);\r\n\t\t},\r\n\t\tonHoverOutNode: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\troot = data.getRoot(setting);\r\n\t\t\tif (root.curHoverNode && !data.isSelectedNode(setting, root.curHoverNode)) {\r\n\t\t\t\tview.removeTreeDom(setting, root.curHoverNode);\r\n\t\t\t\troot.curHoverNode = null;\r\n\t\t\t}\r\n\t\t},\r\n\t\tonMousedownNode: function(eventMouseDown, _node) {\r\n\t\t\tvar i,l,\r\n\t\t\tsetting = data.getSetting(eventMouseDown.data.treeId),\r\n\t\t\troot = data.getRoot(setting);\r\n\t\t\t//right click can't drag & drop\r\n\t\t\tif (eventMouseDown.button == 2 || !setting.edit.enable || (!setting.edit.drag.isCopy && !setting.edit.drag.isMove)) return true;\r\n\r\n\t\t\t//input of edit node name can't drag & drop\r\n\t\t\tvar target = eventMouseDown.target,\r\n\t\t\t_nodes = data.getRoot(setting).curSelectedList,\r\n\t\t\tnodes = [];\r\n\t\t\tif (!data.isSelectedNode(setting, _node)) {\r\n\t\t\t\tnodes = [_node];\r\n\t\t\t} else {\r\n\t\t\t\tfor (i=0, l=_nodes.length; i<l; i++) {\r\n\t\t\t\t\tif (_nodes[i].editNameFlag && tools.eqs(target.tagName, \"input\") && target.getAttribute(\"treeNode\"+consts.id.INPUT) !== null) {\r\n\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tnodes.push(_nodes[i]);\r\n\t\t\t\t\tif (nodes[0].parentTId !== _nodes[i].parentTId) {\r\n\t\t\t\t\t\tnodes = [_node];\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tview.editNodeBlur = true;\r\n\t\t\tview.cancelCurEditNode(setting, null, true);\r\n\t\t\t\r\n\r\n\t\t\tvar doc = $(document), curNode, tmpArrow, tmpTarget,\r\n\t\t\tisOtherTree = false,\r\n\t\t\ttargetSetting = setting,\r\n\t\t\tpreNode, nextNode,\r\n\t\t\tpreTmpTargetNodeId = null,\r\n\t\t\tpreTmpMoveType = null,\r\n\t\t\ttmpTargetNodeId = null,\r\n\t\t\tmoveType = consts.move.TYPE_INNER,\r\n\t\t\tmouseDownX = eventMouseDown.clientX,\r\n\t\t\tmouseDownY = eventMouseDown.clientY,\r\n\t\t\tstartTime = (new Date()).getTime();\r\n\r\n\t\t\tif (tools.uCanDo(setting)) {\r\n\t\t\t\tdoc.bind(\"mousemove\", _docMouseMove);\r\n\t\t\t}\r\n\t\t\tfunction _docMouseMove(event) {\r\n\t\t\t\t//avoid start drag after click node\r\n\t\t\t\tif (root.dragFlag == 0 && Math.abs(mouseDownX - event.clientX) < setting.edit.drag.minMoveSize\r\n\t\t\t\t\t&& Math.abs(mouseDownY - event.clientY) < setting.edit.drag.minMoveSize) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t\tvar i, l, tmpNode, tmpDom, tmpNodes,\r\n\t\t\t\tchildKey = setting.data.key.children;\r\n\t\t\t\t$(\"body\").css(\"cursor\", \"pointer\");\r\n\r\n\t\t\t\tif (root.dragFlag == 0) {\r\n\t\t\t\t\tif (tools.apply(setting.callback.beforeDrag, [setting.treeId, nodes], true) == false) {\r\n\t\t\t\t\t\t_docMouseUp(event);\r\n\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\tif (i==0) {\r\n\t\t\t\t\t\t\troot.dragNodeShowBefore = [];\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\t\tif (tmpNode.isParent && tmpNode.open) {\r\n\t\t\t\t\t\t\tview.expandCollapseNode(setting, tmpNode, !tmpNode.open);\r\n\t\t\t\t\t\t\troot.dragNodeShowBefore[tmpNode.tId] = true;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\troot.dragNodeShowBefore[tmpNode.tId] = false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\troot.dragFlag = 1;\r\n\t\t\t\t\troot.showHoverDom = false;\r\n\t\t\t\t\ttools.showIfameMask(setting, true);\r\n\r\n\t\t\t\t\t//sort\r\n\t\t\t\t\tvar isOrder = true, lastIndex = -1;\r\n\t\t\t\t\tif (nodes.length>1) {\r\n\t\t\t\t\t\tvar pNodes = nodes[0].parentTId ? nodes[0].getParentNode()[childKey] : data.getNodes(setting);\r\n\t\t\t\t\t\ttmpNodes = [];\r\n\t\t\t\t\t\tfor (i=0, l=pNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\tif (root.dragNodeShowBefore[pNodes[i].tId] !== undefined) {\r\n\t\t\t\t\t\t\t\tif (isOrder && lastIndex > -1 && (lastIndex+1) !== i) {\r\n\t\t\t\t\t\t\t\t\tisOrder = false;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\ttmpNodes.push(pNodes[i]);\r\n\t\t\t\t\t\t\t\tlastIndex = i;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (nodes.length === tmpNodes.length) {\r\n\t\t\t\t\t\t\t\tnodes = tmpNodes;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (isOrder) {\r\n\t\t\t\t\t\tpreNode = nodes[0].getPreNode();\r\n\t\t\t\t\t\tnextNode = nodes[nodes.length-1].getNextNode();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t//set node in selected\r\n\t\t\t\t\tcurNode = $(\"<ul class='zTreeDragUL'></ul>\");\r\n\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\t\ttmpNode.editNameFlag = false;\r\n\t\t\t\t\t\tview.selectNode(setting, tmpNode, i>0);\r\n\t\t\t\t\t\tview.removeTreeDom(setting, tmpNode);\r\n\r\n\t\t\t\t\t\ttmpDom = $(\"<li id='\"+ tmpNode.tId +\"_tmp'></li>\");\r\n\t\t\t\t\t\ttmpDom.append($(\"#\" + tmpNode.tId + consts.id.A).clone());\r\n\t\t\t\t\t\ttmpDom.css(\"padding\", \"0\");\r\n\t\t\t\t\t\ttmpDom.children(\"#\" + tmpNode.tId + consts.id.A).removeClass(consts.node.CURSELECTED);\r\n\t\t\t\t\t\tcurNode.append(tmpDom);\r\n\t\t\t\t\t\tif (i == setting.edit.drag.maxShowNodeNum-1) {\r\n\t\t\t\t\t\t\ttmpDom = $(\"<li id='\"+ tmpNode.tId +\"_moretmp'><a>  ...  </a></li>\");\r\n\t\t\t\t\t\t\tcurNode.append(tmpDom);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcurNode.attr(\"id\", nodes[0].tId + consts.id.UL + \"_tmp\");\r\n\t\t\t\t\tcurNode.addClass(setting.treeObj.attr(\"class\"));\r\n\t\t\t\t\tcurNode.appendTo(\"body\");\r\n\r\n\t\t\t\t\ttmpArrow = $(\"<span class='tmpzTreeMove_arrow'></span>\");\r\n\t\t\t\t\ttmpArrow.attr(\"id\", \"zTreeMove_arrow_tmp\");\r\n\t\t\t\t\ttmpArrow.appendTo(\"body\");\r\n\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.DRAG, [event, setting.treeId, nodes]);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (root.dragFlag == 1) {\r\n\t\t\t\t\tif (tmpTarget && tmpArrow.attr(\"id\") == event.target.id && tmpTargetNodeId && (event.clientX + doc.scrollLeft()+2) > ($(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget).offset().left)) {\r\n\t\t\t\t\t\tvar xT = $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget);\r\n\t\t\t\t\t\tevent.target = (xT.length > 0) ? xT.get(0) : event.target;\r\n\t\t\t\t\t} else if (tmpTarget) {\r\n\t\t\t\t\t\ttmpTarget.removeClass(consts.node.TMPTARGET_TREE);\r\n\t\t\t\t\t\tif (tmpTargetNodeId) $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + \"_\" + consts.move.TYPE_PREV)\r\n\t\t\t\t\t\t\t.removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_INNER);\r\n\t\t\t\t\t}\r\n\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t\ttmpTargetNodeId = null;\r\n\r\n\t\t\t\t\t//judge drag & drop in multi ztree\r\n\t\t\t\t\tisOtherTree = false;\r\n\t\t\t\t\ttargetSetting = setting;\r\n\t\t\t\t\tvar settings = data.getSettings();\r\n\t\t\t\t\tfor (var s in settings) {\r\n\t\t\t\t\t\tif (settings[s].treeId && settings[s].edit.enable && settings[s].treeId != setting.treeId\r\n\t\t\t\t\t\t\t&& (event.target.id == settings[s].treeId || $(event.target).parents(\"#\" + settings[s].treeId).length>0)) {\r\n\t\t\t\t\t\t\tisOtherTree = true;\r\n\t\t\t\t\t\t\ttargetSetting = settings[s];\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar docScrollTop = doc.scrollTop(),\r\n\t\t\t\t\tdocScrollLeft = doc.scrollLeft(),\r\n\t\t\t\t\ttreeOffset = targetSetting.treeObj.offset(),\r\n\t\t\t\t\tscrollHeight = targetSetting.treeObj.get(0).scrollHeight,\r\n\t\t\t\t\tscrollWidth = targetSetting.treeObj.get(0).scrollWidth,\r\n\t\t\t\t\tdTop = (event.clientY + docScrollTop - treeOffset.top),\r\n\t\t\t\t\tdBottom = (targetSetting.treeObj.height() + treeOffset.top - event.clientY - docScrollTop),\r\n\t\t\t\t\tdLeft = (event.clientX + docScrollLeft - treeOffset.left),\r\n\t\t\t\t\tdRight = (targetSetting.treeObj.width() + treeOffset.left - event.clientX - docScrollLeft),\r\n\t\t\t\t\tisTop = (dTop < setting.edit.drag.borderMax && dTop > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisBottom = (dBottom < setting.edit.drag.borderMax && dBottom > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisLeft = (dLeft < setting.edit.drag.borderMax && dLeft > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisRight = (dRight < setting.edit.drag.borderMax && dRight > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisTreeInner = dTop > setting.edit.drag.borderMin && dBottom > setting.edit.drag.borderMin && dLeft > setting.edit.drag.borderMin && dRight > setting.edit.drag.borderMin,\r\n\t\t\t\t\tisTreeTop = (isTop && targetSetting.treeObj.scrollTop() <= 0),\r\n\t\t\t\t\tisTreeBottom = (isBottom && (targetSetting.treeObj.scrollTop() + targetSetting.treeObj.height()+10) >= scrollHeight),\r\n\t\t\t\t\tisTreeLeft = (isLeft && targetSetting.treeObj.scrollLeft() <= 0),\r\n\t\t\t\t\tisTreeRight = (isRight && (targetSetting.treeObj.scrollLeft() + targetSetting.treeObj.width()+10) >= scrollWidth);\r\n\r\n\t\t\t\t\tif (event.target.id && targetSetting.treeObj.find(\"#\" + event.target.id).length > 0) {\r\n\t\t\t\t\t\t//get node <li> dom\r\n\t\t\t\t\t\tvar targetObj = event.target;\r\n\t\t\t\t\t\twhile (targetObj && targetObj.tagName && !tools.eqs(targetObj.tagName, \"li\") && targetObj.id != targetSetting.treeId) {\r\n\t\t\t\t\t\t\ttargetObj = targetObj.parentNode;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvar canMove = true;\r\n\t\t\t\t\t\t//don't move to self or children of self\r\n\t\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\t\t\tif (targetObj.id === tmpNode.tId) {\r\n\t\t\t\t\t\t\t\tcanMove = false;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t} else if ($(\"#\" + tmpNode.tId).find(\"#\" + targetObj.id).length > 0) {\r\n\t\t\t\t\t\t\t\tcanMove = false;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (canMove) {\r\n\t\t\t\t\t\t\tif (event.target.id &&\r\n\t\t\t\t\t\t\t\t(event.target.id == (targetObj.id + consts.id.A) || $(event.target).parents(\"#\" + targetObj.id + consts.id.A).length > 0)) {\r\n\t\t\t\t\t\t\t\ttmpTarget = $(targetObj);\r\n\t\t\t\t\t\t\t\ttmpTargetNodeId = targetObj.id;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t//the mouse must be in zTree\r\n\t\t\t\t\ttmpNode = nodes[0];\r\n\t\t\t\t\tif (isTreeInner && (event.target.id == targetSetting.treeId || $(event.target).parents(\"#\" + targetSetting.treeId).length>0)) {\r\n\t\t\t\t\t\t//judge mouse move in root of ztree\r\n\t\t\t\t\t\tif (!tmpTarget && (event.target.id == targetSetting.treeId || isTreeTop || isTreeBottom || isTreeLeft || isTreeRight) && (isOtherTree || (!isOtherTree && tmpNode.parentTId))) {\r\n\t\t\t\t\t\t\ttmpTarget = targetSetting.treeObj;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t//auto scroll top\r\n\t\t\t\t\t\tif (isTop) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop()-10);\r\n\t\t\t\t\t\t} else if (isBottom)  {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop()+10);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (isLeft) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft()-10);\r\n\t\t\t\t\t\t} else if (isRight) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft()+10);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t//auto scroll left\r\n\t\t\t\t\t\tif (tmpTarget && tmpTarget != targetSetting.treeObj && tmpTarget.offset().left < targetSetting.treeObj.offset().left) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft()+ tmpTarget.offset().left - targetSetting.treeObj.offset().left);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcurNode.css({\r\n\t\t\t\t\t\t\"top\": (event.clientY + docScrollTop + 3) + \"px\",\r\n\t\t\t\t\t\t\"left\": (event.clientX + docScrollLeft + 3) + \"px\"\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tvar dX = 0;\r\n\t\t\t\t\tvar dY = 0;\r\n\t\t\t\t\tif (tmpTarget && tmpTarget.attr(\"id\")!=targetSetting.treeId) {\r\n\t\t\t\t\t\tvar tmpTargetNode = tmpTargetNodeId == null ? null: data.getNodeCache(targetSetting, tmpTargetNodeId),\r\n\t\t\t\t\t\tisCopy = (event.ctrlKey && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy),\r\n\t\t\t\t\t\tisPrev = !!(preNode && tmpTargetNodeId === preNode.tId),\r\n\t\t\t\t\t\tisNext = !!(nextNode && tmpTargetNodeId === nextNode.tId),\r\n\t\t\t\t\t\tisInner = (tmpNode.parentTId && tmpNode.parentTId == tmpTargetNodeId),\r\n\t\t\t\t\t\tcanPrev = (isCopy || !isNext) && tools.apply(targetSetting.edit.drag.prev, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.prev),\r\n\t\t\t\t\t\tcanNext = (isCopy || !isPrev) && tools.apply(targetSetting.edit.drag.next, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.next),\r\n\t\t\t\t\t\tcanInner = (isCopy || !isInner) && !(targetSetting.data.keep.leaf && !tmpTargetNode.isParent) && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.inner);\r\n\t\t\t\t\t\tif (!canPrev && !canNext && !canInner) {\r\n\t\t\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t\t\t\ttmpTargetNodeId = \"\";\r\n\t\t\t\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t\t\t\t\ttmpArrow.css({\r\n\t\t\t\t\t\t\t\t\"display\":\"none\"\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\tif (window.zTreeMoveTimer) {\r\n\t\t\t\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tvar tmpTargetA = $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget),\r\n\t\t\t\t\t\t\ttmpNextA = tmpTargetNode.isLastNode ? null : $(\"#\" + tmpTargetNode.getNextNode().tId + consts.id.A, tmpTarget.next()),\r\n\t\t\t\t\t\t\ttmpTop = tmpTargetA.offset().top,\r\n\t\t\t\t\t\t\ttmpLeft = tmpTargetA.offset().left,\r\n\t\t\t\t\t\t\tprevPercent = canPrev ? (canInner ? 0.25 : (canNext ? 0.5 : 1) ) : -1,\r\n\t\t\t\t\t\t\tnextPercent = canNext ? (canInner ? 0.75 : (canPrev ? 0.5 : 0) ) : -1,\r\n\t\t\t\t\t\t\tdY_percent = (event.clientY + docScrollTop - tmpTop)/tmpTargetA.height();\r\n\t\t\t\t\t\t\tif ((prevPercent==1 ||dY_percent<=prevPercent && dY_percent>=-.2) && canPrev) {\r\n\t\t\t\t\t\t\t\tdX = 1 - tmpArrow.width();\r\n\t\t\t\t\t\t\t\tdY = tmpTop - tmpArrow.height()/2;\r\n\t\t\t\t\t\t\t\tmoveType = consts.move.TYPE_PREV;\r\n\t\t\t\t\t\t\t} else if ((nextPercent==0 || dY_percent>=nextPercent && dY_percent<=1.2) && canNext) {\r\n\t\t\t\t\t\t\t\tdX = 1 - tmpArrow.width();\r\n\t\t\t\t\t\t\t\tdY = (tmpNextA == null || (tmpTargetNode.isParent && tmpTargetNode.open)) ? (tmpTop + tmpTargetA.height() - tmpArrow.height()/2) : (tmpNextA.offset().top - tmpArrow.height()/2);\r\n\t\t\t\t\t\t\t\tmoveType = consts.move.TYPE_NEXT;\r\n\t\t\t\t\t\t\t}else {\r\n\t\t\t\t\t\t\t\tdX = 5 - tmpArrow.width();\r\n\t\t\t\t\t\t\t\tdY = tmpTop;\r\n\t\t\t\t\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\ttmpArrow.css({\r\n\t\t\t\t\t\t\t\t\"display\":\"block\",\r\n\t\t\t\t\t\t\t\t\"top\": dY + \"px\",\r\n\t\t\t\t\t\t\t\t\"left\": (tmpLeft + dX) + \"px\"\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\ttmpTargetA.addClass(consts.node.TMPTARGET_NODE + \"_\" + moveType);\r\n\r\n\t\t\t\t\t\t\tif (preTmpTargetNodeId != tmpTargetNodeId || preTmpMoveType != moveType) {\r\n\t\t\t\t\t\t\t\tstartTime = (new Date()).getTime();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (tmpTargetNode && tmpTargetNode.isParent && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\t\t\t\tvar startTimer = true;\r\n\t\t\t\t\t\t\t\tif (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId !== tmpTargetNode.tId) {\r\n\t\t\t\t\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null;\r\n\t\t\t\t\t\t\t\t} else if (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId === tmpTargetNode.tId) {\r\n\t\t\t\t\t\t\t\t\tstartTimer = false;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tif (startTimer) {\r\n\t\t\t\t\t\t\t\t\twindow.zTreeMoveTimer = setTimeout(function() {\r\n\t\t\t\t\t\t\t\t\t\tif (moveType != consts.move.TYPE_INNER) return;\r\n\t\t\t\t\t\t\t\t\t\tif (tmpTargetNode && tmpTargetNode.isParent && !tmpTargetNode.open && (new Date()).getTime() - startTime > targetSetting.edit.drag.autoOpenTime\r\n\t\t\t\t\t\t\t\t\t\t\t&& tools.apply(targetSetting.callback.beforeDragOpen, [targetSetting.treeId, tmpTargetNode], true)) {\r\n\t\t\t\t\t\t\t\t\t\t\tview.switchNode(targetSetting, tmpTargetNode);\r\n\t\t\t\t\t\t\t\t\t\t\tif (targetSetting.edit.drag.autoExpandTrigger) {\r\n\t\t\t\t\t\t\t\t\t\t\t\ttargetSetting.treeObj.trigger(consts.event.EXPAND, [targetSetting.treeId, tmpTargetNode]);\r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t}, targetSetting.edit.drag.autoOpenTime+50);\r\n\t\t\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = tmpTargetNode.tId;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t\t\t\tif (tmpTarget && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, null], !!targetSetting.edit.drag.inner)) {\r\n\t\t\t\t\t\t\ttmpTarget.addClass(consts.node.TMPTARGET_TREE);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\ttmpArrow.css({\r\n\t\t\t\t\t\t\t\"display\":\"none\"\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t\tif (window.zTreeMoveTimer) {\r\n\t\t\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tpreTmpTargetNodeId = tmpTargetNodeId;\r\n\t\t\t\t\tpreTmpMoveType = moveType;\r\n\t\t\t\t}\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tdoc.bind(\"mouseup\", _docMouseUp);\r\n\t\t\tfunction _docMouseUp(event) {\r\n\t\t\t\tif (window.zTreeMoveTimer) {\r\n\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null;\r\n\t\t\t\t}\r\n\t\t\t\tpreTmpTargetNodeId = null;\r\n\t\t\t\tpreTmpMoveType = null;\r\n\t\t\t\tdoc.unbind(\"mousemove\", _docMouseMove);\r\n\t\t\t\tdoc.unbind(\"mouseup\", _docMouseUp);\r\n\t\t\t\tdoc.unbind(\"selectstart\", _docSelect);\r\n\t\t\t\t$(\"body\").css(\"cursor\", \"auto\");\r\n\t\t\t\tif (tmpTarget) {\r\n\t\t\t\t\ttmpTarget.removeClass(consts.node.TMPTARGET_TREE);\r\n\t\t\t\t\tif (tmpTargetNodeId) $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + \"_\" + consts.move.TYPE_PREV)\r\n\t\t\t\t\t\t\t.removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_INNER);\r\n\t\t\t\t}\r\n\t\t\t\ttools.showIfameMask(setting, false);\r\n\r\n\t\t\t\troot.showHoverDom = true;\r\n\t\t\t\tif (root.dragFlag == 0) return;\r\n\t\t\t\troot.dragFlag = 0;\r\n\r\n\t\t\t\tvar i, l, tmpNode;\r\n\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\tif (tmpNode.isParent && root.dragNodeShowBefore[tmpNode.tId] && !tmpNode.open) {\r\n\t\t\t\t\t\tview.expandCollapseNode(setting, tmpNode, !tmpNode.open);\r\n\t\t\t\t\t\tdelete root.dragNodeShowBefore[tmpNode.tId];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (curNode) curNode.remove();\r\n\t\t\t\tif (tmpArrow) tmpArrow.remove();\r\n\r\n\t\t\t\tvar isCopy = (event.ctrlKey && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy);\r\n\t\t\t\tif (!isCopy && tmpTarget && tmpTargetNodeId && nodes[0].parentTId && tmpTargetNodeId==nodes[0].parentTId && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t}\r\n\t\t\t\tif (tmpTarget) {\r\n\t\t\t\t\tvar dragTargetNode = tmpTargetNodeId == null ? null: data.getNodeCache(targetSetting, tmpTargetNodeId);\r\n\t\t\t\t\tif (tools.apply(setting.callback.beforeDrop, [targetSetting.treeId, nodes, dragTargetNode, moveType, isCopy], true) == false) return;\r\n\t\t\t\t\tvar newNodes = isCopy ? tools.clone(nodes) : nodes;\r\n\t\t\t\t\t\r\n\t\t\t\t\tfunction dropCallback() {\r\n\t\t\t\t\t\tif (isOtherTree) {\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tif (!isCopy) {\r\n\t\t\t\t\t\t\t\tfor(var i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\t\t\tview.removeNode(setting, nodes[i]);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode, newNodes);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode.getParentNode(), newNodes);\r\n\t\t\t\t\t\t\t\tif (moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\t\t\t\t\t\tfor (i=0, l=newNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[i], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tfor (i=-1, l=newNodes.length-1; i<l; l--) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[l], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tif (isCopy && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode, newNodes);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tif (isCopy) {\r\n\t\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode.getParentNode(), newNodes);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tif (moveType != consts.move.TYPE_NEXT) {\r\n\t\t\t\t\t\t\t\t\tfor (i=0, l=newNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[i], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tfor (i=-1, l=newNodes.length-1; i<l; l--) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[l], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tfor (i=0, l=newNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\tview.selectNode(targetSetting, newNodes[i], i>0);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t$(\"#\" + newNodes[0].tId).focus().blur();\r\n\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.DROP, [event, targetSetting.treeId, newNodes, dragTargetNode, moveType, isCopy]);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (moveType == consts.move.TYPE_INNER && tools.canAsync(targetSetting, dragTargetNode)) {\r\n\t\t\t\t\t\tview.asyncNode(targetSetting, dragTargetNode, false, dropCallback);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tdropCallback();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\tview.selectNode(targetSetting, nodes[i], i>0);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.DROP, [event, setting.treeId, nodes, null, null, null]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tdoc.bind(\"selectstart\", _docSelect);\r\n\t\t\tfunction _docSelect() {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\t//Avoid FireFox's Bug\r\n\t\t\t//If zTree Div CSS set 'overflow', so drag node outside of zTree, and event.target is error.\r\n\t\t\tif(eventMouseDown.preventDefault) {\r\n\t\t\t\teventMouseDown.preventDefault();\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t},\r\n\t//method of tools for zTree\r\n\t_tools = {\r\n\t\tgetAbs: function (obj) {\r\n\t\t\tvar oRect = obj.getBoundingClientRect();\r\n\t\t\treturn [oRect.left,oRect.top]\r\n\t\t},\r\n\t\tinputFocus: function(inputObj) {\r\n\t\t\tif (inputObj.get(0)) {\r\n\t\t\t\tinputObj.focus();\r\n\t\t\t\ttools.setCursorPosition(inputObj.get(0), inputObj.val().length);\r\n\t\t\t}\r\n\t\t},\r\n\t\tinputSelect: function(inputObj) {\r\n\t\t\tif (inputObj.get(0)) {\r\n\t\t\t\tinputObj.focus();\r\n\t\t\t\tinputObj.select();\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetCursorPosition: function(obj, pos){\r\n\t\t\tif(obj.setSelectionRange) {\r\n\t\t\t\tobj.focus();\r\n\t\t\t\tobj.setSelectionRange(pos,pos);\r\n\t\t\t} else if (obj.createTextRange) {\r\n\t\t\t\tvar range = obj.createTextRange();\r\n\t\t\t\trange.collapse(true);\r\n\t\t\t\trange.moveEnd('character', pos);\r\n\t\t\t\trange.moveStart('character', pos);\r\n\t\t\t\trange.select();\r\n\t\t\t}\r\n\t\t},\r\n\t\tshowIfameMask: function(setting, showSign) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\t//clear full mask\r\n\t\t\twhile (root.dragMaskList.length > 0) {\r\n\t\t\t\troot.dragMaskList[0].remove();\r\n\t\t\t\troot.dragMaskList.shift();\r\n\t\t\t}\r\n\t\t\tif (showSign) {\r\n\t\t\t\t//show mask\r\n\t\t\t\tvar iframeList = $(\"iframe\");\r\n\t\t\t\tfor (var i = 0, l = iframeList.length; i < l; i++) {\r\n\t\t\t\t\tvar obj = iframeList.get(i),\r\n\t\t\t\t\tr = tools.getAbs(obj),\r\n\t\t\t\t\tdragMask = $(\"<div id='zTreeMask_\" + i + \"' class='zTreeMask' style='top:\" + r[1] + \"px; left:\" + r[0] + \"px; width:\" + obj.offsetWidth + \"px; height:\" + obj.offsetHeight + \"px;'></div>\");\r\n\t\t\t\t\tdragMask.appendTo(\"body\");\r\n\t\t\t\t\troot.dragMaskList.push(dragMask);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate ztree dom\r\n\t_view = {\r\n\t\taddEditBtn: function(setting, node) {\r\n\t\t\tif (node.editNameFlag || $(\"#\" + node.tId + consts.id.EDIT).length > 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!tools.apply(setting.edit.showRenameBtn, [setting.treeId, node], setting.edit.showRenameBtn)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\teditStr = \"<span class='\" + consts.className.BUTTON + \" edit' id='\" + node.tId + consts.id.EDIT + \"' title='\"+tools.apply(setting.edit.renameTitle, [setting.treeId, node], setting.edit.renameTitle)+\"' treeNode\"+consts.id.EDIT+\" style='display:none;'></span>\";\r\n\t\t\taObj.append(editStr);\r\n\r\n\t\t\t$(\"#\" + node.tId + consts.id.EDIT).bind('click',\r\n\t\t\t\tfunction() {\r\n\t\t\t\t\tif (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeEditName, [setting.treeId, node], true) == false) return false;\r\n\t\t\t\t\tview.editNode(setting, node);\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t\t).show();\r\n\t\t},\r\n\t\taddRemoveBtn: function(setting, node) {\r\n\t\t\tif (node.editNameFlag || $(\"#\" + node.tId + consts.id.REMOVE).length > 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!tools.apply(setting.edit.showRemoveBtn, [setting.treeId, node], setting.edit.showRemoveBtn)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\tremoveStr = \"<span class='\" + consts.className.BUTTON + \" remove' id='\" + node.tId + consts.id.REMOVE + \"' title='\"+tools.apply(setting.edit.removeTitle, [setting.treeId, node], setting.edit.removeTitle)+\"' treeNode\"+consts.id.REMOVE+\" style='display:none;'></span>\";\r\n\t\t\taObj.append(removeStr);\r\n\r\n\t\t\t$(\"#\" + node.tId + consts.id.REMOVE).bind('click',\r\n\t\t\t\tfunction() {\r\n\t\t\t\t\tif (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return false;\r\n\t\t\t\t\tview.removeNode(setting, node);\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]);\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t\t).bind('mousedown',\r\n\t\t\t\tfunction(eventMouseDown) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t\t).show();\r\n\t\t},\r\n\t\taddHoverDom: function(setting, node) {\r\n\t\t\tif (data.getRoot(setting).showHoverDom) {\r\n\t\t\t\tnode.isHover = true;\r\n\t\t\t\tif (setting.edit.enable) {\r\n\t\t\t\t\tview.addEditBtn(setting, node);\r\n\t\t\t\t\tview.addRemoveBtn(setting, node);\r\n\t\t\t\t}\r\n\t\t\t\ttools.apply(setting.view.addHoverDom, [setting.treeId, node]);\r\n\t\t\t}\r\n\t\t},\r\n\t\tcancelCurEditNode: function (setting, forceName) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tnameKey = setting.data.key.name,\r\n\t\t\tnode = root.curEditNode;\r\n\t\t\t\r\n\t\t\tif (node) {\r\n\t\t\t\tvar inputObj = root.curEditInput;\r\n\t\t\t\tvar newName = forceName ? forceName:inputObj.val();\r\n\t\t\t\tif (!forceName && tools.apply(setting.callback.beforeRename, [setting.treeId, node, newName], true) === false) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnode[nameKey] = newName ? newName:inputObj.val();\r\n\t\t\t\t\tif (!forceName) {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.RENAME, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A);\r\n\t\t\t\taObj.removeClass(consts.node.CURSELECTED_EDIT);\r\n\t\t\t\tinputObj.unbind();\r\n\t\t\t\tview.setNodeName(setting, node);\r\n\t\t\t\tnode.editNameFlag = false;\r\n\t\t\t\troot.curEditNode = null;\r\n\t\t\t\troot.curEditInput = null;\r\n\t\t\t\tview.selectNode(setting, node, false);\r\n\t\t\t}\r\n\t\t\troot.noSelection = true;\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\teditNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tview.editNodeBlur = false;\r\n\t\t\tif (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) {\r\n\t\t\t\tsetTimeout(function() {tools.inputFocus(root.curEditInput);}, 0);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar nameKey = setting.data.key.name;\r\n\t\t\tnode.editNameFlag = true;\r\n\t\t\tview.removeTreeDom(setting, node);\r\n\t\t\tview.cancelCurEditNode(setting);\r\n\t\t\tview.selectNode(setting, node, false);\r\n\t\t\t$(\"#\" + node.tId + consts.id.SPAN).html(\"<input type=text class='rename' id='\" + node.tId + consts.id.INPUT + \"' treeNode\" + consts.id.INPUT + \" >\");\r\n\t\t\tvar inputObj = $(\"#\" + node.tId + consts.id.INPUT);\r\n\t\t\tinputObj.attr(\"value\", node[nameKey]);\r\n\t\t\tif (setting.edit.editNameSelectAll) {\r\n\t\t\t\ttools.inputSelect(inputObj);\r\n\t\t\t} else {\r\n\t\t\t\ttools.inputFocus(inputObj);\r\n\t\t\t}\r\n\r\n\t\t\tinputObj.bind('blur', function(event) {\r\n\t\t\t\tif (!view.editNodeBlur) {\r\n\t\t\t\t\tview.cancelCurEditNode(setting);\r\n\t\t\t\t}\r\n\t\t\t}).bind('keydown', function(event) {\r\n\t\t\t\tif (event.keyCode==\"13\") {\r\n\t\t\t\t\tview.editNodeBlur = true;\r\n\t\t\t\t\tview.cancelCurEditNode(setting, null, true);\r\n\t\t\t\t} else if (event.keyCode==\"27\") {\r\n\t\t\t\t\tview.cancelCurEditNode(setting, node[nameKey]);\r\n\t\t\t\t}\r\n\t\t\t}).bind('click', function(event) {\r\n\t\t\t\treturn false;\r\n\t\t\t}).bind('dblclick', function(event) {\r\n\t\t\t\treturn false;\r\n\t\t\t});\r\n\r\n\t\t\t$(\"#\" + node.tId + consts.id.A).addClass(consts.node.CURSELECTED_EDIT);\r\n\t\t\troot.curEditInput = inputObj;\r\n\t\t\troot.noSelection = false;\r\n\t\t\troot.curEditNode = node;\r\n\t\t},\r\n\t\tmoveNode: function(setting, targetNode, node, moveType, animateFlag, isSilent) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tif (targetNode == node) return;\r\n\t\t\tif (setting.data.keep.leaf && targetNode && !targetNode.isParent && moveType == consts.move.TYPE_INNER) return;\r\n\t\t\tvar oldParentNode = (node.parentTId ? node.getParentNode(): root),\r\n\t\t\ttargetNodeIsRoot = (targetNode === null || targetNode == root);\r\n\t\t\tif (targetNodeIsRoot && targetNode === null) targetNode = root;\r\n\t\t\tif (targetNodeIsRoot) moveType = consts.move.TYPE_INNER;\r\n\t\t\tvar targetParentNode = (targetNode.parentTId ? targetNode.getParentNode() : root);\r\n\r\n\t\t\tif (moveType != consts.move.TYPE_PREV && moveType != consts.move.TYPE_NEXT) {\r\n\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\tif (targetNodeIsRoot) {\r\n\t\t\t\t\t//parentTId of root node is null\r\n\t\t\t\t\tnode.parentTId = null;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (!targetNode.isParent) {\r\n\t\t\t\t\t\ttargetNode.isParent = true;\r\n\t\t\t\t\t\ttargetNode.open = !!targetNode.open;\r\n\t\t\t\t\t\tview.setNodeLineIcos(setting, targetNode);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tnode.parentTId = targetNode.tId;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t//move node Dom\r\n\t\t\tvar targetObj, target_ulObj;\r\n\t\t\tif (targetNodeIsRoot) {\r\n\t\t\t\ttargetObj = setting.treeObj;\r\n\t\t\t\ttarget_ulObj = targetObj;\r\n\t\t\t} else {\r\n\t\t\t\tif (!isSilent && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\tview.expandCollapseNode(setting, targetNode, true, false);\r\n\t\t\t\t} else if (!isSilent) {\r\n\t\t\t\t\tview.expandCollapseNode(setting, targetNode.getParentNode(), true, false);\r\n\t\t\t\t}\r\n\t\t\t\ttargetObj = $(\"#\" + targetNode.tId);\r\n\t\t\t\ttarget_ulObj = $(\"#\" + targetNode.tId + consts.id.UL);\r\n\t\t\t\tif (!!targetObj.get(0) && !target_ulObj.get(0)) {\r\n\t\t\t\t\tvar ulstr = [];\r\n\t\t\t\t\tview.makeUlHtml(setting, targetNode, ulstr, '');\r\n\t\t\t\t\ttargetObj.append(ulstr.join(''));\r\n\t\t\t\t}\r\n\t\t\t\ttarget_ulObj = $(\"#\" + targetNode.tId + consts.id.UL);\r\n\t\t\t}\r\n\t\t\tvar nodeDom = $(\"#\" + node.tId);\r\n\t\t\tif (!nodeDom.get(0)) {\r\n\t\t\t\tnodeDom = view.appendNodes(setting, node.level, [node], null, false, true).join('');\r\n\t\t\t} else if (!targetObj.get(0)) {\r\n\t\t\t\tnodeDom.remove();\r\n\t\t\t}\r\n\t\t\tif (target_ulObj.get(0) && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\ttarget_ulObj.append(nodeDom);\r\n\t\t\t} else if (targetObj.get(0) && moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\ttargetObj.before(nodeDom);\r\n\t\t\t} else if (targetObj.get(0) && moveType == consts.move.TYPE_NEXT) {\r\n\t\t\t\ttargetObj.after(nodeDom);\r\n\t\t\t}\r\n\r\n\t\t\t//repair the data after move\r\n\t\t\tvar i,l,\r\n\t\t\ttmpSrcIndex = -1,\r\n\t\t\ttmpTargetIndex = 0,\r\n\t\t\toldNeighbor = null,\r\n\t\t\tnewNeighbor = null,\r\n\t\t\toldLevel = node.level;\r\n\t\t\tif (node.isFirstNode) {\r\n\t\t\t\ttmpSrcIndex = 0;\r\n\t\t\t\tif (oldParentNode[childKey].length > 1 ) {\r\n\t\t\t\t\toldNeighbor = oldParentNode[childKey][1];\r\n\t\t\t\t\toldNeighbor.isFirstNode = true;\r\n\t\t\t\t}\r\n\t\t\t} else if (node.isLastNode) {\r\n\t\t\t\ttmpSrcIndex = oldParentNode[childKey].length -1;\r\n\t\t\t\toldNeighbor = oldParentNode[childKey][tmpSrcIndex - 1];\r\n\t\t\t\toldNeighbor.isLastNode = true;\r\n\t\t\t} else {\r\n\t\t\t\tfor (i = 0, l = oldParentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\tif (oldParentNode[childKey][i].tId == node.tId) {\r\n\t\t\t\t\t\ttmpSrcIndex = i;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (tmpSrcIndex >= 0) {\r\n\t\t\t\toldParentNode[childKey].splice(tmpSrcIndex, 1);\r\n\t\t\t}\r\n\t\t\tif (moveType != consts.move.TYPE_INNER) {\r\n\t\t\t\tfor (i = 0, l = targetParentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\tif (targetParentNode[childKey][i].tId == targetNode.tId) tmpTargetIndex = i;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\tif (!targetNode[childKey]) targetNode[childKey] = new Array();\r\n\t\t\t\tif (targetNode[childKey].length > 0) {\r\n\t\t\t\t\tnewNeighbor = targetNode[childKey][targetNode[childKey].length - 1];\r\n\t\t\t\t\tnewNeighbor.isLastNode = false;\r\n\t\t\t\t}\r\n\t\t\t\ttargetNode[childKey].splice(targetNode[childKey].length, 0, node);\r\n\t\t\t\tnode.isLastNode = true;\r\n\t\t\t\tnode.isFirstNode = (targetNode[childKey].length == 1);\r\n\t\t\t} else if (targetNode.isFirstNode && moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex, 0, node);\r\n\t\t\t\tnewNeighbor = targetNode;\r\n\t\t\t\tnewNeighbor.isFirstNode = false;\r\n\t\t\t\tnode.parentTId = targetNode.parentTId;\r\n\t\t\t\tnode.isFirstNode = true;\r\n\t\t\t\tnode.isLastNode = false;\r\n\r\n\t\t\t} else if (targetNode.isLastNode && moveType == consts.move.TYPE_NEXT) {\r\n\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex + 1, 0, node);\r\n\t\t\t\tnewNeighbor = targetNode;\r\n\t\t\t\tnewNeighbor.isLastNode = false;\r\n\t\t\t\tnode.parentTId = targetNode.parentTId;\r\n\t\t\t\tnode.isFirstNode = false;\r\n\t\t\t\tnode.isLastNode = true;\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex, 0, node);\r\n\t\t\t\t} else {\r\n\t\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex + 1, 0, node);\r\n\t\t\t\t}\r\n\t\t\t\tnode.parentTId = targetNode.parentTId;\r\n\t\t\t\tnode.isFirstNode = false;\r\n\t\t\t\tnode.isLastNode = false;\r\n\t\t\t}\r\n\t\t\tdata.fixPIdKeyValue(setting, node);\r\n\t\t\tdata.setSonNodeLevel(setting, node.getParentNode(), node);\r\n\r\n\t\t\t//repair node what been moved\r\n\t\t\tview.setNodeLineIcos(setting, node);\r\n\t\t\tview.repairNodeLevelClass(setting, node, oldLevel)\r\n\r\n\t\t\t//repair node's old parentNode dom\r\n\t\t\tif (!setting.data.keep.parent && oldParentNode[childKey].length < 1) {\r\n\t\t\t\t//old parentNode has no child nodes\r\n\t\t\t\toldParentNode.isParent = false;\r\n\t\t\t\toldParentNode.open = false;\r\n\t\t\t\tvar tmp_ulObj = $(\"#\" + oldParentNode.tId + consts.id.UL),\r\n\t\t\t\ttmp_switchObj = $(\"#\" + oldParentNode.tId + consts.id.SWITCH),\r\n\t\t\t\ttmp_icoObj = $(\"#\" + oldParentNode.tId + consts.id.ICON);\r\n\t\t\t\tview.replaceSwitchClass(oldParentNode, tmp_switchObj, consts.folder.DOCU);\r\n\t\t\t\tview.replaceIcoClass(oldParentNode, tmp_icoObj, consts.folder.DOCU);\r\n\t\t\t\ttmp_ulObj.css(\"display\", \"none\");\r\n\r\n\t\t\t} else if (oldNeighbor) {\r\n\t\t\t\t//old neigbor node\r\n\t\t\t\tview.setNodeLineIcos(setting, oldNeighbor);\r\n\t\t\t}\r\n\r\n\t\t\t//new neigbor node\r\n\t\t\tif (newNeighbor) {\r\n\t\t\t\tview.setNodeLineIcos(setting, newNeighbor);\r\n\t\t\t}\r\n\r\n\t\t\t//repair checkbox / radio\r\n\t\t\tif (!!setting.check && setting.check.enable && view.repairChkClass) {\r\n\t\t\t\tview.repairChkClass(setting, oldParentNode);\r\n\t\t\t\tview.repairParentChkClassWithSelf(setting, oldParentNode);\r\n\t\t\t\tif (oldParentNode != node.parent)\r\n\t\t\t\t\tview.repairParentChkClassWithSelf(setting, node);\r\n\t\t\t}\r\n\r\n\t\t\t//expand parents after move\r\n\t\t\tif (!isSilent) {\r\n\t\t\t\tview.expandCollapseParentNode(setting, node.getParentNode(), true, animateFlag);\r\n\t\t\t}\r\n\t\t},\r\n\t\tremoveEditBtn: function(node) {\r\n\t\t\t$(\"#\" + node.tId + consts.id.EDIT).unbind().remove();\r\n\t\t},\r\n\t\tremoveRemoveBtn: function(node) {\r\n\t\t\t$(\"#\" + node.tId + consts.id.REMOVE).unbind().remove();\r\n\t\t},\r\n\t\tremoveTreeDom: function(setting, node) {\r\n\t\t\tnode.isHover = false;\r\n\t\t\tview.removeEditBtn(node);\r\n\t\t\tview.removeRemoveBtn(node);\r\n\t\t\ttools.apply(setting.view.removeHoverDom, [setting.treeId, node]);\r\n\t\t},\r\n\t\trepairNodeLevelClass: function(setting, node, oldLevel) {\r\n\t\t\tif (oldLevel === node.level) return;\r\n\t\t\tvar liObj = $(\"#\" + node.tId),\r\n\t\t\taObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\tulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\toldClass = consts.className.LEVEL + oldLevel,\r\n\t\t\tnewClass = consts.className.LEVEL + node.level;\r\n\t\t\tliObj.removeClass(oldClass);\r\n\t\t\tliObj.addClass(newClass);\r\n\t\t\taObj.removeClass(oldClass);\r\n\t\t\taObj.addClass(newClass);\r\n\t\t\tulObj.removeClass(oldClass);\r\n\t\t\tulObj.addClass(newClass);\r\n\t\t}\r\n\t},\r\n\r\n\t_z = {\r\n\t\ttools: _tools,\r\n\t\tview: _view,\r\n\t\tevent: _event,\r\n\t\tdata: _data\r\n\t};\r\n\t$.extend(true, $.fn.zTree.consts, _consts);\r\n\t$.extend(true, $.fn.zTree._z, _z);\r\n\r\n\tvar zt = $.fn.zTree,\r\n\ttools = zt._z.tools,\r\n\tconsts = zt.consts,\r\n\tview = zt._z.view,\r\n\tdata = zt._z.data,\r\n\tevent = zt._z.event;\r\n\r\n\tdata.exSetting(_setting);\r\n\tdata.addInitBind(_bindEvent);\r\n\tdata.addInitUnBind(_unbindEvent);\r\n\tdata.addInitCache(_initCache);\r\n\tdata.addInitNode(_initNode);\r\n\tdata.addInitProxy(_eventProxy);\r\n\tdata.addInitRoot(_initRoot);\r\n\tdata.addZTreeTools(_zTreeTools);\r\n\r\n\tvar _cancelPreSelectedNode = view.cancelPreSelectedNode;\r\n\tview.cancelPreSelectedNode = function (setting, node) {\r\n\t\tvar list = data.getRoot(setting).curSelectedList;\r\n\t\tfor (var i=0, j=list.length; i<j; i++) {\r\n\t\t\tif (!node || node === list[i]) {\r\n\t\t\t\tview.removeTreeDom(setting, list[i]);\r\n\t\t\t\tif (node) break;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (_cancelPreSelectedNode) _cancelPreSelectedNode.apply(view, arguments);\r\n\t}\r\n\r\n\tvar _createNodes = view.createNodes;\r\n\tview.createNodes = function(setting, level, nodes, parentNode) {\r\n\t\tif (_createNodes) {\r\n\t\t\t_createNodes.apply(view, arguments);\r\n\t\t}\r\n\t\tif (!nodes) return;\r\n\t\tif (view.repairParentChkClassWithSelf) {\r\n\t\t\tview.repairParentChkClassWithSelf(setting, parentNode);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _makeNodeUrl = view.makeNodeUrl;\r\n\tview.makeNodeUrl = function(setting, node) {\r\n\t\treturn setting.edit.enable ? null : (_makeNodeUrl.apply(view, arguments));\r\n\t}\r\n\r\n\tvar _removeNode = view.removeNode;\r\n\tview.removeNode = function(setting, node) {\r\n\t\tvar root = data.getRoot(setting);\r\n\t\tif (root.curEditNode === node) root.curEditNode = null;\r\n\t\tif (_removeNode) {\r\n\t\t\t_removeNode.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _selectNode = view.selectNode;\r\n\tview.selectNode = function(setting, node, addFlag) {\r\n\t\tvar root = data.getRoot(setting);\r\n\t\tif (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (_selectNode) _selectNode.apply(view, arguments);\r\n\t\tview.addHoverDom(setting, node);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tvar _uCanDo = tools.uCanDo;\r\n\ttools.uCanDo = function(setting, e) {\r\n\t\tvar root = data.getRoot(setting);\r\n\t\tif (e && (tools.eqs(e.type, \"mouseover\") || tools.eqs(e.type, \"mouseout\") || tools.eqs(e.type, \"mousedown\") || tools.eqs(e.type, \"mouseup\"))) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn (!root.curEditNode) && (_uCanDo ? _uCanDo.apply(view, arguments) : true);\r\n\t}\r\n})(jQuery);\r\n\r\n/*\r\n * JQuery zTree exHideNodes 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\t//default init node of exLib\r\n\tvar _initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (typeof n.isHidden == \"string\") n.isHidden = tools.eqs(n.isHidden, \"true\");\r\n\t\tn.isHidden = !!n.isHidden;\r\n\t\tdata.initHideForExCheck(setting, n);\r\n\t},\r\n\t//add dom for check\r\n\t_beforeA = function(setting, node, html) {},\r\n\t//update zTreeObj, add method of exLib\r\n\t_zTreeTools = function(setting, zTreeTools) {\r\n\t\tzTreeTools.showNodes = function(nodes, options) {\r\n\t\t\tview.showNodes(setting, nodes, options);\r\n\t\t}\r\n\t\tzTreeTools.showNode = function(node, options) {\r\n\t\t\tif (!node) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tview.showNodes(setting, [node], options);\r\n\t\t}\r\n\t\tzTreeTools.hideNodes = function(nodes, options) {\r\n\t\t\tview.hideNodes(setting, nodes, options);\r\n\t\t}\r\n\t\tzTreeTools.hideNode = function(node, options) {\r\n\t\t\tif (!node) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tview.hideNodes(setting, [node], options);\r\n\t\t}\r\n\r\n\t\tvar _checkNode = zTreeTools.checkNode;\r\n\t\tif (_checkNode) {\r\n\t\t\tzTreeTools.checkNode = function(node, checked, checkTypeFlag, callbackFlag) {\r\n\t\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t_checkNode.apply(zTreeTools, arguments);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate data\r\n\t_data = {\r\n\t\tinitHideForExCheck: function(setting, n) {\r\n\t\t\tif (n.isHidden && setting.check && setting.check.enable) {\r\n\t\t\t\tif(typeof n._nocheck == \"undefined\") {\r\n\t\t\t\t\tn._nocheck = !!n.nocheck\r\n\t\t\t\t\tn.nocheck = true;\r\n\t\t\t\t}\r\n\t\t\t\tn.check_Child_State = -1;\r\n\t\t\t\tif (view.repairParentChkClassWithSelf) {\r\n\t\t\t\t\tview.repairParentChkClassWithSelf(setting, n);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tinitShowForExCheck: function(setting, n) {\r\n\t\t\tif (!n.isHidden && setting.check && setting.check.enable) {\r\n\t\t\t\tif(typeof n._nocheck != \"undefined\") {\r\n\t\t\t\t\tn.nocheck = n._nocheck;\r\n\t\t\t\t\tdelete n._nocheck;\r\n\t\t\t\t}\r\n\t\t\t\tif (view.setChkClass) {\r\n\t\t\t\t\tvar checkObj = $(\"#\" + n.tId + consts.id.CHECK);\r\n\t\t\t\t\tview.setChkClass(setting, checkObj, n);\r\n\t\t\t\t}\r\n\t\t\t\tif (view.repairParentChkClassWithSelf) {\r\n\t\t\t\t\tview.repairParentChkClassWithSelf(setting, n);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate ztree dom\r\n\t_view = {\r\n\t\tclearOldFirstNode: function(setting, node) {\r\n\t\t\tvar n = node.getNextNode();\r\n\t\t\twhile(!!n){\r\n\t\t\t\tif (n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = false;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (n.isLastNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tn = n.getNextNode();\r\n\t\t\t}\r\n\t\t},\r\n\t\tclearOldLastNode: function(setting, node) {\r\n\t\t\tvar n = node.getPreNode();\r\n\t\t\twhile(!!n){\r\n\t\t\t\tif (n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = false;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (n.isFirstNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tn = n.getPreNode();\r\n\t\t\t}\r\n\t\t},\r\n\t\tmakeDOMNodeMainBefore: function(html, setting, node) {\r\n\t\t\thtml.push(\"<li \", (node.isHidden ? \"style='display:none;' \" : \"\"), \"id='\", node.tId, \"' class='\", consts.className.LEVEL, node.level,\"' tabindex='0' hidefocus='true' treenode>\");\r\n\t\t},\r\n\t\tshowNode: function(setting, node, options) {\r\n\t\t\tnode.isHidden = false;\r\n\t\t\tdata.initShowForExCheck(setting, node);\r\n\t\t\t$(\"#\" + node.tId).show();\r\n\t\t},\r\n\t\tshowNodes: function(setting, nodes, options) {\r\n\t\t\tif (!nodes || nodes.length == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar pList = {}, i, j;\r\n\t\t\tfor (i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tvar n = nodes[i];\r\n\t\t\t\tif (!pList[n.parentTId]) {\r\n\t\t\t\t\tvar pn = n.getParentNode();\r\n\t\t\t\t\tpList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode();\r\n\t\t\t\t}\r\n\t\t\t\tview.showNode(setting, n, options);\r\n\t\t\t}\r\n\t\t\tfor (var tId in pList) {\r\n\t\t\t\tvar children = pList[tId][setting.data.key.children];\r\n\t\t\t\tview.setFirstNodeForShow(setting, children);\r\n\t\t\t\tview.setLastNodeForShow(setting, children);\r\n\t\t\t}\r\n\t\t},\r\n\t\thideNode: function(setting, node, options) {\r\n\t\t\tnode.isHidden = true;\r\n\t\t\tnode.isFirstNode = false;\r\n\t\t\tnode.isLastNode = false;\r\n\t\t\tdata.initHideForExCheck(setting, node);\r\n\t\t\tview.cancelPreSelectedNode(setting, node);\r\n\t\t\t$(\"#\" + node.tId).hide();\r\n\t\t},\r\n\t\thideNodes: function(setting, nodes, options) {\r\n\t\t\tif (!nodes || nodes.length == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar pList = {}, i, j;\r\n\t\t\tfor (i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tvar n = nodes[i];\r\n\t\t\t\tif ((n.isFirstNode || n.isLastNode) && !pList[n.parentTId]) {\r\n\t\t\t\t\tvar pn = n.getParentNode();\r\n\t\t\t\t\tpList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode();\r\n\t\t\t\t}\r\n\t\t\t\tview.hideNode(setting, n, options);\r\n\t\t\t}\r\n\t\t\tfor (var tId in pList) {\r\n\t\t\t\tvar children = pList[tId][setting.data.key.children];\r\n\t\t\t\tview.setFirstNodeForHide(setting, children);\r\n\t\t\t\tview.setLastNodeForHide(setting, children);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetFirstNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif (childLength > 0 && !parentNode[childKey][0].isHidden) {\r\n\t\t\t\tparentNode[childKey][0].isFirstNode = true;\r\n\t\t\t} else if (childLength > 0) {\r\n\t\t\t\tview.setFirstNodeForHide(setting, parentNode[childKey]);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetLastNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif (childLength > 0 && !parentNode[childKey][0].isHidden) {\r\n\t\t\t\tparentNode[childKey][childLength - 1].isLastNode = true;\r\n\t\t\t} else if (childLength > 0) {\r\n\t\t\t\tview.setLastNodeForHide(setting, parentNode[childKey]);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetFirstNodeForHide: function(setting, nodes) {\r\n\t\t\tvar n,i,j;\r\n\t\t\tfor (i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (n.isFirstNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (!n.isHidden && !n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = true;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn n;\r\n\t\t},\r\n\t\tsetFirstNodeForShow: function(setting, nodes) {\r\n\t\t\tvar n,i,j, first, old;\r\n\t\t\tfor(i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (!first && !n.isHidden && n.isFirstNode) {\r\n\t\t\t\t\tfirst = n;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else if (!first && !n.isHidden && !n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = true;\r\n\t\t\t\t\tfirst = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t} else if (first && n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = false;\r\n\t\t\t\t\told = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn {\"new\":first, \"old\":old};\r\n\t\t},\r\n\t\tsetLastNodeForHide: function(setting, nodes) {\r\n\t\t\tvar n,i;\r\n\t\t\tfor (i=nodes.length-1; i>=0; i--) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (n.isLastNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (!n.isHidden && !n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = true;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn n;\r\n\t\t},\r\n\t\tsetLastNodeForShow: function(setting, nodes) {\r\n\t\t\tvar n,i,j, last, old;\r\n\t\t\tfor (i=nodes.length-1; i>=0; i--) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (!last && !n.isHidden && n.isLastNode) {\r\n\t\t\t\t\tlast = n;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else if (!last && !n.isHidden && !n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = true;\r\n\t\t\t\t\tlast = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t} else if (last && n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = false;\r\n\t\t\t\t\told = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn {\"new\":last, \"old\":old};\r\n\t\t}\r\n\t},\r\n\r\n\t_z = {\r\n\t\tview: _view,\r\n\t\tdata: _data\r\n\t};\r\n\t$.extend(true, $.fn.zTree._z, _z);\r\n\r\n\tvar zt = $.fn.zTree,\r\n\ttools = zt._z.tools,\r\n\tconsts = zt.consts,\r\n\tview = zt._z.view,\r\n\tdata = zt._z.data,\r\n\tevent = zt._z.event;\r\n\r\n\tdata.addInitNode(_initNode);\r\n\tdata.addBeforeA(_beforeA);\r\n\tdata.addZTreeTools(_zTreeTools);\r\n\r\n//\tOverride method in core\r\n\tvar _dInitNode = data.initNode;\r\n\tdata.tmpHideParent = -1;\r\n\tdata.initNode = function(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (data.tmpHideParent !== parentNode) {\r\n\t\t\tdata.tmpHideParent = parentNode;\r\n\t\t\tvar tmpPNode = (parentNode) ? parentNode: data.getRoot(setting),\r\n\t\t\tchildren = tmpPNode[setting.data.key.children];\r\n\t\t\tdata.tmpHideFirstNode = view.setFirstNodeForHide(setting, children);\r\n\t\t\tdata.tmpHideLastNode = view.setLastNodeForHide(setting, children);\r\n\t\t\tview.setNodeLineIcos(setting, data.tmpHideFirstNode);\r\n\t\t\tview.setNodeLineIcos(setting, data.tmpHideLastNode);\r\n\t\t}\r\n\t\tisFirstNode = (data.tmpHideFirstNode === node);\r\n\t\tisLastNode = (data.tmpHideLastNode === node);\r\n\t\tif (_dInitNode) _dInitNode.apply(data, arguments);\r\n\t\tif (isLastNode) {\r\n\t\t\tview.clearOldLastNode(setting, node);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _makeChkFlag = data.makeChkFlag;\r\n\tif (!!_makeChkFlag) {\r\n\t\tdata.makeChkFlag = function(setting, node) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_makeChkFlag.apply(data, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _getTreeCheckedNodes = data.getTreeCheckedNodes;\r\n\tif (!!_getTreeCheckedNodes) {\r\n\t\tdata.getTreeCheckedNodes = function(setting, nodes, checked, results) {\r\n\t\t\tif (!!nodes && nodes.length > 0) {\r\n\t\t\t\tvar p = nodes[0].getParentNode();\r\n\t\t\t\tif (!!p && !!p.isHidden) {\r\n\t\t\t\t\treturn [];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn _getTreeCheckedNodes.apply(data, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _getTreeChangeCheckedNodes = data.getTreeChangeCheckedNodes;\r\n\tif (!!_getTreeChangeCheckedNodes) {\r\n\t\tdata.getTreeChangeCheckedNodes = function(setting, nodes, results) {\r\n\t\t\tif (!!nodes && nodes.length > 0) {\r\n\t\t\t\tvar p = nodes[0].getParentNode();\r\n\t\t\t\tif (!!p && !!p.isHidden) {\r\n\t\t\t\t\treturn [];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn _getTreeChangeCheckedNodes.apply(data, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _expandCollapseSonNode = view.expandCollapseSonNode;\r\n\tif (!!_expandCollapseSonNode) {\r\n\t\tview.expandCollapseSonNode = function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_expandCollapseSonNode.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _setSonNodeCheckBox = view.setSonNodeCheckBox;\r\n\tif (!!_setSonNodeCheckBox) {\r\n\t\tview.setSonNodeCheckBox = function(setting, node, value, srcNode) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_setSonNodeCheckBox.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _repairParentChkClassWithSelf = view.repairParentChkClassWithSelf;\r\n\tif (!!_repairParentChkClassWithSelf) {\r\n\t\tview.repairParentChkClassWithSelf = function(setting, node) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_repairParentChkClassWithSelf.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n})(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/js/jquery.ztree.core-3.5.js",
    "content": "/*\r\n * JQuery zTree core 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\tvar settings = {}, roots = {}, caches = {},\r\n\t//default consts of core\r\n\t_consts = {\r\n\t\tclassName: {\r\n\t\t\tBUTTON: \"button\",\r\n\t\t\tLEVEL: \"level\",\r\n\t\t\tICO_LOADING: \"ico_loading\",\r\n\t\t\tSWITCH: \"switch\"\r\n\t\t},\r\n\t\tevent: {\r\n\t\t\tNODECREATED: \"ztree_nodeCreated\",\r\n\t\t\tCLICK: \"ztree_click\",\r\n\t\t\tEXPAND: \"ztree_expand\",\r\n\t\t\tCOLLAPSE: \"ztree_collapse\",\r\n\t\t\tASYNC_SUCCESS: \"ztree_async_success\",\r\n\t\t\tASYNC_ERROR: \"ztree_async_error\"\r\n\t\t},\r\n\t\tid: {\r\n\t\t\tA: \"_a\",\r\n\t\t\tICON: \"_ico\",\r\n\t\t\tSPAN: \"_span\",\r\n\t\t\tSWITCH: \"_switch\",\r\n\t\t\tUL: \"_ul\"\r\n\t\t},\r\n\t\tline: {\r\n\t\t\tROOT: \"root\",\r\n\t\t\tROOTS: \"roots\",\r\n\t\t\tCENTER: \"center\",\r\n\t\t\tBOTTOM: \"bottom\",\r\n\t\t\tNOLINE: \"noline\",\r\n\t\t\tLINE: \"line\"\r\n\t\t},\r\n\t\tfolder: {\r\n\t\t\tOPEN: \"open\",\r\n\t\t\tCLOSE: \"close\",\r\n\t\t\tDOCU: \"docu\"\r\n\t\t},\r\n\t\tnode: {\r\n\t\t\tCURSELECTED: \"curSelectedNode\"\r\n\t\t}\r\n\t},\r\n\t//default setting of core\r\n\t_setting = {\r\n\t\ttreeId: \"\",\r\n\t\ttreeObj: null,\r\n\t\tview: {\r\n\t\t\taddDiyDom: null,\r\n\t\t\tautoCancelSelected: true,\r\n\t\t\tdblClickExpand: true,\r\n\t\t\texpandSpeed: \"fast\",\r\n\t\t\tfontCss: {},\r\n\t\t\tnameIsHTML: false,\r\n\t\t\tselectedMulti: true,\r\n\t\t\tshowIcon: true,\r\n\t\t\tshowLine: true,\r\n\t\t\tshowTitle: true\r\n\t\t},\r\n\t\tdata: {\r\n\t\t\tkey: {\r\n\t\t\t\tchildren: \"children\",\r\n\t\t\t\tname: \"name\",\r\n\t\t\t\ttitle: \"\",\r\n\t\t\t\turl: \"url\"\r\n\t\t\t},\r\n\t\t\tsimpleData: {\r\n\t\t\t\tenable: false,\r\n\t\t\t\tidKey: \"id\",\r\n\t\t\t\tpIdKey: \"pId\",\r\n\t\t\t\trootPId: null\r\n\t\t\t},\r\n\t\t\tkeep: {\r\n\t\t\t\tparent: false,\r\n\t\t\t\tleaf: false\r\n\t\t\t}\r\n\t\t},\r\n\t\tasync: {\r\n\t\t\tenable: false,\r\n\t\t\tcontentType: \"application/x-www-form-urlencoded\",\r\n\t\t\ttype: \"post\",\r\n\t\t\tdataType: \"text\",\r\n\t\t\turl: \"\",\r\n\t\t\tautoParam: [],\r\n\t\t\totherParam: [],\r\n\t\t\tdataFilter: null\r\n\t\t},\r\n\t\tcallback: {\r\n\t\t\tbeforeAsync:null,\r\n\t\t\tbeforeClick:null,\r\n\t\t\tbeforeDblClick:null,\r\n\t\t\tbeforeRightClick:null,\r\n\t\t\tbeforeMouseDown:null,\r\n\t\t\tbeforeMouseUp:null,\r\n\t\t\tbeforeExpand:null,\r\n\t\t\tbeforeCollapse:null,\r\n\t\t\tbeforeRemove:null,\r\n\r\n\t\t\tonAsyncError:null,\r\n\t\t\tonAsyncSuccess:null,\r\n\t\t\tonNodeCreated:null,\r\n\t\t\tonClick:null,\r\n\t\t\tonDblClick:null,\r\n\t\t\tonRightClick:null,\r\n\t\t\tonMouseDown:null,\r\n\t\t\tonMouseUp:null,\r\n\t\t\tonExpand:null,\r\n\t\t\tonCollapse:null,\r\n\t\t\tonRemove:null\r\n\t\t}\r\n\t},\r\n\t//default root of core\r\n\t//zTree use root to save full data\r\n\t_initRoot = function (setting) {\r\n\t\tvar r = data.getRoot(setting);\r\n\t\tif (!r) {\r\n\t\t\tr = {};\r\n\t\t\tdata.setRoot(setting, r);\r\n\t\t}\r\n\t\tr[setting.data.key.children] = [];\r\n\t\tr.expandTriggerFlag = false;\r\n\t\tr.curSelectedList = [];\r\n\t\tr.noSelection = true;\r\n\t\tr.createdNodes = [];\r\n\t\tr.zId = 0;\r\n\t\tr._ver = (new Date()).getTime();\r\n\t},\r\n\t//default cache of core\r\n\t_initCache = function(setting) {\r\n\t\tvar c = data.getCache(setting);\r\n\t\tif (!c) {\r\n\t\t\tc = {};\r\n\t\t\tdata.setCache(setting, c);\r\n\t\t}\r\n\t\tc.nodes = [];\r\n\t\tc.doms = [];\r\n\t},\r\n\t//default bindEvent of core\r\n\t_bindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.bind(c.NODECREATED, function (event, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onNodeCreated, [event, treeId, node]);\r\n\t\t});\r\n\r\n\t\to.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) {\r\n\t\t\ttools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]);\r\n\t\t});\r\n\r\n\t\to.bind(c.EXPAND, function (event, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onExpand, [event, treeId, node]);\r\n\t\t});\r\n\r\n\t\to.bind(c.COLLAPSE, function (event, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onCollapse, [event, treeId, node]);\r\n\t\t});\r\n\r\n\t\to.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) {\r\n\t\t\ttools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]);\r\n\t\t});\r\n\r\n\t\to.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) {\r\n\t\t\ttools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]);\r\n\t\t});\r\n\t},\r\n\t_unbindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.unbind(c.NODECREATED)\r\n\t\t.unbind(c.CLICK)\r\n\t\t.unbind(c.EXPAND)\r\n\t\t.unbind(c.COLLAPSE)\r\n\t\t.unbind(c.ASYNC_SUCCESS)\r\n\t\t.unbind(c.ASYNC_ERROR);\r\n\t},\t\r\n\t//default event proxy of core\r\n\t_eventProxy = function(event) {\r\n\t\tvar target = event.target,\r\n\t\tsetting = data.getSetting(event.data.treeId),\r\n\t\ttId = \"\", node = null,\r\n\t\tnodeEventType = \"\", treeEventType = \"\",\r\n\t\tnodeEventCallback = null, treeEventCallback = null,\r\n\t\ttmp = null;\r\n\r\n\t\tif (tools.eqs(event.type, \"mousedown\")) {\r\n\t\t\ttreeEventType = \"mousedown\";\r\n\t\t} else if (tools.eqs(event.type, \"mouseup\")) {\r\n\t\t\ttreeEventType = \"mouseup\";\r\n\t\t} else if (tools.eqs(event.type, \"contextmenu\")) {\r\n\t\t\ttreeEventType = \"contextmenu\";\r\n\t\t} else if (tools.eqs(event.type, \"click\")) {\r\n\t\t\tif (tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.SWITCH) !== null) {\r\n\t\t\t\ttId = ($(target).parent(\"li\").get(0) || $(target).parentsUntil(\"li\").parent().get(0)).id;\r\n\t\t\t\tnodeEventType = \"switchNode\";\r\n\t\t\t} else {\r\n\t\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\t\tif (tmp) {\r\n\t\t\t\t\ttId = ($(tmp).parent(\"li\").get(0) || $(tmp).parentsUntil(\"li\").parent().get(0)).id;\r\n\t\t\t\t\tnodeEventType = \"clickNode\";\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(event.type, \"dblclick\")) {\r\n\t\t\ttreeEventType = \"dblclick\";\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {\r\n\t\t\t\ttId = ($(tmp).parent(\"li\").get(0) || $(tmp).parentsUntil(\"li\").parent().get(0)).id;\r\n\t\t\t\tnodeEventType = \"switchNode\";\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (treeEventType.length > 0 && tId.length == 0) {\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {tId = ($(tmp).parent(\"li\").get(0) || $(tmp).parentsUntil(\"li\").parent().get(0)).id;}\r\n\t\t}\r\n\t\t// event to node\r\n\t\tif (tId.length>0) {\r\n\t\t\tnode = data.getNodeCache(setting, tId);\r\n\t\t\tswitch (nodeEventType) {\r\n\t\t\t\tcase \"switchNode\" :\r\n\t\t\t\t\tif (!node.isParent) {\r\n\t\t\t\t\t\tnodeEventType = \"\";\r\n\t\t\t\t\t} else if (tools.eqs(event.type, \"click\") \r\n\t\t\t\t\t\t|| (tools.eqs(event.type, \"dblclick\") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) {\r\n\t\t\t\t\t\tnodeEventCallback = handler.onSwitchNode;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tnodeEventType = \"\";\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"clickNode\" :\r\n\t\t\t\t\tnodeEventCallback = handler.onClickNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// event to zTree\r\n\t\tswitch (treeEventType) {\r\n\t\t\tcase \"mousedown\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeMousedown;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"mouseup\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeMouseup;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"dblclick\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeDblclick;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"contextmenu\" :\r\n\t\t\t\ttreeEventCallback = handler.onZTreeContextmenu;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t\tvar proxyResult = {\r\n\t\t\tstop: false,\r\n\t\t\tnode: node,\r\n\t\t\tnodeEventType: nodeEventType,\r\n\t\t\tnodeEventCallback: nodeEventCallback,\r\n\t\t\ttreeEventType: treeEventType,\r\n\t\t\ttreeEventCallback: treeEventCallback\r\n\t\t};\r\n\t\treturn proxyResult\r\n\t},\r\n\t//default init node of core\r\n\t_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (!n) return;\r\n\t\tvar r = data.getRoot(setting),\r\n\t\tchildKey = setting.data.key.children;\r\n\t\tn.level = level;\r\n\t\tn.tId = setting.treeId + \"_\" + (++r.zId);\r\n\t\tn.parentTId = parentNode ? parentNode.tId : null;\r\n\t\tif (n[childKey] && n[childKey].length > 0) {\r\n\t\t\tif (typeof n.open == \"string\") n.open = tools.eqs(n.open, \"true\");\r\n\t\t\tn.open = !!n.open;\r\n\t\t\tn.isParent = true;\r\n\t\t\tn.zAsync = true;\r\n\t\t} else {\r\n\t\t\tn.open = false;\r\n\t\t\tif (typeof n.isParent == \"string\") n.isParent = tools.eqs(n.isParent, \"true\");\r\n\t\t\tn.isParent = !!n.isParent;\r\n\t\t\tn.zAsync = !n.isParent;\r\n\t\t}\r\n\t\tn.isFirstNode = isFirstNode;\r\n\t\tn.isLastNode = isLastNode;\r\n\t\tn.getParentNode = function() {return data.getNodeCache(setting, n.parentTId);};\r\n\t\tn.getPreNode = function() {return data.getPreNode(setting, n);};\r\n\t\tn.getNextNode = function() {return data.getNextNode(setting, n);};\r\n\t\tn.isAjaxing = false;\r\n\t\tdata.fixPIdKeyValue(setting, n);\r\n\t},\r\n\t_init = {\r\n\t\tbind: [_bindEvent],\r\n\t\tunbind: [_unbindEvent],\r\n\t\tcaches: [_initCache],\r\n\t\tnodes: [_initNode],\r\n\t\tproxys: [_eventProxy],\r\n\t\troots: [_initRoot],\r\n\t\tbeforeA: [],\r\n\t\tafterA: [],\r\n\t\tinnerBeforeA: [],\r\n\t\tinnerAfterA: [],\r\n\t\tzTreeTools: []\r\n\t},\r\n\t//method of operate data\r\n\tdata = {\r\n\t\taddNodeCache: function(setting, node) {\r\n\t\t\tdata.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node;\r\n\t\t},\r\n\t\tgetNodeCacheId: function(tId) {\r\n\t\t\treturn tId.substring(tId.lastIndexOf(\"_\")+1);\r\n\t\t},\r\n\t\taddAfterA: function(afterA) {\r\n\t\t\t_init.afterA.push(afterA);\r\n\t\t},\r\n\t\taddBeforeA: function(beforeA) {\r\n\t\t\t_init.beforeA.push(beforeA);\r\n\t\t},\r\n\t\taddInnerAfterA: function(innerAfterA) {\r\n\t\t\t_init.innerAfterA.push(innerAfterA);\r\n\t\t},\r\n\t\taddInnerBeforeA: function(innerBeforeA) {\r\n\t\t\t_init.innerBeforeA.push(innerBeforeA);\r\n\t\t},\r\n\t\taddInitBind: function(bindEvent) {\r\n\t\t\t_init.bind.push(bindEvent);\r\n\t\t},\r\n\t\taddInitUnBind: function(unbindEvent) {\r\n\t\t\t_init.unbind.push(unbindEvent);\r\n\t\t},\r\n\t\taddInitCache: function(initCache) {\r\n\t\t\t_init.caches.push(initCache);\r\n\t\t},\r\n\t\taddInitNode: function(initNode) {\r\n\t\t\t_init.nodes.push(initNode);\r\n\t\t},\r\n\t\taddInitProxy: function(initProxy) {\r\n\t\t\t_init.proxys.push(initProxy);\r\n\t\t},\r\n\t\taddInitRoot: function(initRoot) {\r\n\t\t\t_init.roots.push(initRoot);\r\n\t\t},\r\n\t\taddNodesData: function(setting, parentNode, nodes) {\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (!parentNode[childKey]) parentNode[childKey] = [];\r\n\t\t\tif (parentNode[childKey].length > 0) {\r\n\t\t\t\tparentNode[childKey][parentNode[childKey].length - 1].isLastNode = false;\r\n\t\t\t\tview.setNodeLineIcos(setting, parentNode[childKey][parentNode[childKey].length - 1]);\r\n\t\t\t}\r\n\t\t\tparentNode.isParent = true;\r\n\t\t\tparentNode[childKey] = parentNode[childKey].concat(nodes);\r\n\t\t},\r\n\t\taddSelectedNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tif (!data.isSelectedNode(setting, node)) {\r\n\t\t\t\troot.curSelectedList.push(node);\r\n\t\t\t}\r\n\t\t},\r\n\t\taddCreatedNode: function(setting, node) {\r\n\t\t\tif (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {\r\n\t\t\t\tvar root = data.getRoot(setting);\r\n\t\t\t\troot.createdNodes.push(node);\r\n\t\t\t}\r\n\t\t},\r\n\t\taddZTreeTools: function(zTreeTools) {\r\n\t\t\t_init.zTreeTools.push(zTreeTools);\r\n\t\t},\r\n\t\texSetting: function(s) {\r\n\t\t\t$.extend(true, _setting, s);\r\n\t\t},\r\n\t\tfixPIdKeyValue: function(setting, node) {\r\n\t\t\tif (setting.data.simpleData.enable) {\r\n\t\t\t\tnode[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId;\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetAfterA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.afterA.length; i<j; i++) {\r\n\t\t\t\t_init.afterA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetBeforeA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.beforeA.length; i<j; i++) {\r\n\t\t\t\t_init.beforeA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetInnerAfterA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.innerAfterA.length; i<j; i++) {\r\n\t\t\t\t_init.innerAfterA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetInnerBeforeA: function(setting, node, array) {\r\n\t\t\tfor (var i=0, j=_init.innerBeforeA.length; i<j; i++) {\r\n\t\t\t\t_init.innerBeforeA[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tgetCache: function(setting) {\r\n\t\t\treturn caches[setting.treeId];\r\n\t\t},\r\n\t\tgetNextNode: function(setting, node) {\r\n\t\t\tif (!node) return null;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tp = node.parentTId ? node.getParentNode() : data.getRoot(setting);\r\n\t\t\tfor (var i=0, l=p[childKey].length-1; i<=l; i++) {\r\n\t\t\t\tif (p[childKey][i] === node) {\r\n\t\t\t\t\treturn (i==l ? null : p[childKey][i+1]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tgetNodeByParam: function(setting, nodes, key, value) {\r\n\t\t\tif (!nodes || !key) return null;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i][key] == value) {\r\n\t\t\t\t\treturn nodes[i];\r\n\t\t\t\t}\r\n\t\t\t\tvar tmp = data.getNodeByParam(setting, nodes[i][childKey], key, value);\r\n\t\t\t\tif (tmp) return tmp;\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tgetNodeCache: function(setting, tId) {\r\n\t\t\tif (!tId) return null;\r\n\t\t\tvar n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)];\r\n\t\t\treturn n ? n : null;\r\n\t\t},\r\n\t\tgetNodeName: function(setting, node) {\r\n\t\t\tvar nameKey = setting.data.key.name;\r\n\t\t\treturn \"\" + node[nameKey];\r\n\t\t},\r\n\t\tgetNodeTitle: function(setting, node) {\r\n\t\t\tvar t = setting.data.key.title === \"\" ? setting.data.key.name : setting.data.key.title;\r\n\t\t\treturn \"\" + node[t];\r\n\t\t},\r\n\t\tgetNodes: function(setting) {\r\n\t\t\treturn data.getRoot(setting)[setting.data.key.children];\r\n\t\t},\r\n\t\tgetNodesByParam: function(setting, nodes, key, value) {\r\n\t\t\tif (!nodes || !key) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tresult = [];\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i][key] == value) {\r\n\t\t\t\t\tresult.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tresult = result.concat(data.getNodesByParam(setting, nodes[i][childKey], key, value));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tgetNodesByParamFuzzy: function(setting, nodes, key, value) {\r\n\t\t\tif (!nodes || !key) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tresult = [];\r\n\t\t\tvalue = value.toLowerCase();\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (typeof nodes[i][key] == \"string\" && nodes[i][key].toLowerCase().indexOf(value)>-1) {\r\n\t\t\t\t\tresult.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tresult = result.concat(data.getNodesByParamFuzzy(setting, nodes[i][childKey], key, value));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tgetNodesByFilter: function(setting, nodes, filter, isSingle, invokeParam) {\r\n\t\t\tif (!nodes) return (isSingle ? null : []);\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tresult = isSingle ? null : [];\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (tools.apply(filter, [nodes[i], invokeParam], false)) {\r\n\t\t\t\t\tif (isSingle) {return nodes[i];}\r\n\t\t\t\t\tresult.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tvar tmpResult = data.getNodesByFilter(setting, nodes[i][childKey], filter, isSingle, invokeParam);\r\n\t\t\t\tif (isSingle && !!tmpResult) {return tmpResult;}\r\n\t\t\t\tresult = isSingle ? tmpResult : result.concat(tmpResult);\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tgetPreNode: function(setting, node) {\r\n\t\t\tif (!node) return null;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tp = node.parentTId ? node.getParentNode() : data.getRoot(setting);\r\n\t\t\tfor (var i=0, l=p[childKey].length; i<l; i++) {\r\n\t\t\t\tif (p[childKey][i] === node) {\r\n\t\t\t\t\treturn (i==0 ? null : p[childKey][i-1]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tgetRoot: function(setting) {\r\n\t\t\treturn setting ? roots[setting.treeId] : null;\r\n\t\t},\r\n\t\tgetSetting: function(treeId) {\r\n\t\t\treturn settings[treeId];\r\n\t\t},\r\n\t\tgetSettings: function() {\r\n\t\t\treturn settings;\r\n\t\t},\r\n\t\tgetZTreeTools: function(treeId) {\r\n\t\t\tvar r = this.getRoot(this.getSetting(treeId));\r\n\t\t\treturn r ? r.treeTools : null;\r\n\t\t},\r\n\t\tinitCache: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.caches.length; i<j; i++) {\r\n\t\t\t\t_init.caches[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tinitNode: function(setting, level, node, parentNode, preNode, nextNode) {\r\n\t\t\tfor (var i=0, j=_init.nodes.length; i<j; i++) {\r\n\t\t\t\t_init.nodes[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tinitRoot: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.roots.length; i<j; i++) {\r\n\t\t\t\t_init.roots[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tisSelectedNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tfor (var i=0, j=root.curSelectedList.length; i<j; i++) {\r\n\t\t\t\tif(node === root.curSelectedList[i]) return true;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t},\r\n\t\tremoveNodeCache: function(setting, node) {\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (node[childKey]) {\r\n\t\t\t\tfor (var i=0, l=node[childKey].length; i<l; i++) {\r\n\t\t\t\t\targuments.callee(setting, node[childKey][i]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tdata.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null;\r\n\t\t},\r\n\t\tremoveSelectedNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tfor (var i=0, j=root.curSelectedList.length; i<j; i++) {\r\n\t\t\t\tif(node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) {\r\n\t\t\t\t\troot.curSelectedList.splice(i, 1);\r\n\t\t\t\t\ti--;j--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetCache: function(setting, cache) {\r\n\t\t\tcaches[setting.treeId] = cache;\r\n\t\t},\r\n\t\tsetRoot: function(setting, root) {\r\n\t\t\troots[setting.treeId] = root;\r\n\t\t},\r\n\t\tsetZTreeTools: function(setting, zTreeTools) {\r\n\t\t\tfor (var i=0, j=_init.zTreeTools.length; i<j; i++) {\r\n\t\t\t\t_init.zTreeTools[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\ttransformToArrayFormat: function (setting, nodes) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tr = [];\r\n\t\t\tif (tools.isArray(nodes)) {\r\n\t\t\t\tfor (var i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\tr.push(nodes[i]);\r\n\t\t\t\t\tif (nodes[i][childKey])\r\n\t\t\t\t\t\tr = r.concat(data.transformToArrayFormat(setting, nodes[i][childKey]));\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tr.push(nodes);\r\n\t\t\t\tif (nodes[childKey])\r\n\t\t\t\t\tr = r.concat(data.transformToArrayFormat(setting, nodes[childKey]));\r\n\t\t\t}\r\n\t\t\treturn r;\r\n\t\t},\r\n\t\ttransformTozTreeFormat: function(setting, sNodes) {\r\n\t\t\tvar i,l,\r\n\t\t\tkey = setting.data.simpleData.idKey,\r\n\t\t\tparentKey = setting.data.simpleData.pIdKey,\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tif (!key || key==\"\" || !sNodes) return [];\r\n\r\n\t\t\tif (tools.isArray(sNodes)) {\r\n\t\t\t\tvar r = [];\r\n\t\t\t\tvar tmpMap = [];\r\n\t\t\t\tfor (i=0, l=sNodes.length; i<l; i++) {\r\n\t\t\t\t\ttmpMap[sNodes[i][key]] = sNodes[i];\r\n\t\t\t\t}\r\n\t\t\t\tfor (i=0, l=sNodes.length; i<l; i++) {\r\n\t\t\t\t\tif (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] != sNodes[i][parentKey]) {\r\n\t\t\t\t\t\tif (!tmpMap[sNodes[i][parentKey]][childKey])\r\n\t\t\t\t\t\t\ttmpMap[sNodes[i][parentKey]][childKey] = [];\r\n\t\t\t\t\t\ttmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tr.push(sNodes[i]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn r;\r\n\t\t\t}else {\r\n\t\t\t\treturn [sNodes];\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of event proxy\r\n\tevent = {\r\n\t\tbindEvent: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.bind.length; i<j; i++) {\r\n\t\t\t\t_init.bind[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tunbindEvent: function(setting) {\r\n\t\t\tfor (var i=0, j=_init.unbind.length; i<j; i++) {\r\n\t\t\t\t_init.unbind[i].apply(this, arguments);\r\n\t\t\t}\r\n\t\t},\r\n\t\tbindTree: function(setting) {\r\n\t\t\tvar eventParam = {\r\n\t\t\t\ttreeId: setting.treeId\r\n\t\t\t},\r\n\t\t\to = setting.treeObj;\r\n\t\t\t// for can't select text\r\n\t\t\to.bind('selectstart', function(e){\r\n\t\t\t\t\tvar n = e.originalEvent.srcElement.nodeName.toLowerCase();\r\n\t\t\t\t\treturn (n === \"input\" || n === \"textarea\" );\r\n\t\t\t}).css({\r\n\t\t\t\t\"-moz-user-select\":\"-moz-none\"\r\n\t\t\t});\r\n\t\t\to.bind('click', eventParam, event.proxy);\r\n\t\t\to.bind('dblclick', eventParam, event.proxy);\r\n\t\t\to.bind('mouseover', eventParam, event.proxy);\r\n\t\t\to.bind('mouseout', eventParam, event.proxy);\r\n\t\t\to.bind('mousedown', eventParam, event.proxy);\r\n\t\t\to.bind('mouseup', eventParam, event.proxy);\r\n\t\t\to.bind('contextmenu', eventParam, event.proxy);\r\n\t\t},\r\n\t\tunbindTree: function(setting) {\r\n\t\t\tvar o = setting.treeObj;\r\n\t\t\to.unbind('click', event.proxy)\r\n\t\t\t.unbind('dblclick', event.proxy)\r\n\t\t\t.unbind('mouseover', event.proxy)\r\n\t\t\t.unbind('mouseout', event.proxy)\r\n\t\t\t.unbind('mousedown', event.proxy)\r\n\t\t\t.unbind('mouseup', event.proxy)\r\n\t\t\t.unbind('contextmenu', event.proxy);\r\n\t\t},\r\n\t\tdoProxy: function(e) {\r\n\t\t\tvar results = [];\r\n\t\t\tfor (var i=0, j=_init.proxys.length; i<j; i++) {\r\n\t\t\t\tvar proxyResult = _init.proxys[i].apply(this, arguments);\r\n\t\t\t\tresults.push(proxyResult);\r\n\t\t\t\tif (proxyResult.stop) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn results;\r\n\t\t},\r\n\t\tproxy: function(e) {\r\n\t\t\tvar setting = data.getSetting(e.data.treeId);\r\n\t\t\tif (!tools.uCanDo(setting, e)) return true;\r\n\t\t\tvar results = event.doProxy(e),\r\n\t\t\tr = true, x = false;\r\n\t\t\tfor (var i=0, l=results.length; i<l; i++) {\r\n\t\t\t\tvar proxyResult = results[i];\r\n\t\t\t\tif (proxyResult.nodeEventCallback) {\r\n\t\t\t\t\tx = true;\r\n\t\t\t\t\tr = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;\r\n\t\t\t\t}\r\n\t\t\t\tif (proxyResult.treeEventCallback) {\r\n\t\t\t\t\tx = true;\r\n\t\t\t\t\tr = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn r;\r\n\t\t}\r\n\t},\r\n\t//method of event handler\r\n\thandler = {\r\n\t\tonSwitchNode: function (event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (node.open) {\r\n\t\t\t\tif (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true;\r\n\t\t\t\tdata.getRoot(setting).expandTriggerFlag = true;\r\n\t\t\t\tview.switchNode(setting, node);\r\n\t\t\t} else {\r\n\t\t\t\tif (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true;\r\n\t\t\t\tdata.getRoot(setting).expandTriggerFlag = true;\r\n\t\t\t\tview.switchNode(setting, node);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonClickNode: function (event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tclickFlag = ( (setting.view.autoCancelSelected && event.ctrlKey) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && event.ctrlKey && setting.view.selectedMulti) ? 2 : 1;\r\n\t\t\tif (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true;\r\n\t\t\tif (clickFlag === 0) {\r\n\t\t\t\tview.cancelPreSelectedNode(setting, node);\r\n\t\t\t} else {\r\n\t\t\t\tview.selectNode(setting, node, clickFlag === 2);\r\n\t\t\t}\r\n\t\t\tsetting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]);\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeMousedown: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeMouseup: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeDblclick: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onDblClick, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonZTreeContextmenu: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId);\r\n\t\t\tif (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) {\r\n\t\t\t\ttools.apply(setting.callback.onRightClick, [event, setting.treeId, node]);\r\n\t\t\t}\r\n\t\t\treturn (typeof setting.callback.onRightClick) != \"function\";\r\n\t\t}\r\n\t},\r\n\t//method of tools for zTree\r\n\ttools = {\r\n\t\tapply: function(fun, param, defaultValue) {\r\n\t\t\tif ((typeof fun) == \"function\") {\r\n\t\t\t\treturn fun.apply(zt, param?param:[]);\r\n\t\t\t}\r\n\t\t\treturn defaultValue;\r\n\t\t},\r\n\t\tcanAsync: function(setting, node) {\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\treturn (setting.async.enable && node && node.isParent && !(node.zAsync || (node[childKey] && node[childKey].length > 0)));\r\n\t\t},\r\n\t\tclone: function (obj){\r\n\t\t\tif (obj === null) return null;\r\n\t\t\tvar o = obj.constructor === Array ? [] : {};\r\n\t\t\tfor(var i in obj){\r\n\t\t\t\to[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === \"object\" ? arguments.callee(obj[i]) : obj[i]);\r\n\t\t\t}\r\n\t\t\treturn o;\r\n\t\t},\r\n\t\teqs: function(str1, str2) {\r\n\t\t\treturn str1.toLowerCase() === str2.toLowerCase();\r\n\t\t},\r\n\t\tisArray: function(arr) {\r\n\t\t\treturn Object.prototype.toString.apply(arr) === \"[object Array]\";\r\n\t\t},\r\n\t\tgetMDom: function (setting, curDom, targetExpr) {\r\n\t\t\tif (!curDom) return null;\r\n\t\t\twhile (curDom && curDom.id !== setting.treeId) {\r\n\t\t\t\tfor (var i=0, l=targetExpr.length; curDom.tagName && i<l; i++) {\r\n\t\t\t\t\tif (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) {\r\n\t\t\t\t\t\treturn curDom;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcurDom = curDom.parentNode;\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t},\r\n\t\tuCanDo: function(setting, e) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t},\r\n\t//method of operate ztree dom\r\n\tview = {\r\n\t\taddNodes: function(setting, parentNode, newNodes, isSilent) {\r\n\t\t\tif (setting.data.keep.leaf && parentNode && !parentNode.isParent) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!tools.isArray(newNodes)) {\r\n\t\t\t\tnewNodes = [newNodes];\r\n\t\t\t}\r\n\t\t\tif (setting.data.simpleData.enable) {\r\n\t\t\t\tnewNodes = data.transformTozTreeFormat(setting, newNodes);\r\n\t\t\t}\r\n\t\t\tif (parentNode) {\r\n\t\t\t\tvar target_switchObj = $(\"#\" + parentNode.tId + consts.id.SWITCH),\r\n\t\t\t\ttarget_icoObj = $(\"#\" + parentNode.tId + consts.id.ICON),\r\n\t\t\t\ttarget_ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\r\n\t\t\t\tif (!parentNode.open) {\r\n\t\t\t\t\tview.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE);\r\n\t\t\t\t\tview.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE);\r\n\t\t\t\t\tparentNode.open = false;\r\n\t\t\t\t\ttarget_ulObj.css({\r\n\t\t\t\t\t\t\"display\": \"none\"\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdata.addNodesData(setting, parentNode, newNodes);\r\n\t\t\t\tview.createNodes(setting, parentNode.level + 1, newNodes, parentNode);\r\n\t\t\t\tif (!isSilent) {\r\n\t\t\t\t\tview.expandCollapseParentNode(setting, parentNode, true);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tdata.addNodesData(setting, data.getRoot(setting), newNodes);\r\n\t\t\t\tview.createNodes(setting, 0, newNodes, null);\r\n\t\t\t}\r\n\t\t},\r\n\t\tappendNodes: function(setting, level, nodes, parentNode, initFlag, openFlag) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar html = [],\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tvar node = nodes[i];\r\n\t\t\t\tif (initFlag) {\r\n\t\t\t\t\tvar tmpPNode = (parentNode) ? parentNode: data.getRoot(setting),\r\n\t\t\t\t\ttmpPChild = tmpPNode[childKey],\r\n\t\t\t\t\tisFirstNode = ((tmpPChild.length == nodes.length) && (i == 0)),\r\n\t\t\t\t\tisLastNode = (i == (nodes.length - 1));\r\n\t\t\t\t\tdata.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag);\r\n\t\t\t\t\tdata.addNodeCache(setting, node);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar childHtml = [];\r\n\t\t\t\tif (node[childKey] && node[childKey].length > 0) {\r\n\t\t\t\t\t//make child html first, because checkType\r\n\t\t\t\t\tchildHtml = view.appendNodes(setting, level + 1, node[childKey], node, initFlag, openFlag && node.open);\r\n\t\t\t\t}\r\n\t\t\t\tif (openFlag) {\r\n\t\t\t\t\t\r\n\t\t\t\t\tview.makeDOMNodeMainBefore(html, setting, node);\r\n\t\t\t\t\tview.makeDOMNodeLine(html, setting, node);\r\n\t\t\t\t\tdata.getBeforeA(setting, node, html);\r\n\t\t\t\t\tview.makeDOMNodeNameBefore(html, setting, node);\r\n\t\t\t\t\tdata.getInnerBeforeA(setting, node, html);\r\n\t\t\t\t\tview.makeDOMNodeIcon(html, setting, node);\r\n\t\t\t\t\tdata.getInnerAfterA(setting, node, html);\r\n\t\t\t\t\tview.makeDOMNodeNameAfter(html, setting, node);\r\n\t\t\t\t\tdata.getAfterA(setting, node, html);\r\n\t\t\t\t\tif (node.isParent && node.open) {\r\n\t\t\t\t\t\tview.makeUlHtml(setting, node, html, childHtml.join(''));\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.makeDOMNodeMainAfter(html, setting, node);\r\n\t\t\t\t\tdata.addCreatedNode(setting, node);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn html;\r\n\t\t},\r\n\t\tappendParentULDom: function(setting, node) {\r\n\t\t\tvar html = [],\r\n\t\t\tnObj = $(\"#\" + node.tId),\r\n\t\t\tulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\tchildHtml = view.appendNodes(setting, node.level+1, node[childKey], node, false, true);\r\n\t\t\tview.makeUlHtml(setting, node, html, childHtml.join(''));\r\n\t\t\tif (!nObj.get(0) && !!node.parentTId) {\r\n\t\t\t\tview.appendParentULDom(setting, node.getParentNode());\r\n\t\t\t\tnObj = $(\"#\" + node.tId);\r\n\t\t\t}\r\n\t\t\tif (ulObj.get(0)) {\r\n\t\t\t\tulObj.remove();\r\n\t\t\t}\r\n\t\t\tnObj.append(html.join(''));\r\n\t\t},\r\n\t\tasyncNode: function(setting, node, isSilent, callback) {\r\n\t\t\tvar i, l;\r\n\t\t\tif (node && !node.isParent) {\r\n\t\t\t\ttools.apply(callback);\r\n\t\t\t\treturn false;\r\n\t\t\t} else if (node && node.isAjaxing) {\r\n\t\t\t\treturn false;\r\n\t\t\t} else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) {\r\n\t\t\t\ttools.apply(callback);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tif (node) {\r\n\t\t\t\tnode.isAjaxing = true;\r\n\t\t\t\tvar icoObj = $(\"#\" + node.tId + consts.id.ICON);\r\n\t\t\t\ticoObj.attr({\"style\":\"\", \"class\":consts.className.BUTTON + \" \" + consts.className.ICO_LOADING});\r\n\t\t\t}\r\n\r\n\t\t\tvar tmpParam = {};\r\n\t\t\tfor (i = 0, l = setting.async.autoParam.length; node && i < l; i++) {\r\n\t\t\t\tvar pKey = setting.async.autoParam[i].split(\"=\"), spKey = pKey;\r\n\t\t\t\tif (pKey.length>1) {\r\n\t\t\t\t\tspKey = pKey[1];\r\n\t\t\t\t\tpKey = pKey[0];\r\n\t\t\t\t}\r\n\t\t\t\ttmpParam[spKey] = node[pKey];\r\n\t\t\t}\r\n\t\t\tif (tools.isArray(setting.async.otherParam)) {\r\n\t\t\t\tfor (i = 0, l = setting.async.otherParam.length; i < l; i += 2) {\r\n\t\t\t\t\ttmpParam[setting.async.otherParam[i]] = setting.async.otherParam[i + 1];\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tfor (var p in setting.async.otherParam) {\r\n\t\t\t\t\ttmpParam[p] = setting.async.otherParam[p];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar _tmpV = data.getRoot(setting)._ver;\r\n\t\t\t$.ajax({\r\n\t\t\t\tcontentType: setting.async.contentType,\r\n\t\t\t\ttype: setting.async.type,\r\n\t\t\t\turl: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url),\r\n\t\t\t\tdata: tmpParam,\r\n\t\t\t\tdataType: setting.async.dataType,\r\n\t\t\t\tsuccess: function(msg) {\r\n\t\t\t\t\tif (_tmpV != data.getRoot(setting)._ver) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tvar newNodes = [];\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (!msg || msg.length == 0) {\r\n\t\t\t\t\t\t\tnewNodes = [];\r\n\t\t\t\t\t\t} else if (typeof msg == \"string\") {\r\n\t\t\t\t\t\t\tnewNodes = eval(\"(\" + msg + \")\");\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tnewNodes = msg;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} catch(err) {\r\n\t\t\t\t\t\tnewNodes = msg;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (node) {\r\n\t\t\t\t\t\tnode.isAjaxing = null;\r\n\t\t\t\t\t\tnode.zAsync = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.setNodeLineIcos(setting, node);\r\n\t\t\t\t\tif (newNodes && newNodes !== \"\") {\r\n\t\t\t\t\t\tnewNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes);\r\n\t\t\t\t\t\tview.addNodes(setting, node, !!newNodes ? tools.clone(newNodes) : [], !!isSilent);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tview.addNodes(setting, node, [], !!isSilent);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]);\r\n\t\t\t\t\ttools.apply(callback);\r\n\t\t\t\t},\r\n\t\t\t\terror: function(XMLHttpRequest, textStatus, errorThrown) {\r\n\t\t\t\t\tif (_tmpV != data.getRoot(setting)._ver) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (node) node.isAjaxing = null;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, node);\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tcancelPreSelectedNode: function (setting, node) {\r\n\t\t\tvar list = data.getRoot(setting).curSelectedList;\r\n\t\t\tfor (var i=0, j=list.length-1; j>=i; j--) {\r\n\t\t\t\tif (!node || node === list[j]) {\r\n\t\t\t\t\t$(\"#\" + list[j].tId + consts.id.A).removeClass(consts.node.CURSELECTED);\r\n\t\t\t\t\tif (node) {\r\n\t\t\t\t\t\tdata.removeSelectedNode(setting, node);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!node) data.getRoot(setting).curSelectedList = [];\r\n\t\t},\r\n\t\tcreateNodeCallback: function(setting) {\r\n\t\t\tif (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {\r\n\t\t\t\tvar root = data.getRoot(setting);\r\n\t\t\t\twhile (root.createdNodes.length>0) {\r\n\t\t\t\t\tvar node = root.createdNodes.shift();\r\n\t\t\t\t\ttools.apply(setting.view.addDiyDom, [setting.treeId, node]);\r\n\t\t\t\t\tif (!!setting.callback.onNodeCreated) {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tcreateNodes: function(setting, level, nodes, parentNode) {\r\n\t\t\tif (!nodes || nodes.length == 0) return;\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\topenFlag = !parentNode || parentNode.open || !!$(\"#\" + parentNode[childKey][0].tId).get(0);\r\n\t\t\troot.createdNodes = [];\r\n\t\t\tvar zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, true, openFlag);\r\n\t\t\tif (!parentNode) {\r\n\t\t\t\tsetting.treeObj.append(zTreeHtml.join(''));\r\n\t\t\t} else {\r\n\t\t\t\tvar ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\t\t\t\tif (ulObj.get(0)) {\r\n\t\t\t\t\tulObj.append(zTreeHtml.join(''));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tview.createNodeCallback(setting);\r\n\t\t},\r\n\t\tdestroy: function(setting) {\r\n\t\t\tif (!setting) return;\r\n\t\t\tdata.initCache(setting);\r\n\t\t\tdata.initRoot(setting);\r\n\t\t\tevent.unbindTree(setting);\r\n\t\t\tevent.unbindEvent(setting);\r\n\t\t\tsetting.treeObj.empty();\r\n\t\t},\r\n\t\texpandCollapseNode: function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tif (!node) {\r\n\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (root.expandTriggerFlag) {\r\n\t\t\t\tvar _callback = callback;\r\n\t\t\t\tcallback = function(){\r\n\t\t\t\t\tif (_callback) _callback();\r\n\t\t\t\t\tif (node.open) {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\t\t\t\troot.expandTriggerFlag = false;\r\n\t\t\t}\r\n\t\t\tif (!node.open && node.isParent && ((!$(\"#\" + node.tId + consts.id.UL).get(0)) || (node[childKey] && node[childKey].length>0 && !$(\"#\" + node[childKey][0].tId).get(0)))) {\r\n\t\t\t\tview.appendParentULDom(setting, node);\r\n\t\t\t\tview.createNodeCallback(setting);\r\n\t\t\t}\r\n\t\t\tif (node.open == expandFlag) {\r\n\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar ulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\tswitchObj = $(\"#\" + node.tId + consts.id.SWITCH),\r\n\t\t\ticoObj = $(\"#\" + node.tId + consts.id.ICON);\r\n\r\n\t\t\tif (node.isParent) {\r\n\t\t\t\tnode.open = !node.open;\r\n\t\t\t\tif (node.iconOpen && node.iconClose) {\r\n\t\t\t\t\ticoObj.attr(\"style\", view.makeNodeIcoStyle(setting, node));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (node.open) {\r\n\t\t\t\t\tview.replaceSwitchClass(node, switchObj, consts.folder.OPEN);\r\n\t\t\t\t\tview.replaceIcoClass(node, icoObj, consts.folder.OPEN);\r\n\t\t\t\t\tif (animateFlag == false || setting.view.expandSpeed == \"\") {\r\n\t\t\t\t\t\tulObj.show();\r\n\t\t\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (node[childKey] && node[childKey].length > 0) {\r\n\t\t\t\t\t\t\tulObj.slideDown(setting.view.expandSpeed, callback);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tulObj.show();\r\n\t\t\t\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tview.replaceSwitchClass(node, switchObj, consts.folder.CLOSE);\r\n\t\t\t\t\tview.replaceIcoClass(node, icoObj, consts.folder.CLOSE);\r\n\t\t\t\t\tif (animateFlag == false || setting.view.expandSpeed == \"\" || !(node[childKey] && node[childKey].length > 0)) {\r\n\t\t\t\t\t\tulObj.hide();\r\n\t\t\t\t\t\ttools.apply(callback, []);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tulObj.slideUp(setting.view.expandSpeed, callback);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\ttools.apply(callback, []);\r\n\t\t\t}\r\n\t\t},\r\n\t\texpandCollapseParentNode: function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tif (!node) return;\r\n\t\t\tif (!node.parentTId) {\r\n\t\t\t\tview.expandCollapseNode(setting, node, expandFlag, animateFlag, callback);\r\n\t\t\t\treturn;\r\n\t\t\t} else {\r\n\t\t\t\tview.expandCollapseNode(setting, node, expandFlag, animateFlag);\r\n\t\t\t}\r\n\t\t\tif (node.parentTId) {\r\n\t\t\t\tview.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback);\r\n\t\t\t}\r\n\t\t},\r\n\t\texpandCollapseSonNode: function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\ttreeNodes = (node) ? node[childKey]: root[childKey],\r\n\t\t\tselfAnimateSign = (node) ? false : animateFlag,\r\n\t\t\texpandTriggerFlag = data.getRoot(setting).expandTriggerFlag;\r\n\t\t\tdata.getRoot(setting).expandTriggerFlag = false;\r\n\t\t\tif (treeNodes) {\r\n\t\t\t\tfor (var i = 0, l = treeNodes.length; i < l; i++) {\r\n\t\t\t\t\tif (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tdata.getRoot(setting).expandTriggerFlag = expandTriggerFlag;\r\n\t\t\tview.expandCollapseNode(setting, node, expandFlag, animateFlag, callback );\r\n\t\t},\r\n\t\tmakeDOMNodeIcon: function(html, setting, node) {\r\n\t\t\tvar nameStr = data.getNodeName(setting, node),\r\n\t\t\tname = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\r\n\t\t\thtml.push(\"<span id='\", node.tId, consts.id.ICON,\r\n\t\t\t\t\"' title='' treeNode\", consts.id.ICON,\" class='\", view.makeNodeIcoClass(setting, node),\r\n\t\t\t\t\"' style='\", view.makeNodeIcoStyle(setting, node), \"'></span><span id='\", node.tId, consts.id.SPAN,\r\n\t\t\t\t\"'>\",name,\"</span>\");\r\n\t\t},\r\n\t\tmakeDOMNodeLine: function(html, setting, node) {\r\n\t\t\thtml.push(\"<span id='\", node.tId, consts.id.SWITCH,\t\"' title='' class='\", view.makeNodeLineClass(setting, node), \"' treeNode\", consts.id.SWITCH,\"></span>\");\r\n\t\t},\r\n\t\tmakeDOMNodeMainAfter: function(html, setting, node) {\r\n\t\t\thtml.push(\"</li>\");\r\n\t\t},\r\n\t\tmakeDOMNodeMainBefore: function(html, setting, node) {\r\n\t\t\thtml.push(\"<li id='\", node.tId, \"' class='\", consts.className.LEVEL, node.level,\"' tabindex='0' hidefocus='true' treenode>\");\r\n\t\t},\r\n\t\tmakeDOMNodeNameAfter: function(html, setting, node) {\r\n\t\t\thtml.push(\"</a>\");\r\n\t\t},\r\n\t\tmakeDOMNodeNameBefore: function(html, setting, node) {\r\n\t\t\tvar title = data.getNodeTitle(setting, node),\r\n\t\t\turl = view.makeNodeUrl(setting, node),\r\n\t\t\tfontcss = view.makeNodeFontCss(setting, node),\r\n\t\t\tfontStyle = [];\r\n\t\t\tfor (var f in fontcss) {\r\n\t\t\t\tfontStyle.push(f, \":\", fontcss[f], \";\");\r\n\t\t\t}\r\n\t\t\thtml.push(\"<a id='\", node.tId, consts.id.A, \"' class='\", consts.className.LEVEL, node.level,\"' treeNode\", consts.id.A,\" onclick=\\\"\", (node.click || ''),\r\n\t\t\t\t\"\\\" \", ((url != null && url.length > 0) ? \"href='\" + url + \"'\" : \"\"), \" target='\",view.makeNodeTarget(node),\"' style='\", fontStyle.join(''),\r\n\t\t\t\t\"'\");\r\n\t\t\tif (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) {html.push(\"title='\", title.replace(/'/g,\"&#39;\").replace(/</g,'&lt;').replace(/>/g,'&gt;'),\"'\");}\r\n\t\t\thtml.push(\">\");\r\n\t\t},\r\n\t\tmakeNodeFontCss: function(setting, node) {\r\n\t\t\tvar fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss);\r\n\t\t\treturn (fontCss && ((typeof fontCss) != \"function\")) ? fontCss : {};\r\n\t\t},\r\n\t\tmakeNodeIcoClass: function(setting, node) {\r\n\t\t\tvar icoCss = [\"ico\"];\r\n\t\t\tif (!node.isAjaxing) {\r\n\t\t\t\ticoCss[0] = (node.iconSkin ? node.iconSkin + \"_\" : \"\") + icoCss[0];\r\n\t\t\t\tif (node.isParent) {\r\n\t\t\t\t\ticoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);\r\n\t\t\t\t} else {\r\n\t\t\t\t\ticoCss.push(consts.folder.DOCU);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn consts.className.BUTTON + \" \" + icoCss.join('_');\r\n\t\t},\r\n\t\tmakeNodeIcoStyle: function(setting, node) {\r\n\t\t\tvar icoStyle = [];\r\n\t\t\tif (!node.isAjaxing) {\r\n\t\t\t\tvar icon = (node.isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node.icon;\r\n\t\t\t\tif (icon) icoStyle.push(\"background:url(\", icon, \") 0 0 no-repeat;\");\r\n\t\t\t\tif (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) {\r\n\t\t\t\t\ticoStyle.push(\"width:0px;height:0px;\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn icoStyle.join('');\r\n\t\t},\r\n\t\tmakeNodeLineClass: function(setting, node) {\r\n\t\t\tvar lineClass = [];\r\n\t\t\tif (setting.view.showLine) {\r\n\t\t\t\tif (node.level == 0 && node.isFirstNode && node.isLastNode) {\r\n\t\t\t\t\tlineClass.push(consts.line.ROOT);\r\n\t\t\t\t} else if (node.level == 0 && node.isFirstNode) {\r\n\t\t\t\t\tlineClass.push(consts.line.ROOTS);\r\n\t\t\t\t} else if (node.isLastNode) {\r\n\t\t\t\t\tlineClass.push(consts.line.BOTTOM);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineClass.push(consts.line.CENTER);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tlineClass.push(consts.line.NOLINE);\r\n\t\t\t}\r\n\t\t\tif (node.isParent) {\r\n\t\t\t\tlineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);\r\n\t\t\t} else {\r\n\t\t\t\tlineClass.push(consts.folder.DOCU);\r\n\t\t\t}\r\n\t\t\treturn view.makeNodeLineClassEx(node) + lineClass.join('_');\r\n\t\t},\r\n\t\tmakeNodeLineClassEx: function(node) {\r\n\t\t\treturn consts.className.BUTTON + \" \" + consts.className.LEVEL + node.level + \" \" + consts.className.SWITCH + \" \";\r\n\t\t},\r\n\t\tmakeNodeTarget: function(node) {\r\n\t\t\treturn (node.target || \"_blank\");\r\n\t\t},\r\n\t\tmakeNodeUrl: function(setting, node) {\r\n\t\t\tvar urlKey = setting.data.key.url;\r\n\t\t\treturn node[urlKey] ? node[urlKey] : null;\r\n\t\t},\r\n\t\tmakeUlHtml: function(setting, node, html, content) {\r\n\t\t\thtml.push(\"<ul id='\", node.tId, consts.id.UL, \"' class='\", consts.className.LEVEL, node.level, \" \", view.makeUlLineClass(setting, node), \"' style='display:\", (node.open ? \"block\": \"none\"),\"'>\");\r\n\t\t\thtml.push(content);\r\n\t\t\thtml.push(\"</ul>\");\r\n\t\t},\r\n\t\tmakeUlLineClass: function(setting, node) {\r\n\t\t\treturn ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : \"\");\r\n\t\t},\r\n\t\tremoveChildNodes: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tnodes = node[childKey];\r\n\t\t\tif (!nodes) return;\r\n\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tdata.removeNodeCache(setting, nodes[i]);\r\n\t\t\t}\r\n\t\t\tdata.removeSelectedNode(setting);\r\n\t\t\tdelete node[childKey];\r\n\r\n\t\t\tif (!setting.data.keep.parent) {\r\n\t\t\t\tnode.isParent = false;\r\n\t\t\t\tnode.open = false;\r\n\t\t\t\tvar tmp_switchObj = $(\"#\" + node.tId + consts.id.SWITCH),\r\n\t\t\t\ttmp_icoObj = $(\"#\" + node.tId + consts.id.ICON);\r\n\t\t\t\tview.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU);\r\n\t\t\t\tview.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU);\r\n\t\t\t\t$(\"#\" + node.tId + consts.id.UL).remove();\r\n\t\t\t} else {\r\n\t\t\t\t$(\"#\" + node.tId + consts.id.UL).empty();\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetFirstNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif ( childLength > 0) {\r\n\t\t\t\tparentNode[childKey][0].isFirstNode = true;\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetLastNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif ( childLength > 0) {\r\n\t\t\t\tparentNode[childKey][childLength - 1].isLastNode = true;\r\n\t\t\t}\r\n\t\t},\r\n\t\tremoveNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\tparentNode = (node.parentTId) ? node.getParentNode() : root;\r\n\r\n\t\t\tnode.isFirstNode = false;\r\n\t\t\tnode.isLastNode = false;\r\n\t\t\tnode.getPreNode = function() {return null;};\r\n\t\t\tnode.getNextNode = function() {return null;};\r\n\r\n\t\t\tif (!data.getNodeCache(setting, node.tId)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n                        \r\n\t\t\t$(\"#\" + node.tId).remove();\r\n\t\t\tdata.removeNodeCache(setting, node);\r\n\t\t\tdata.removeSelectedNode(setting, node);\r\n\r\n\t\t\tfor (var i = 0, l = parentNode[childKey].length; i < l; i++) {\r\n\t\t\t\tif (parentNode[childKey][i].tId == node.tId) {\r\n\t\t\t\t\tparentNode[childKey].splice(i, 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tview.setFirstNode(setting, parentNode);\r\n\t\t\tview.setLastNode(setting, parentNode);\r\n                                                \r\n\t\t\tvar tmp_ulObj,tmp_switchObj,tmp_icoObj,\r\n\t\t\tchildLength = parentNode[childKey].length;\r\n\r\n\t\t\t//repair nodes old parent\r\n\t\t\tif (!setting.data.keep.parent && childLength == 0) {\r\n\t\t\t\t//old parentNode has no child nodes\r\n\t\t\t\tparentNode.isParent = false;\r\n\t\t\t\tparentNode.open = false;\r\n\t\t\t\ttmp_ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\t\t\t\ttmp_switchObj = $(\"#\" + parentNode.tId + consts.id.SWITCH);\r\n\t\t\t\ttmp_icoObj = $(\"#\" + parentNode.tId + consts.id.ICON);\r\n\t\t\t\tview.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU);\r\n\t\t\t\tview.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU);\r\n\t\t\t\ttmp_ulObj.css(\"display\", \"none\");\r\n\r\n\t\t\t} else if (setting.view.showLine && childLength > 0) {\r\n\t\t\t\t//old parentNode has child nodes\r\n\t\t\t\tvar newLast = parentNode[childKey][childLength - 1];\r\n\t\t\t\ttmp_ulObj = $(\"#\" + newLast.tId + consts.id.UL);\r\n\t\t\t\ttmp_switchObj = $(\"#\" + newLast.tId + consts.id.SWITCH);\r\n\t\t\t\ttmp_icoObj = $(\"#\" + newLast.tId + consts.id.ICON);\r\n\t\t\t\tif (parentNode == root) {\r\n\t\t\t\t\tif (parentNode[childKey].length == 1) {\r\n\t\t\t\t\t\t//node was root, and ztree has only one root after move node\r\n\t\t\t\t\t\tview.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tvar tmp_first_switchObj = $(\"#\" + parentNode[childKey][0].tId + consts.id.SWITCH);\r\n\t\t\t\t\t\tview.replaceSwitchClass(parentNode[childKey][0], tmp_first_switchObj, consts.line.ROOTS);\r\n\t\t\t\t\t\tview.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tview.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);\r\n\t\t\t\t}\r\n\t\t\t\ttmp_ulObj.removeClass(consts.line.LINE);\r\n\t\t\t}\r\n\t\t},\r\n\t\treplaceIcoClass: function(node, obj, newName) {\r\n\t\t\tif (!obj || node.isAjaxing) return;\r\n\t\t\tvar tmpName = obj.attr(\"class\");\r\n\t\t\tif (tmpName == undefined) return;\r\n\t\t\tvar tmpList = tmpName.split(\"_\");\r\n\t\t\tswitch (newName) {\r\n\t\t\t\tcase consts.folder.OPEN:\r\n\t\t\t\tcase consts.folder.CLOSE:\r\n\t\t\t\tcase consts.folder.DOCU:\r\n\t\t\t\t\ttmpList[tmpList.length-1] = newName;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tobj.attr(\"class\", tmpList.join(\"_\"));\r\n\t\t},\r\n\t\treplaceSwitchClass: function(node, obj, newName) {\r\n\t\t\tif (!obj) return;\r\n\t\t\tvar tmpName = obj.attr(\"class\");\r\n\t\t\tif (tmpName == undefined) return;\r\n\t\t\tvar tmpList = tmpName.split(\"_\");\r\n\t\t\tswitch (newName) {\r\n\t\t\t\tcase consts.line.ROOT:\r\n\t\t\t\tcase consts.line.ROOTS:\r\n\t\t\t\tcase consts.line.CENTER:\r\n\t\t\t\tcase consts.line.BOTTOM:\r\n\t\t\t\tcase consts.line.NOLINE:\r\n\t\t\t\t\ttmpList[0] = view.makeNodeLineClassEx(node) + newName;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase consts.folder.OPEN:\r\n\t\t\t\tcase consts.folder.CLOSE:\r\n\t\t\t\tcase consts.folder.DOCU:\r\n\t\t\t\t\ttmpList[1] = newName;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tobj.attr(\"class\", tmpList.join(\"_\"));\r\n\t\t\tif (newName !== consts.folder.DOCU) {\r\n\t\t\t\tobj.removeAttr(\"disabled\");\r\n\t\t\t} else {\r\n\t\t\t\tobj.attr(\"disabled\", \"disabled\");\r\n\t\t\t}\r\n\t\t},\r\n\t\tselectNode: function(setting, node, addFlag) {\r\n\t\t\tif (!addFlag) {\r\n\t\t\t\tview.cancelPreSelectedNode(setting);\r\n\t\t\t}\r\n\t\t\t$(\"#\" + node.tId + consts.id.A).addClass(consts.node.CURSELECTED);\r\n\t\t\tdata.addSelectedNode(setting, node);\r\n\t\t},\r\n\t\tsetNodeFontCss: function(setting, treeNode) {\r\n\t\t\tvar aObj = $(\"#\" + treeNode.tId + consts.id.A),\r\n\t\t\tfontCss = view.makeNodeFontCss(setting, treeNode);\r\n\t\t\tif (fontCss) {\r\n\t\t\t\taObj.css(fontCss);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetNodeLineIcos: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar switchObj = $(\"#\" + node.tId + consts.id.SWITCH),\r\n\t\t\tulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\ticoObj = $(\"#\" + node.tId + consts.id.ICON),\r\n\t\t\tulLine = view.makeUlLineClass(setting, node);\r\n\t\t\tif (ulLine.length==0) {\r\n\t\t\t\tulObj.removeClass(consts.line.LINE);\r\n\t\t\t} else {\r\n\t\t\t\tulObj.addClass(ulLine);\r\n\t\t\t}\r\n\t\t\tswitchObj.attr(\"class\", view.makeNodeLineClass(setting, node));\r\n\t\t\tif (node.isParent) {\r\n\t\t\t\tswitchObj.removeAttr(\"disabled\");\r\n\t\t\t} else {\r\n\t\t\t\tswitchObj.attr(\"disabled\", \"disabled\");\r\n\t\t\t}\r\n\t\t\ticoObj.removeAttr(\"style\");\r\n\t\t\ticoObj.attr(\"style\", view.makeNodeIcoStyle(setting, node));\r\n\t\t\ticoObj.attr(\"class\", view.makeNodeIcoClass(setting, node));\r\n\t\t},\r\n\t\tsetNodeName: function(setting, node) {\r\n\t\t\tvar title = data.getNodeTitle(setting, node),\r\n\t\t\tnObj = $(\"#\" + node.tId + consts.id.SPAN);\r\n\t\t\tnObj.empty();\r\n\t\t\tif (setting.view.nameIsHTML) {\r\n\t\t\t\tnObj.html(data.getNodeName(setting, node));\r\n\t\t\t} else {\r\n\t\t\t\tnObj.text(data.getNodeName(setting, node));\r\n\t\t\t}\r\n\t\t\tif (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) {\r\n\t\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A);\r\n\t\t\t\taObj.attr(\"title\", !title ? \"\" : title);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetNodeTarget: function(node) {\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A);\r\n\t\t\taObj.attr(\"target\", view.makeNodeTarget(node));\r\n\t\t},\r\n\t\tsetNodeUrl: function(setting, node) {\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\turl = view.makeNodeUrl(setting, node);\r\n\t\t\tif (url == null || url.length == 0) {\r\n\t\t\t\taObj.removeAttr(\"href\");\r\n\t\t\t} else {\r\n\t\t\t\taObj.attr(\"href\", url);\r\n\t\t\t}\r\n\t\t},\r\n\t\tswitchNode: function(setting, node) {\r\n\t\t\tif (node.open || !tools.canAsync(setting, node)) {\r\n\t\t\t\tview.expandCollapseNode(setting, node, !node.open);\r\n\t\t\t} else if (setting.async.enable) {\r\n\t\t\t\tif (!view.asyncNode(setting, node)) {\r\n\t\t\t\t\tview.expandCollapseNode(setting, node, !node.open);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t} else if (node) {\r\n\t\t\t\tview.expandCollapseNode(setting, node, !node.open);\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\t// zTree defind\r\n\t$.fn.zTree = {\r\n\t\tconsts : _consts,\r\n\t\t_z : {\r\n\t\t\ttools: tools,\r\n\t\t\tview: view,\r\n\t\t\tevent: event,\r\n\t\t\tdata: data\r\n\t\t},\r\n\t\tgetZTreeObj: function(treeId) {\r\n\t\t\tvar o = data.getZTreeTools(treeId);\r\n\t\t\treturn o ? o : null;\r\n\t\t},\r\n\t\tdestroy: function(treeId) {\r\n\t\t\tif (!!treeId && treeId.length > 0) {\r\n\t\t\t\tview.destroy(data.getSetting(treeId));\r\n\t\t\t} else {\r\n\t\t\t\tfor(var s in settings) {\r\n\t\t\t\t\tview.destroy(settings[s]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tinit: function(obj, zSetting, zNodes) {\r\n\t\t\tvar setting = tools.clone(_setting);\r\n\t\t\t$.extend(true, setting, zSetting);\r\n\t\t\tsetting.treeId = obj.attr(\"id\");\r\n\t\t\tsetting.treeObj = obj;\r\n\t\t\tsetting.treeObj.empty();\r\n\t\t\tsettings[setting.treeId] = setting;\r\n\t\t\t//For some older browser,(e.g., ie6)\r\n\t\t\tif(typeof document.body.style.maxHeight === \"undefined\") {\r\n\t\t\t\tsetting.view.expandSpeed = \"\";\r\n\t\t\t}\r\n\t\t\tdata.initRoot(setting);\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tzNodes = zNodes ? tools.clone(tools.isArray(zNodes)? zNodes : [zNodes]) : [];\r\n\t\t\tif (setting.data.simpleData.enable) {\r\n\t\t\t\troot[childKey] = data.transformTozTreeFormat(setting, zNodes);\r\n\t\t\t} else {\r\n\t\t\t\troot[childKey] = zNodes;\r\n\t\t\t}\r\n\r\n\t\t\tdata.initCache(setting);\r\n\t\t\tevent.unbindTree(setting);\r\n\t\t\tevent.bindTree(setting);\r\n\t\t\tevent.unbindEvent(setting);\r\n\t\t\tevent.bindEvent(setting);\r\n\t\t\t\r\n\t\t\tvar zTreeTools = {\r\n\t\t\t\tsetting : setting,\r\n\t\t\t\taddNodes : function(parentNode, newNodes, isSilent) {\r\n\t\t\t\t\tif (!newNodes) return null;\r\n\t\t\t\t\tif (!parentNode) parentNode = null;\r\n\t\t\t\t\tif (parentNode && !parentNode.isParent && setting.data.keep.leaf) return null;\r\n\t\t\t\t\tvar xNewNodes = tools.clone(tools.isArray(newNodes)? newNodes: [newNodes]);\r\n\t\t\t\t\tfunction addCallback() {\r\n\t\t\t\t\t\tview.addNodes(setting, parentNode, xNewNodes, (isSilent==true));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (tools.canAsync(setting, parentNode)) {\r\n\t\t\t\t\t\tview.asyncNode(setting, parentNode, isSilent, addCallback);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\taddCallback();\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn xNewNodes;\r\n\t\t\t\t},\r\n\t\t\t\tcancelSelectedNode : function(node) {\r\n\t\t\t\t\tview.cancelPreSelectedNode(this.setting, node);\r\n\t\t\t\t},\r\n\t\t\t\tdestroy : function() {\r\n\t\t\t\t\tview.destroy(this.setting);\r\n\t\t\t\t},\r\n\t\t\t\texpandAll : function(expandFlag) {\r\n\t\t\t\t\texpandFlag = !!expandFlag;\r\n\t\t\t\t\tview.expandCollapseSonNode(this.setting, null, expandFlag, true);\r\n\t\t\t\t\treturn expandFlag;\r\n\t\t\t\t},\r\n\t\t\t\texpandNode : function(node, expandFlag, sonSign, focus, callbackFlag) {\r\n\t\t\t\t\tif (!node || !node.isParent) return null;\r\n\t\t\t\t\tif (expandFlag !== true && expandFlag !== false) {\r\n\t\t\t\t\t\texpandFlag = !node.open;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcallbackFlag = !!callbackFlag;\r\n\r\n\t\t\t\t\tif (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) {\r\n\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t} else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) {\r\n\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (expandFlag && node.parentTId) {\r\n\t\t\t\t\t\tview.expandCollapseParentNode(this.setting, node.getParentNode(), expandFlag, false);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (expandFlag === node.open && !sonSign) {\r\n\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tdata.getRoot(setting).expandTriggerFlag = callbackFlag;\r\n\t\t\t\t\tif (sonSign) {\r\n\t\t\t\t\t\tview.expandCollapseSonNode(this.setting, node, expandFlag, true, function() {\r\n\t\t\t\t\t\t\tif (focus !== false) {try{$(\"#\" + node.tId).focus().blur();}catch(e){}}\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tnode.open = !expandFlag;\r\n\t\t\t\t\t\tview.switchNode(this.setting, node);\r\n\t\t\t\t\t\tif (focus !== false) {try{$(\"#\" + node.tId).focus().blur();}catch(e){}}\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn expandFlag;\r\n\t\t\t\t},\r\n\t\t\t\tgetNodes : function() {\r\n\t\t\t\t\treturn data.getNodes(this.setting);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodeByParam : function(key, value, parentNode) {\r\n\t\t\t\t\tif (!key) return null;\r\n\t\t\t\t\treturn data.getNodeByParam(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), key, value);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodeByTId : function(tId) {\r\n\t\t\t\t\treturn data.getNodeCache(this.setting, tId);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodesByParam : function(key, value, parentNode) {\r\n\t\t\t\t\tif (!key) return null;\r\n\t\t\t\t\treturn data.getNodesByParam(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), key, value);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodesByParamFuzzy : function(key, value, parentNode) {\r\n\t\t\t\t\tif (!key) return null;\r\n\t\t\t\t\treturn data.getNodesByParamFuzzy(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), key, value);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodesByFilter: function(filter, isSingle, parentNode, invokeParam) {\r\n\t\t\t\t\tisSingle = !!isSingle;\r\n\t\t\t\t\tif (!filter || (typeof filter != \"function\")) return (isSingle ? null : []);\r\n\t\t\t\t\treturn data.getNodesByFilter(this.setting, parentNode?parentNode[this.setting.data.key.children]:data.getNodes(this.setting), filter, isSingle, invokeParam);\r\n\t\t\t\t},\r\n\t\t\t\tgetNodeIndex : function(node) {\r\n\t\t\t\t\tif (!node) return null;\r\n\t\t\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\t\t\tparentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(this.setting);\r\n\t\t\t\t\tfor (var i=0, l = parentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\t\tif (parentNode[childKey][i] == node) return i;\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn -1;\r\n\t\t\t\t},\r\n\t\t\t\tgetSelectedNodes : function() {\r\n\t\t\t\t\tvar r = [], list = data.getRoot(this.setting).curSelectedList;\r\n\t\t\t\t\tfor (var i=0, l=list.length; i<l; i++) {\r\n\t\t\t\t\t\tr.push(list[i]);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn r;\r\n\t\t\t\t},\r\n\t\t\t\tisSelectedNode : function(node) {\r\n\t\t\t\t\treturn data.isSelectedNode(this.setting, node);\r\n\t\t\t\t},\r\n\t\t\t\treAsyncChildNodes : function(parentNode, reloadType, isSilent) {\r\n\t\t\t\t\tif (!this.setting.async.enable) return;\r\n\t\t\t\t\tvar isRoot = !parentNode;\r\n\t\t\t\t\tif (isRoot) {\r\n\t\t\t\t\t\tparentNode = data.getRoot(this.setting);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (reloadType==\"refresh\") {\r\n\t\t\t\t\t\tvar childKey = this.setting.data.key.children;\r\n\t\t\t\t\t\tfor (var i = 0, l = parentNode[childKey] ? parentNode[childKey].length : 0; i < l; i++) {\r\n\t\t\t\t\t\t\tdata.removeNodeCache(setting, parentNode[childKey][i]);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdata.removeSelectedNode(setting);\r\n\t\t\t\t\t\tparentNode[childKey] = [];\r\n\t\t\t\t\t\tif (isRoot) {\r\n\t\t\t\t\t\t\tthis.setting.treeObj.empty();\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tvar ulObj = $(\"#\" + parentNode.tId + consts.id.UL);\r\n\t\t\t\t\t\t\tulObj.empty();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.asyncNode(this.setting, isRoot? null:parentNode, !!isSilent);\r\n\t\t\t\t},\r\n\t\t\t\trefresh : function() {\r\n\t\t\t\t\tthis.setting.treeObj.empty();\r\n\t\t\t\t\tvar root = data.getRoot(this.setting),\r\n\t\t\t\t\tnodes = root[this.setting.data.key.children]\r\n\t\t\t\t\tdata.initRoot(this.setting);\r\n\t\t\t\t\troot[this.setting.data.key.children] = nodes\r\n\t\t\t\t\tdata.initCache(this.setting);\r\n\t\t\t\t\tview.createNodes(this.setting, 0, root[this.setting.data.key.children]);\r\n\t\t\t\t},\r\n\t\t\t\tremoveChildNodes : function(node) {\r\n\t\t\t\t\tif (!node) return null;\r\n\t\t\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\t\t\tnodes = node[childKey];\r\n\t\t\t\t\tview.removeChildNodes(setting, node);\r\n\t\t\t\t\treturn nodes ? nodes : null;\r\n\t\t\t\t},\r\n\t\t\t\tremoveNode : function(node, callbackFlag) {\r\n\t\t\t\t\tif (!node) return;\r\n\t\t\t\t\tcallbackFlag = !!callbackFlag;\r\n\t\t\t\t\tif (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return;\r\n\t\t\t\t\tview.removeNode(setting, node);\r\n\t\t\t\t\tif (callbackFlag) {\r\n\t\t\t\t\t\tthis.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t\tselectNode : function(node, addFlag) {\r\n\t\t\t\t\tif (!node) return;\r\n\t\t\t\t\tif (tools.uCanDo(this.setting)) {\r\n\t\t\t\t\t\taddFlag = setting.view.selectedMulti && addFlag;\r\n\t\t\t\t\t\tif (node.parentTId) {\r\n\t\t\t\t\t\t\tview.expandCollapseParentNode(this.setting, node.getParentNode(), true, false, function() {\r\n\t\t\t\t\t\t\t\ttry{$(\"#\" + node.tId).focus().blur();}catch(e){}\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttry{$(\"#\" + node.tId).focus().blur();}catch(e){}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tview.selectNode(this.setting, node, addFlag);\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t\ttransformTozTreeNodes : function(simpleNodes) {\r\n\t\t\t\t\treturn data.transformTozTreeFormat(this.setting, simpleNodes);\r\n\t\t\t\t},\r\n\t\t\t\ttransformToArray : function(nodes) {\r\n\t\t\t\t\treturn data.transformToArrayFormat(this.setting, nodes);\r\n\t\t\t\t},\r\n\t\t\t\tupdateNode : function(node, checkTypeFlag) {\r\n\t\t\t\t\tif (!node) return;\r\n\t\t\t\t\tvar nObj = $(\"#\" + node.tId);\r\n\t\t\t\t\tif (nObj.get(0) && tools.uCanDo(this.setting)) {\r\n\t\t\t\t\t\tview.setNodeName(this.setting, node);\r\n\t\t\t\t\t\tview.setNodeTarget(node);\r\n\t\t\t\t\t\tview.setNodeUrl(this.setting, node);\r\n\t\t\t\t\t\tview.setNodeLineIcos(this.setting, node);\r\n\t\t\t\t\t\tview.setNodeFontCss(this.setting, node);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\troot.treeTools = zTreeTools;\r\n\t\t\tdata.setZTreeTools(setting, zTreeTools);\r\n\r\n\t\t\tif (root[childKey] && root[childKey].length > 0) {\r\n\t\t\t\tview.createNodes(setting, 0, root[childKey]);\r\n\t\t\t} else if (setting.async.enable && setting.async.url && setting.async.url !== '') {\r\n\t\t\t\tview.asyncNode(setting);\r\n\t\t\t}\r\n\t\t\treturn zTreeTools;\r\n\t\t}\r\n\t};\r\n\r\n\tvar zt = $.fn.zTree,\r\n\tconsts = zt.consts;\r\n})(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/js/jquery.ztree.excheck-3.5.js",
    "content": "/*\r\n * JQuery zTree excheck 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\t//default consts of excheck\r\n\tvar _consts = {\r\n\t\tevent: {\r\n\t\t\tCHECK: \"ztree_check\"\r\n\t\t},\r\n\t\tid: {\r\n\t\t\tCHECK: \"_check\"\r\n\t\t},\r\n\t\tcheckbox: {\r\n\t\t\tSTYLE: \"checkbox\",\r\n\t\t\tDEFAULT: \"chk\",\r\n\t\t\tDISABLED: \"disable\",\r\n\t\t\tFALSE: \"false\",\r\n\t\t\tTRUE: \"true\",\r\n\t\t\tFULL: \"full\",\r\n\t\t\tPART: \"part\",\r\n\t\t\tFOCUS: \"focus\"\r\n\t\t},\r\n\t\tradio: {\r\n\t\t\tSTYLE: \"radio\",\r\n\t\t\tTYPE_ALL: \"all\",\r\n\t\t\tTYPE_LEVEL: \"level\"\r\n\t\t}\r\n\t},\r\n\t//default setting of excheck\r\n\t_setting = {\r\n\t\tcheck: {\r\n\t\t\tenable: false,\r\n\t\t\tautoCheckTrigger: false,\r\n\t\t\tchkStyle: _consts.checkbox.STYLE,\r\n\t\t\tnocheckInherit: false,\r\n\t\t\tchkDisabledInherit: false,\r\n\t\t\tradioType: _consts.radio.TYPE_LEVEL,\r\n\t\t\tchkboxType: {\r\n\t\t\t\t\"Y\": \"ps\",\r\n\t\t\t\t\"N\": \"ps\"\r\n\t\t\t}\r\n\t\t},\r\n\t\tdata: {\r\n\t\t\tkey: {\r\n\t\t\t\tchecked: \"checked\"\r\n\t\t\t}\r\n\t\t},\r\n\t\tcallback: {\r\n\t\t\tbeforeCheck:null,\r\n\t\t\tonCheck:null\r\n\t\t}\r\n\t},\r\n\t//default root of excheck\r\n\t_initRoot = function (setting) {\r\n\t\tvar r = data.getRoot(setting);\r\n\t\tr.radioCheckedList = [];\r\n\t},\r\n\t//default cache of excheck\r\n\t_initCache = function(treeId) {},\r\n\t//default bind event of excheck\r\n\t_bindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.bind(c.CHECK, function (event, srcEvent, treeId, node) {\r\n\t\t\ttools.apply(setting.callback.onCheck, [!!srcEvent?srcEvent : event, treeId, node]);\r\n\t\t});\r\n\t},\r\n\t_unbindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj,\r\n\t\tc = consts.event;\r\n\t\to.unbind(c.CHECK);\r\n\t},\r\n\t//default event proxy of excheck\r\n\t_eventProxy = function(e) {\r\n\t\tvar target = e.target,\r\n\t\tsetting = data.getSetting(e.data.treeId),\r\n\t\ttId = \"\", node = null,\r\n\t\tnodeEventType = \"\", treeEventType = \"\",\r\n\t\tnodeEventCallback = null, treeEventCallback = null;\r\n\r\n\t\tif (tools.eqs(e.type, \"mouseover\")) {\r\n\t\t\tif (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.CHECK) !== null) {\r\n\t\t\t\ttId = target.parentNode.id;\r\n\t\t\t\tnodeEventType = \"mouseoverCheck\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"mouseout\")) {\r\n\t\t\tif (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.CHECK) !== null) {\r\n\t\t\t\ttId = target.parentNode.id;\r\n\t\t\t\tnodeEventType = \"mouseoutCheck\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"click\")) {\r\n\t\t\tif (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\"+ consts.id.CHECK) !== null) {\r\n\t\t\t\ttId = target.parentNode.id;\r\n\t\t\t\tnodeEventType = \"checkNode\";\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (tId.length>0) {\r\n\t\t\tnode = data.getNodeCache(setting, tId);\r\n\t\t\tswitch (nodeEventType) {\r\n\t\t\t\tcase \"checkNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onCheckNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"mouseoverCheck\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onMouseoverCheck;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"mouseoutCheck\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onMouseoutCheck;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tvar proxyResult = {\r\n\t\t\tstop: false,\r\n\t\t\tnode: node,\r\n\t\t\tnodeEventType: nodeEventType,\r\n\t\t\tnodeEventCallback: nodeEventCallback,\r\n\t\t\ttreeEventType: treeEventType,\r\n\t\t\ttreeEventCallback: treeEventCallback\r\n\t\t};\r\n\t\treturn proxyResult\r\n\t},\r\n\t//default init node of excheck\r\n\t_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (!n) return;\r\n\t\tvar checkedKey = setting.data.key.checked;\r\n\t\tif (typeof n[checkedKey] == \"string\") n[checkedKey] = tools.eqs(n[checkedKey], \"true\");\r\n\t\tn[checkedKey] = !!n[checkedKey];\r\n\t\tn.checkedOld = n[checkedKey];\r\n\t\tif (typeof n.nocheck == \"string\") n.nocheck = tools.eqs(n.nocheck, \"true\");\r\n\t\tn.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck);\r\n\t\tif (typeof n.chkDisabled == \"string\") n.chkDisabled = tools.eqs(n.chkDisabled, \"true\");\r\n\t\tn.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled);\r\n\t\tif (typeof n.halfCheck == \"string\") n.halfCheck = tools.eqs(n.halfCheck, \"true\");\r\n\t\tn.halfCheck = !!n.halfCheck;\r\n\t\tn.check_Child_State = -1;\r\n\t\tn.check_Focus = false;\r\n\t\tn.getCheckStatus = function() {return data.getCheckStatus(setting, n);};\r\n\t},\r\n\t//add dom for check\r\n\t_beforeA = function(setting, node, html) {\r\n\t\tvar checkedKey = setting.data.key.checked;\r\n\t\tif (setting.check.enable) {\r\n\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\tif (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && node[checkedKey] ) {\r\n\t\t\t\tvar r = data.getRoot(setting);\r\n\t\t\t\tr.radioCheckedList.push(node);\r\n\t\t\t}\r\n\t\t\thtml.push(\"<span ID='\", node.tId, consts.id.CHECK, \"' class='\", view.makeChkClass(setting, node), \"' treeNode\", consts.id.CHECK, (node.nocheck === true?\" style='display:none;'\":\"\"),\"></span>\");\r\n\t\t}\r\n\t},\r\n\t//update zTreeObj, add method of check\r\n\t_zTreeTools = function(setting, zTreeTools) {\r\n\t\tzTreeTools.checkNode = function(node, checked, checkTypeFlag, callbackFlag) {\r\n\t\t\tvar checkedKey = this.setting.data.key.checked;\r\n\t\t\tif (node.chkDisabled === true) return;\r\n\t\t\tif (checked !== true && checked !== false) {\r\n\t\t\t\tchecked = !node[checkedKey];\r\n\t\t\t}\r\n\t\t\tcallbackFlag = !!callbackFlag;\r\n\t\t\t\r\n\t\t\tif (node[checkedKey] === checked && !checkTypeFlag) {\r\n\t\t\t\treturn;\r\n\t\t\t} else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) {\r\n\t\t\t\tnode[checkedKey] = checked;\r\n\t\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\t\tif (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);\r\n\t\t\t\tview.setChkClass(this.setting, checkObj, node);\r\n\t\t\t\tview.repairParentChkClassWithSelf(this.setting, node);\r\n\t\t\t\tif (callbackFlag) {\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tzTreeTools.checkAllNodes = function(checked) {\r\n\t\t\tview.repairAllChk(this.setting, !!checked);\r\n\t\t}\r\n\r\n\t\tzTreeTools.getCheckedNodes = function(checked) {\r\n\t\t\tvar childKey = this.setting.data.key.children;\r\n\t\t\tchecked = (checked !== false);\r\n\t\t\treturn data.getTreeCheckedNodes(this.setting, data.getRoot(setting)[childKey], checked);\r\n\t\t}\r\n\r\n\t\tzTreeTools.getChangeCheckedNodes = function() {\r\n\t\t\tvar childKey = this.setting.data.key.children;\r\n\t\t\treturn data.getTreeChangeCheckedNodes(this.setting, data.getRoot(setting)[childKey]);\r\n\t\t}\r\n\r\n\t\tzTreeTools.setChkDisabled = function(node, disabled, inheritParent, inheritChildren) {\r\n\t\t\tdisabled = !!disabled;\r\n\t\t\tinheritParent = !!inheritParent;\r\n\t\t\tinheritChildren = !!inheritChildren;\r\n\t\t\tview.repairSonChkDisabled(this.setting, node, disabled, inheritChildren);\r\n\t\t\tview.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent);\r\n\t\t}\r\n\r\n\t\tvar _updateNode = zTreeTools.updateNode;\r\n\t\tzTreeTools.updateNode = function(node, checkTypeFlag) {\r\n\t\t\tif (_updateNode) _updateNode.apply(zTreeTools, arguments);\r\n\t\t\tif (!node || !this.setting.check.enable) return;\r\n\t\t\tvar nObj = $(\"#\" + node.tId);\r\n\t\t\tif (nObj.get(0) && tools.uCanDo(this.setting)) {\r\n\t\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\t\tif (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);\r\n\t\t\t\tview.setChkClass(this.setting, checkObj, node);\r\n\t\t\t\tview.repairParentChkClassWithSelf(this.setting, node);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate data\r\n\t_data = {\r\n\t\tgetRadioCheckedList: function(setting) {\r\n\t\t\tvar checkedList = data.getRoot(setting).radioCheckedList;\r\n\t\t\tfor (var i=0, j=checkedList.length; i<j; i++) {\r\n\t\t\t\tif(!data.getNodeCache(setting, checkedList[i].tId)) {\r\n\t\t\t\t\tcheckedList.splice(i, 1);\r\n\t\t\t\t\ti--; j--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn checkedList;\r\n\t\t},\r\n\t\tgetCheckStatus: function(setting, node) {\r\n\t\t\tif (!setting.check.enable || node.nocheck || node.chkDisabled) return null;\r\n\t\t\tvar checkedKey = setting.data.key.checked,\r\n\t\t\tr = {\r\n\t\t\t\tchecked: node[checkedKey],\r\n\t\t\t\thalf: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (node[checkedKey] ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0)))\r\n\t\t\t};\r\n\t\t\treturn r;\r\n\t\t},\r\n\t\tgetTreeCheckedNodes: function(setting, nodes, checked, results) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tonlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL);\r\n\t\t\tresults = !results ? [] : results;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] == checked) {\r\n\t\t\t\t\tresults.push(nodes[i]);\r\n\t\t\t\t\tif(onlyOne) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tdata.getTreeCheckedNodes(setting, nodes[i][childKey], checked, results);\r\n\t\t\t\tif(onlyOne && results.length > 0) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn results;\r\n\t\t},\r\n\t\tgetTreeChangeCheckedNodes: function(setting, nodes, results) {\r\n\t\t\tif (!nodes) return [];\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked;\r\n\t\t\tresults = !results ? [] : results;\r\n\t\t\tfor (var i = 0, l = nodes.length; i < l; i++) {\r\n\t\t\t\tif (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] != nodes[i].checkedOld) {\r\n\t\t\t\t\tresults.push(nodes[i]);\r\n\t\t\t\t}\r\n\t\t\t\tdata.getTreeChangeCheckedNodes(setting, nodes[i][childKey], results);\r\n\t\t\t}\r\n\t\t\treturn results;\r\n\t\t},\r\n\t\tmakeChkFlag: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tchkFlag = -1;\r\n\t\t\tif (node[childKey]) {\r\n\t\t\t\tfor (var i = 0, l = node[childKey].length; i < l; i++) {\r\n\t\t\t\t\tvar cNode = node[childKey][i];\r\n\t\t\t\t\tvar tmp = -1;\r\n\t\t\t\t\tif (setting.check.chkStyle == consts.radio.STYLE) {\r\n\t\t\t\t\t\tif (cNode.nocheck === true || cNode.chkDisabled === true) {\r\n\t\t\t\t\t\t\ttmp = cNode.check_Child_State;\r\n\t\t\t\t\t\t} else if (cNode.halfCheck === true) {\r\n\t\t\t\t\t\t\ttmp = 2;\r\n\t\t\t\t\t\t} else if (cNode[checkedKey]) {\r\n\t\t\t\t\t\t\ttmp = 2;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttmp = cNode.check_Child_State > 0 ? 2:0;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (tmp == 2) {\r\n\t\t\t\t\t\t\tchkFlag = 2; break;\r\n\t\t\t\t\t\t} else if (tmp == 0){\r\n\t\t\t\t\t\t\tchkFlag = 0;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (setting.check.chkStyle == consts.checkbox.STYLE) {\r\n\t\t\t\t\t\tif (cNode.nocheck === true || cNode.chkDisabled === true) {\r\n\t\t\t\t\t\t\ttmp = cNode.check_Child_State;\r\n\t\t\t\t\t\t} else if (cNode.halfCheck === true) {\r\n\t\t\t\t\t\t\ttmp = 1;\r\n\t\t\t\t\t\t} else if (cNode[checkedKey] ) {\r\n\t\t\t\t\t\t\ttmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttmp = (cNode.check_Child_State > 0) ? 1 : 0;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (tmp === 1) {\r\n\t\t\t\t\t\t\tchkFlag = 1; break;\r\n\t\t\t\t\t\t} else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) {\r\n\t\t\t\t\t\t\tchkFlag = 1; break;\r\n\t\t\t\t\t\t} else if (chkFlag === 2 && tmp > -1 && tmp < 2) {\r\n\t\t\t\t\t\t\tchkFlag = 1; break;\r\n\t\t\t\t\t\t} else if (tmp > -1) {\r\n\t\t\t\t\t\t\tchkFlag = tmp;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tnode.check_Child_State = chkFlag;\r\n\t\t}\r\n\t},\r\n\t//method of event proxy\r\n\t_event = {\r\n\r\n\t},\r\n\t//method of event handler\r\n\t_handler = {\r\n\t\tonCheckNode: function (event, node) {\r\n\t\t\tif (node.chkDisabled === true) return false;\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tcheckedKey = setting.data.key.checked;\r\n\t\t\tif (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true;\r\n\t\t\tnode[checkedKey] = !node[checkedKey];\r\n\t\t\tview.checkNodeRelation(setting, node);\r\n\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\tview.repairParentChkClassWithSelf(setting, node);\r\n\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]);\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonMouseoverCheck: function(event, node) {\r\n\t\t\tif (node.chkDisabled === true) return false;\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tnode.check_Focus = true;\r\n\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\tonMouseoutCheck: function(event, node) {\r\n\t\t\tif (node.chkDisabled === true) return false;\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tnode.check_Focus = false;\r\n\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t},\r\n\t//method of tools for zTree\r\n\t_tools = {\r\n\r\n\t},\r\n\t//method of operate ztree dom\r\n\t_view = {\r\n\t\tcheckNodeRelation: function(setting, node) {\r\n\t\t\tvar pNode, i, l,\r\n\t\t\tchildKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tr = consts.radio;\r\n\t\t\tif (setting.check.chkStyle == r.STYLE) {\r\n\t\t\t\tvar checkedList = data.getRadioCheckedList(setting);\r\n\t\t\t\tif (node[checkedKey]) {\r\n\t\t\t\t\tif (setting.check.radioType == r.TYPE_ALL) {\r\n\t\t\t\t\t\tfor (i = checkedList.length-1; i >= 0; i--) {\r\n\t\t\t\t\t\t\tpNode = checkedList[i];\r\n\t\t\t\t\t\t\tpNode[checkedKey] = false;\r\n\t\t\t\t\t\t\tcheckedList.splice(i, 1);\r\n\r\n\t\t\t\t\t\t\tview.setChkClass(setting, $(\"#\" + pNode.tId + consts.id.CHECK), pNode);\r\n\t\t\t\t\t\t\tif (pNode.parentTId != node.parentTId) {\r\n\t\t\t\t\t\t\t\tview.repairParentChkClassWithSelf(setting, pNode);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcheckedList.push(node);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tvar parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);\r\n\t\t\t\t\t\tfor (i = 0, l = parentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\t\t\tpNode = parentNode[childKey][i];\r\n\t\t\t\t\t\t\tif (pNode[checkedKey] && pNode != node) {\r\n\t\t\t\t\t\t\t\tpNode[checkedKey] = false;\r\n\t\t\t\t\t\t\t\tview.setChkClass(setting, $(\"#\" + pNode.tId + consts.id.CHECK), pNode);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (setting.check.radioType == r.TYPE_ALL) {\r\n\t\t\t\t\tfor (i = 0, l = checkedList.length; i < l; i++) {\r\n\t\t\t\t\t\tif (node == checkedList[i]) {\r\n\t\t\t\t\t\t\tcheckedList.splice(i, 1);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.Y.indexOf(\"s\") > -1)) {\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, node, true);\r\n\t\t\t\t}\r\n\t\t\t\tif (!node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.N.indexOf(\"s\") > -1)) {\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, node, false);\r\n\t\t\t\t}\r\n\t\t\t\tif (node[checkedKey] && setting.check.chkboxType.Y.indexOf(\"p\") > -1) {\r\n\t\t\t\t\tview.setParentNodeCheckBox(setting, node, true);\r\n\t\t\t\t}\r\n\t\t\t\tif (!node[checkedKey] && setting.check.chkboxType.N.indexOf(\"p\") > -1) {\r\n\t\t\t\t\tview.setParentNodeCheckBox(setting, node, false);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tmakeChkClass: function(setting, node) {\r\n\t\t\tvar checkedKey = setting.data.key.checked,\r\n\t\t\tc = consts.checkbox, r = consts.radio,\r\n\t\t\tfullStyle = \"\";\r\n\t\t\tif (node.chkDisabled === true) {\r\n\t\t\t\tfullStyle = c.DISABLED;\r\n\t\t\t} else if (node.halfCheck) {\r\n\t\t\t\tfullStyle = c.PART;\r\n\t\t\t} else if (setting.check.chkStyle == r.STYLE) {\r\n\t\t\t\tfullStyle = (node.check_Child_State < 1)? c.FULL:c.PART;\r\n\t\t\t} else {\r\n\t\t\t\tfullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART);\r\n\t\t\t}\r\n\t\t\tvar chkName = setting.check.chkStyle + \"_\" + (node[checkedKey] ? c.TRUE : c.FALSE) + \"_\" + fullStyle;\r\n\t\t\tchkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + \"_\" + c.FOCUS : chkName;\r\n\t\t\treturn consts.className.BUTTON + \" \" + c.DEFAULT + \" \" + chkName;\r\n\t\t},\r\n\t\trepairAllChk: function(setting, checked) {\r\n\t\t\tif (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) {\r\n\t\t\t\tvar checkedKey = setting.data.key.checked,\r\n\t\t\t\tchildKey = setting.data.key.children,\r\n\t\t\t\troot = data.getRoot(setting);\r\n\t\t\t\tfor (var i = 0, l = root[childKey].length; i<l ; i++) {\r\n\t\t\t\t\tvar node = root[childKey][i];\r\n\t\t\t\t\tif (node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\t\t\tnode[checkedKey] = checked;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, node, checked);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairChkClass: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\tif (node.nocheck !== true) {\r\n\t\t\t\tvar checkObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairParentChkClass: function(setting, node) {\r\n\t\t\tif (!node || !node.parentTId) return;\r\n\t\t\tvar pNode = node.getParentNode();\r\n\t\t\tview.repairChkClass(setting, pNode);\r\n\t\t\tview.repairParentChkClass(setting, pNode);\r\n\t\t},\r\n\t\trepairParentChkClassWithSelf: function(setting, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (node[childKey] && node[childKey].length > 0) {\r\n\t\t\t\tview.repairParentChkClass(setting, node[childKey][0]);\r\n\t\t\t} else {\r\n\t\t\t\tview.repairParentChkClass(setting, node);\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairSonChkDisabled: function(setting, node, chkDisabled, inherit) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tif (node.chkDisabled != chkDisabled) {\r\n\t\t\t\tnode.chkDisabled = chkDisabled;\r\n\t\t\t}\r\n\t\t\tview.repairChkClass(setting, node);\r\n\t\t\tif (node[childKey] && inherit) {\r\n\t\t\t\tfor (var i = 0, l = node[childKey].length; i < l; i++) {\r\n\t\t\t\t\tvar sNode = node[childKey][i];\r\n\t\t\t\t\tview.repairSonChkDisabled(setting, sNode, chkDisabled, inherit);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\trepairParentChkDisabled: function(setting, node, chkDisabled, inherit) {\r\n\t\t\tif (!node) return;\r\n\t\t\tif (node.chkDisabled != chkDisabled && inherit) {\r\n\t\t\t\tnode.chkDisabled = chkDisabled;\r\n\t\t\t}\r\n\t\t\tview.repairChkClass(setting, node);\r\n\t\t\tview.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit);\r\n\t\t},\r\n\t\tsetChkClass: function(setting, obj, node) {\r\n\t\t\tif (!obj) return;\r\n\t\t\tif (node.nocheck === true) {\r\n\t\t\t\tobj.hide();\r\n\t\t\t} else {\r\n\t\t\t\tobj.show();\r\n\t\t\t}\r\n\t\t\tobj.removeClass();\r\n\t\t\tobj.addClass(view.makeChkClass(setting, node));\r\n\t\t},\r\n\t\tsetParentNodeCheckBox: function(setting, node, value, srcNode) {\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tif (!srcNode) srcNode = node;\r\n\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\tif (node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\tnode[checkedKey] = value;\r\n\t\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\t\tif (setting.check.autoCheckTrigger && node != srcNode) {\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (node.parentTId) {\r\n\t\t\t\tvar pSign = true;\r\n\t\t\t\tif (!value) {\r\n\t\t\t\t\tvar pNodes = node.getParentNode()[childKey];\r\n\t\t\t\t\tfor (var i = 0, l = pNodes.length; i < l; i++) {\r\n\t\t\t\t\t\tif ((pNodes[i].nocheck !== true && pNodes[i].chkDisabled !== true && pNodes[i][checkedKey])\r\n\t\t\t\t\t\t|| ((pNodes[i].nocheck === true || pNodes[i].chkDisabled === true) && pNodes[i].check_Child_State > 0)) {\r\n\t\t\t\t\t\t\tpSign = false;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (pSign) {\r\n\t\t\t\t\tview.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetSonNodeCheckBox: function(setting, node, value, srcNode) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children,\r\n\t\t\tcheckedKey = setting.data.key.checked,\r\n\t\t\tcheckObj = $(\"#\" + node.tId + consts.id.CHECK);\r\n\t\t\tif (!srcNode) srcNode = node;\r\n\r\n\t\t\tvar hasDisable = false;\r\n\t\t\tif (node[childKey]) {\r\n\t\t\t\tfor (var i = 0, l = node[childKey].length; i < l && node.chkDisabled !== true; i++) {\r\n\t\t\t\t\tvar sNode = node[childKey][i];\r\n\t\t\t\t\tview.setSonNodeCheckBox(setting, sNode, value, srcNode);\r\n\t\t\t\t\tif (sNode.chkDisabled === true) hasDisable = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (node != data.getRoot(setting) && node.chkDisabled !== true) {\r\n\t\t\t\tif (hasDisable && node.nocheck !== true) {\r\n\t\t\t\t\tdata.makeChkFlag(setting, node);\r\n\t\t\t\t}\r\n\t\t\t\tif (node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\t\tnode[checkedKey] = value;\r\n\t\t\t\t\tif (!hasDisable) node.check_Child_State = (node[childKey] && node[childKey].length > 0) ? (value ? 2 : 0) : -1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnode.check_Child_State = -1;\r\n\t\t\t\t}\r\n\t\t\t\tview.setChkClass(setting, checkObj, node);\r\n\t\t\t\tif (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) {\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t}\r\n\t},\r\n\r\n\t_z = {\r\n\t\ttools: _tools,\r\n\t\tview: _view,\r\n\t\tevent: _event,\r\n\t\tdata: _data\r\n\t};\r\n\t$.extend(true, $.fn.zTree.consts, _consts);\r\n\t$.extend(true, $.fn.zTree._z, _z);\r\n\r\n\tvar zt = $.fn.zTree,\r\n\ttools = zt._z.tools,\r\n\tconsts = zt.consts,\r\n\tview = zt._z.view,\r\n\tdata = zt._z.data,\r\n\tevent = zt._z.event;\r\n\r\n\tdata.exSetting(_setting);\r\n\tdata.addInitBind(_bindEvent);\r\n\tdata.addInitUnBind(_unbindEvent);\r\n\tdata.addInitCache(_initCache);\r\n\tdata.addInitNode(_initNode);\r\n\tdata.addInitProxy(_eventProxy);\r\n\tdata.addInitRoot(_initRoot);\r\n\tdata.addBeforeA(_beforeA);\r\n\tdata.addZTreeTools(_zTreeTools);\r\n\r\n\tvar _createNodes = view.createNodes;\r\n\tview.createNodes = function(setting, level, nodes, parentNode) {\r\n\t\tif (_createNodes) _createNodes.apply(view, arguments);\r\n\t\tif (!nodes) return;\r\n\t\tview.repairParentChkClassWithSelf(setting, parentNode);\r\n\t}\r\n\tvar _removeNode = view.removeNode;\r\n\tview.removeNode = function(setting, node) {\r\n\t\tvar parentNode = node.getParentNode();\r\n\t\tif (_removeNode) _removeNode.apply(view, arguments);\r\n\t\tif (!node || !parentNode) return;\r\n\t\tview.repairChkClass(setting, parentNode);\r\n\t\tview.repairParentChkClass(setting, parentNode);\r\n\t}\r\n\r\n\tvar _appendNodes = view.appendNodes;\r\n\tview.appendNodes = function(setting, level, nodes, parentNode, initFlag, openFlag) {\r\n\t\tvar html = \"\";\r\n\t\tif (_appendNodes) {\r\n\t\t\thtml = _appendNodes.apply(view, arguments);\r\n\t\t}\r\n\t\tif (parentNode) {\r\n\t\t\tdata.makeChkFlag(setting, parentNode);\r\n\t\t}\r\n\t\treturn html;\r\n\t}\r\n})(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/js/jquery.ztree.exedit-3.5.js",
    "content": "/*\r\n * JQuery zTree exedit 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\t//default consts of exedit\r\n\tvar _consts = {\r\n\t\tevent: {\r\n\t\t\tDRAG: \"ztree_drag\",\r\n\t\t\tDROP: \"ztree_drop\",\r\n\t\t\tREMOVE: \"ztree_remove\",\r\n\t\t\tRENAME: \"ztree_rename\"\r\n\t\t},\r\n\t\tid: {\r\n\t\t\tEDIT: \"_edit\",\r\n\t\t\tINPUT: \"_input\",\r\n\t\t\tREMOVE: \"_remove\"\r\n\t\t},\r\n\t\tmove: {\r\n\t\t\tTYPE_INNER: \"inner\",\r\n\t\t\tTYPE_PREV: \"prev\",\r\n\t\t\tTYPE_NEXT: \"next\"\r\n\t\t},\r\n\t\tnode: {\r\n\t\t\tCURSELECTED_EDIT: \"curSelectedNode_Edit\",\r\n\t\t\tTMPTARGET_TREE: \"tmpTargetzTree\",\r\n\t\t\tTMPTARGET_NODE: \"tmpTargetNode\"\r\n\t\t}\r\n\t},\r\n\t//default setting of exedit\r\n\t_setting = {\r\n\t\tedit: {\r\n\t\t\tenable: false,\r\n\t\t\teditNameSelectAll: false,\r\n\t\t\tshowRemoveBtn: true,\r\n\t\t\tshowRenameBtn: true,\r\n\t\t\tremoveTitle: \"remove\",\r\n\t\t\trenameTitle: \"rename\",\r\n\t\t\tdrag: {\r\n\t\t\t\tautoExpandTrigger: false,\r\n\t\t\t\tisCopy: true,\r\n\t\t\t\tisMove: true,\r\n\t\t\t\tprev: true,\r\n\t\t\t\tnext: true,\r\n\t\t\t\tinner: true,\r\n\t\t\t\tminMoveSize: 5,\r\n\t\t\t\tborderMax: 10,\r\n\t\t\t\tborderMin: -5,\r\n\t\t\t\tmaxShowNodeNum: 5,\r\n\t\t\t\tautoOpenTime: 500\r\n\t\t\t}\r\n\t\t},\r\n\t\tview: {\r\n\t\t\taddHoverDom: null,\r\n\t\t\tremoveHoverDom: null\r\n\t\t},\r\n\t\tcallback: {\r\n\t\t\tbeforeDrag:null,\r\n\t\t\tbeforeDragOpen:null,\r\n\t\t\tbeforeDrop:null,\r\n\t\t\tbeforeEditName:null,\r\n\t\t\tbeforeRename:null,\r\n\t\t\tonDrag:null,\r\n\t\t\tonDrop:null,\r\n\t\t\tonRename:null\r\n\t\t}\r\n\t},\r\n\t//default root of exedit\r\n\t_initRoot = function (setting) {\r\n\t\tvar r = data.getRoot(setting);\r\n\t\tr.curEditNode = null;\r\n\t\tr.curEditInput = null;\r\n\t\tr.curHoverNode = null;\r\n\t\tr.dragFlag = 0;\r\n\t\tr.dragNodeShowBefore = [];\r\n\t\tr.dragMaskList = new Array();\r\n\t\tr.showHoverDom = true;\r\n\t},\r\n\t//default cache of exedit\r\n\t_initCache = function(treeId) {},\r\n\t//default bind event of exedit\r\n\t_bindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj;\r\n\t\tvar c = consts.event;\r\n\t\to.bind(c.RENAME, function (event, treeId, treeNode) {\r\n\t\t\ttools.apply(setting.callback.onRename, [event, treeId, treeNode]);\r\n\t\t});\r\n\r\n\t\to.bind(c.REMOVE, function (event, treeId, treeNode) {\r\n\t\t\ttools.apply(setting.callback.onRemove, [event, treeId, treeNode]);\r\n\t\t});\r\n\r\n\t\to.bind(c.DRAG, function (event, srcEvent, treeId, treeNodes) {\r\n\t\t\ttools.apply(setting.callback.onDrag, [srcEvent, treeId, treeNodes]);\r\n\t\t});\r\n\r\n\t\to.bind(c.DROP, function (event, srcEvent, treeId, treeNodes, targetNode, moveType, isCopy) {\r\n\t\t\ttools.apply(setting.callback.onDrop, [srcEvent, treeId, treeNodes, targetNode, moveType, isCopy]);\r\n\t\t});\r\n\t},\r\n\t_unbindEvent = function(setting) {\r\n\t\tvar o = setting.treeObj;\r\n\t\tvar c = consts.event;\r\n\t\to.unbind(c.RENAME);\r\n\t\to.unbind(c.REMOVE);\r\n\t\to.unbind(c.DRAG);\r\n\t\to.unbind(c.DROP);\r\n\t},\r\n\t//default event proxy of exedit\r\n\t_eventProxy = function(e) {\r\n\t\tvar target = e.target,\r\n\t\tsetting = data.getSetting(e.data.treeId),\r\n\t\trelatedTarget = e.relatedTarget,\r\n\t\ttId = \"\", node = null,\r\n\t\tnodeEventType = \"\", treeEventType = \"\",\r\n\t\tnodeEventCallback = null, treeEventCallback = null,\r\n\t\ttmp = null;\r\n\r\n\t\tif (tools.eqs(e.type, \"mouseover\")) {\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {\r\n\t\t\t\ttId = tmp.parentNode.id;\r\n\t\t\t\tnodeEventType = \"hoverOverNode\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"mouseout\")) {\r\n\t\t\ttmp = tools.getMDom(setting, relatedTarget, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (!tmp) {\r\n\t\t\t\ttId = \"remove\";\r\n\t\t\t\tnodeEventType = \"hoverOutNode\";\r\n\t\t\t}\r\n\t\t} else if (tools.eqs(e.type, \"mousedown\")) {\r\n\t\t\ttmp = tools.getMDom(setting, target, [{tagName:\"a\", attrName:\"treeNode\"+consts.id.A}]);\r\n\t\t\tif (tmp) {\r\n\t\t\t\ttId = tmp.parentNode.id;\r\n\t\t\t\tnodeEventType = \"mousedownNode\";\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (tId.length>0) {\r\n\t\t\tnode = data.getNodeCache(setting, tId);\r\n\t\t\tswitch (nodeEventType) {\r\n\t\t\t\tcase \"mousedownNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onMousedownNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"hoverOverNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onHoverOverNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"hoverOutNode\" :\r\n\t\t\t\t\tnodeEventCallback = _handler.onHoverOutNode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tvar proxyResult = {\r\n\t\t\tstop: false,\r\n\t\t\tnode: node,\r\n\t\t\tnodeEventType: nodeEventType,\r\n\t\t\tnodeEventCallback: nodeEventCallback,\r\n\t\t\ttreeEventType: treeEventType,\r\n\t\t\ttreeEventCallback: treeEventCallback\r\n\t\t};\r\n\t\treturn proxyResult\r\n\t},\r\n\t//default init node of exedit\r\n\t_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (!n) return;\r\n\t\tn.isHover = false;\r\n\t\tn.editNameFlag = false;\r\n\t},\r\n\t//update zTreeObj, add method of edit\r\n\t_zTreeTools = function(setting, zTreeTools) {\r\n\t\tzTreeTools.cancelEditName = function(newName) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tnameKey = setting.data.key.name,\r\n\t\t\tnode = root.curEditNode;\r\n\t\t\tif (!root.curEditNode) return;\r\n\t\t\tview.cancelCurEditNode(setting, newName?newName:node[nameKey]);\r\n\t\t}\r\n\t\tzTreeTools.copyNode = function(targetNode, node, moveType, isSilent) {\r\n\t\t\tif (!node) return null;\r\n\t\t\tif (targetNode && !targetNode.isParent && setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) return null;\r\n\t\t\tvar newNode = tools.clone(node);\r\n\t\t\tif (!targetNode) {\r\n\t\t\t\ttargetNode = null;\r\n\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t}\r\n\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\tfunction copyCallback() {\r\n\t\t\t\t\tview.addNodes(setting, targetNode, [newNode], isSilent);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (tools.canAsync(setting, targetNode)) {\r\n\t\t\t\t\tview.asyncNode(setting, targetNode, isSilent, copyCallback);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcopyCallback();\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tview.addNodes(setting, targetNode.parentNode, [newNode], isSilent);\r\n\t\t\t\tview.moveNode(setting, targetNode, newNode, moveType, false, isSilent);\r\n\t\t\t}\r\n\t\t\treturn newNode;\r\n\t\t}\r\n\t\tzTreeTools.editName = function(node) {\r\n\t\t\tif (!node || !node.tId || node !== data.getNodeCache(setting, node.tId)) return;\r\n\t\t\tif (node.parentTId) view.expandCollapseParentNode(setting, node.getParentNode(), true);\r\n\t\t\tview.editNode(setting, node)\r\n\t\t}\r\n\t\tzTreeTools.moveNode = function(targetNode, node, moveType, isSilent) {\r\n\t\t\tif (!node) return node;\r\n\t\t\tif (targetNode && !targetNode.isParent && setting.data.keep.leaf && moveType === consts.move.TYPE_INNER) {\r\n\t\t\t\treturn null;\r\n\t\t\t} else if (targetNode && ((node.parentTId == targetNode.tId && moveType == consts.move.TYPE_INNER) || $(\"#\" + node.tId).find(\"#\" + targetNode.tId).length > 0)) {\r\n\t\t\t\treturn null;\r\n\t\t\t} else if (!targetNode) {\r\n\t\t\t\ttargetNode = null;\r\n\t\t\t}\r\n\t\t\tfunction moveCallback() {\r\n\t\t\t\tview.moveNode(setting, targetNode, node, moveType, false, isSilent);\r\n\t\t\t}\r\n\t\t\tif (tools.canAsync(setting, targetNode) && moveType === consts.move.TYPE_INNER) {\r\n\t\t\t\tview.asyncNode(setting, targetNode, isSilent, moveCallback);\r\n\t\t\t} else {\r\n\t\t\t\tmoveCallback();\r\n\t\t\t}\r\n\t\t\treturn node;\r\n\t\t}\r\n\t\tzTreeTools.setEditable = function(editable) {\r\n\t\t\tsetting.edit.enable = editable;\r\n\t\t\treturn this.refresh();\r\n\t\t}\r\n\t},\r\n\t//method of operate data\r\n\t_data = {\r\n\t\tsetSonNodeLevel: function(setting, parentNode, node) {\r\n\t\t\tif (!node) return;\r\n\t\t\tvar childKey = setting.data.key.children;\r\n\t\t\tnode.level = (parentNode)? parentNode.level + 1 : 0;\r\n\t\t\tif (!node[childKey]) return;\r\n\t\t\tfor (var i = 0, l = node[childKey].length; i < l; i++) {\r\n\t\t\t\tif (node[childKey][i]) data.setSonNodeLevel(setting, node, node[childKey][i]);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of event proxy\r\n\t_event = {\r\n\r\n\t},\r\n\t//method of event handler\r\n\t_handler = {\r\n\t\tonHoverOverNode: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\troot = data.getRoot(setting);\r\n\t\t\tif (root.curHoverNode != node) {\r\n\t\t\t\t_handler.onHoverOutNode(event);\r\n\t\t\t}\r\n\t\t\troot.curHoverNode = node;\r\n\t\t\tview.addHoverDom(setting, node);\r\n\t\t},\r\n\t\tonHoverOutNode: function(event, node) {\r\n\t\t\tvar setting = data.getSetting(event.data.treeId),\r\n\t\t\troot = data.getRoot(setting);\r\n\t\t\tif (root.curHoverNode && !data.isSelectedNode(setting, root.curHoverNode)) {\r\n\t\t\t\tview.removeTreeDom(setting, root.curHoverNode);\r\n\t\t\t\troot.curHoverNode = null;\r\n\t\t\t}\r\n\t\t},\r\n\t\tonMousedownNode: function(eventMouseDown, _node) {\r\n\t\t\tvar i,l,\r\n\t\t\tsetting = data.getSetting(eventMouseDown.data.treeId),\r\n\t\t\troot = data.getRoot(setting);\r\n\t\t\t//right click can't drag & drop\r\n\t\t\tif (eventMouseDown.button == 2 || !setting.edit.enable || (!setting.edit.drag.isCopy && !setting.edit.drag.isMove)) return true;\r\n\r\n\t\t\t//input of edit node name can't drag & drop\r\n\t\t\tvar target = eventMouseDown.target,\r\n\t\t\t_nodes = data.getRoot(setting).curSelectedList,\r\n\t\t\tnodes = [];\r\n\t\t\tif (!data.isSelectedNode(setting, _node)) {\r\n\t\t\t\tnodes = [_node];\r\n\t\t\t} else {\r\n\t\t\t\tfor (i=0, l=_nodes.length; i<l; i++) {\r\n\t\t\t\t\tif (_nodes[i].editNameFlag && tools.eqs(target.tagName, \"input\") && target.getAttribute(\"treeNode\"+consts.id.INPUT) !== null) {\r\n\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tnodes.push(_nodes[i]);\r\n\t\t\t\t\tif (nodes[0].parentTId !== _nodes[i].parentTId) {\r\n\t\t\t\t\t\tnodes = [_node];\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tview.editNodeBlur = true;\r\n\t\t\tview.cancelCurEditNode(setting, null, true);\r\n\t\t\t\r\n\r\n\t\t\tvar doc = $(document), curNode, tmpArrow, tmpTarget,\r\n\t\t\tisOtherTree = false,\r\n\t\t\ttargetSetting = setting,\r\n\t\t\tpreNode, nextNode,\r\n\t\t\tpreTmpTargetNodeId = null,\r\n\t\t\tpreTmpMoveType = null,\r\n\t\t\ttmpTargetNodeId = null,\r\n\t\t\tmoveType = consts.move.TYPE_INNER,\r\n\t\t\tmouseDownX = eventMouseDown.clientX,\r\n\t\t\tmouseDownY = eventMouseDown.clientY,\r\n\t\t\tstartTime = (new Date()).getTime();\r\n\r\n\t\t\tif (tools.uCanDo(setting)) {\r\n\t\t\t\tdoc.bind(\"mousemove\", _docMouseMove);\r\n\t\t\t}\r\n\t\t\tfunction _docMouseMove(event) {\r\n\t\t\t\t//avoid start drag after click node\r\n\t\t\t\tif (root.dragFlag == 0 && Math.abs(mouseDownX - event.clientX) < setting.edit.drag.minMoveSize\r\n\t\t\t\t\t&& Math.abs(mouseDownY - event.clientY) < setting.edit.drag.minMoveSize) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t\tvar i, l, tmpNode, tmpDom, tmpNodes,\r\n\t\t\t\tchildKey = setting.data.key.children;\r\n\t\t\t\t$(\"body\").css(\"cursor\", \"pointer\");\r\n\r\n\t\t\t\tif (root.dragFlag == 0) {\r\n\t\t\t\t\tif (tools.apply(setting.callback.beforeDrag, [setting.treeId, nodes], true) == false) {\r\n\t\t\t\t\t\t_docMouseUp(event);\r\n\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\tif (i==0) {\r\n\t\t\t\t\t\t\troot.dragNodeShowBefore = [];\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\t\tif (tmpNode.isParent && tmpNode.open) {\r\n\t\t\t\t\t\t\tview.expandCollapseNode(setting, tmpNode, !tmpNode.open);\r\n\t\t\t\t\t\t\troot.dragNodeShowBefore[tmpNode.tId] = true;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\troot.dragNodeShowBefore[tmpNode.tId] = false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\troot.dragFlag = 1;\r\n\t\t\t\t\troot.showHoverDom = false;\r\n\t\t\t\t\ttools.showIfameMask(setting, true);\r\n\r\n\t\t\t\t\t//sort\r\n\t\t\t\t\tvar isOrder = true, lastIndex = -1;\r\n\t\t\t\t\tif (nodes.length>1) {\r\n\t\t\t\t\t\tvar pNodes = nodes[0].parentTId ? nodes[0].getParentNode()[childKey] : data.getNodes(setting);\r\n\t\t\t\t\t\ttmpNodes = [];\r\n\t\t\t\t\t\tfor (i=0, l=pNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\tif (root.dragNodeShowBefore[pNodes[i].tId] !== undefined) {\r\n\t\t\t\t\t\t\t\tif (isOrder && lastIndex > -1 && (lastIndex+1) !== i) {\r\n\t\t\t\t\t\t\t\t\tisOrder = false;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\ttmpNodes.push(pNodes[i]);\r\n\t\t\t\t\t\t\t\tlastIndex = i;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (nodes.length === tmpNodes.length) {\r\n\t\t\t\t\t\t\t\tnodes = tmpNodes;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (isOrder) {\r\n\t\t\t\t\t\tpreNode = nodes[0].getPreNode();\r\n\t\t\t\t\t\tnextNode = nodes[nodes.length-1].getNextNode();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t//set node in selected\r\n\t\t\t\t\tcurNode = $(\"<ul class='zTreeDragUL'></ul>\");\r\n\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\t\ttmpNode.editNameFlag = false;\r\n\t\t\t\t\t\tview.selectNode(setting, tmpNode, i>0);\r\n\t\t\t\t\t\tview.removeTreeDom(setting, tmpNode);\r\n\r\n\t\t\t\t\t\ttmpDom = $(\"<li id='\"+ tmpNode.tId +\"_tmp'></li>\");\r\n\t\t\t\t\t\ttmpDom.append($(\"#\" + tmpNode.tId + consts.id.A).clone());\r\n\t\t\t\t\t\ttmpDom.css(\"padding\", \"0\");\r\n\t\t\t\t\t\ttmpDom.children(\"#\" + tmpNode.tId + consts.id.A).removeClass(consts.node.CURSELECTED);\r\n\t\t\t\t\t\tcurNode.append(tmpDom);\r\n\t\t\t\t\t\tif (i == setting.edit.drag.maxShowNodeNum-1) {\r\n\t\t\t\t\t\t\ttmpDom = $(\"<li id='\"+ tmpNode.tId +\"_moretmp'><a>  ...  </a></li>\");\r\n\t\t\t\t\t\t\tcurNode.append(tmpDom);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcurNode.attr(\"id\", nodes[0].tId + consts.id.UL + \"_tmp\");\r\n\t\t\t\t\tcurNode.addClass(setting.treeObj.attr(\"class\"));\r\n\t\t\t\t\tcurNode.appendTo(\"body\");\r\n\r\n\t\t\t\t\ttmpArrow = $(\"<span class='tmpzTreeMove_arrow'></span>\");\r\n\t\t\t\t\ttmpArrow.attr(\"id\", \"zTreeMove_arrow_tmp\");\r\n\t\t\t\t\ttmpArrow.appendTo(\"body\");\r\n\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.DRAG, [event, setting.treeId, nodes]);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (root.dragFlag == 1) {\r\n\t\t\t\t\tif (tmpTarget && tmpArrow.attr(\"id\") == event.target.id && tmpTargetNodeId && (event.clientX + doc.scrollLeft()+2) > ($(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget).offset().left)) {\r\n\t\t\t\t\t\tvar xT = $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget);\r\n\t\t\t\t\t\tevent.target = (xT.length > 0) ? xT.get(0) : event.target;\r\n\t\t\t\t\t} else if (tmpTarget) {\r\n\t\t\t\t\t\ttmpTarget.removeClass(consts.node.TMPTARGET_TREE);\r\n\t\t\t\t\t\tif (tmpTargetNodeId) $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + \"_\" + consts.move.TYPE_PREV)\r\n\t\t\t\t\t\t\t.removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_INNER);\r\n\t\t\t\t\t}\r\n\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t\ttmpTargetNodeId = null;\r\n\r\n\t\t\t\t\t//judge drag & drop in multi ztree\r\n\t\t\t\t\tisOtherTree = false;\r\n\t\t\t\t\ttargetSetting = setting;\r\n\t\t\t\t\tvar settings = data.getSettings();\r\n\t\t\t\t\tfor (var s in settings) {\r\n\t\t\t\t\t\tif (settings[s].treeId && settings[s].edit.enable && settings[s].treeId != setting.treeId\r\n\t\t\t\t\t\t\t&& (event.target.id == settings[s].treeId || $(event.target).parents(\"#\" + settings[s].treeId).length>0)) {\r\n\t\t\t\t\t\t\tisOtherTree = true;\r\n\t\t\t\t\t\t\ttargetSetting = settings[s];\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar docScrollTop = doc.scrollTop(),\r\n\t\t\t\t\tdocScrollLeft = doc.scrollLeft(),\r\n\t\t\t\t\ttreeOffset = targetSetting.treeObj.offset(),\r\n\t\t\t\t\tscrollHeight = targetSetting.treeObj.get(0).scrollHeight,\r\n\t\t\t\t\tscrollWidth = targetSetting.treeObj.get(0).scrollWidth,\r\n\t\t\t\t\tdTop = (event.clientY + docScrollTop - treeOffset.top),\r\n\t\t\t\t\tdBottom = (targetSetting.treeObj.height() + treeOffset.top - event.clientY - docScrollTop),\r\n\t\t\t\t\tdLeft = (event.clientX + docScrollLeft - treeOffset.left),\r\n\t\t\t\t\tdRight = (targetSetting.treeObj.width() + treeOffset.left - event.clientX - docScrollLeft),\r\n\t\t\t\t\tisTop = (dTop < setting.edit.drag.borderMax && dTop > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisBottom = (dBottom < setting.edit.drag.borderMax && dBottom > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisLeft = (dLeft < setting.edit.drag.borderMax && dLeft > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisRight = (dRight < setting.edit.drag.borderMax && dRight > setting.edit.drag.borderMin),\r\n\t\t\t\t\tisTreeInner = dTop > setting.edit.drag.borderMin && dBottom > setting.edit.drag.borderMin && dLeft > setting.edit.drag.borderMin && dRight > setting.edit.drag.borderMin,\r\n\t\t\t\t\tisTreeTop = (isTop && targetSetting.treeObj.scrollTop() <= 0),\r\n\t\t\t\t\tisTreeBottom = (isBottom && (targetSetting.treeObj.scrollTop() + targetSetting.treeObj.height()+10) >= scrollHeight),\r\n\t\t\t\t\tisTreeLeft = (isLeft && targetSetting.treeObj.scrollLeft() <= 0),\r\n\t\t\t\t\tisTreeRight = (isRight && (targetSetting.treeObj.scrollLeft() + targetSetting.treeObj.width()+10) >= scrollWidth);\r\n\r\n\t\t\t\t\tif (event.target.id && targetSetting.treeObj.find(\"#\" + event.target.id).length > 0) {\r\n\t\t\t\t\t\t//get node <li> dom\r\n\t\t\t\t\t\tvar targetObj = event.target;\r\n\t\t\t\t\t\twhile (targetObj && targetObj.tagName && !tools.eqs(targetObj.tagName, \"li\") && targetObj.id != targetSetting.treeId) {\r\n\t\t\t\t\t\t\ttargetObj = targetObj.parentNode;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvar canMove = true;\r\n\t\t\t\t\t\t//don't move to self or children of self\r\n\t\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\t\t\tif (targetObj.id === tmpNode.tId) {\r\n\t\t\t\t\t\t\t\tcanMove = false;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t} else if ($(\"#\" + tmpNode.tId).find(\"#\" + targetObj.id).length > 0) {\r\n\t\t\t\t\t\t\t\tcanMove = false;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (canMove) {\r\n\t\t\t\t\t\t\tif (event.target.id &&\r\n\t\t\t\t\t\t\t\t(event.target.id == (targetObj.id + consts.id.A) || $(event.target).parents(\"#\" + targetObj.id + consts.id.A).length > 0)) {\r\n\t\t\t\t\t\t\t\ttmpTarget = $(targetObj);\r\n\t\t\t\t\t\t\t\ttmpTargetNodeId = targetObj.id;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t//the mouse must be in zTree\r\n\t\t\t\t\ttmpNode = nodes[0];\r\n\t\t\t\t\tif (isTreeInner && (event.target.id == targetSetting.treeId || $(event.target).parents(\"#\" + targetSetting.treeId).length>0)) {\r\n\t\t\t\t\t\t//judge mouse move in root of ztree\r\n\t\t\t\t\t\tif (!tmpTarget && (event.target.id == targetSetting.treeId || isTreeTop || isTreeBottom || isTreeLeft || isTreeRight) && (isOtherTree || (!isOtherTree && tmpNode.parentTId))) {\r\n\t\t\t\t\t\t\ttmpTarget = targetSetting.treeObj;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t//auto scroll top\r\n\t\t\t\t\t\tif (isTop) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop()-10);\r\n\t\t\t\t\t\t} else if (isBottom)  {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollTop(targetSetting.treeObj.scrollTop()+10);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (isLeft) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft()-10);\r\n\t\t\t\t\t\t} else if (isRight) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft()+10);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t//auto scroll left\r\n\t\t\t\t\t\tif (tmpTarget && tmpTarget != targetSetting.treeObj && tmpTarget.offset().left < targetSetting.treeObj.offset().left) {\r\n\t\t\t\t\t\t\ttargetSetting.treeObj.scrollLeft(targetSetting.treeObj.scrollLeft()+ tmpTarget.offset().left - targetSetting.treeObj.offset().left);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcurNode.css({\r\n\t\t\t\t\t\t\"top\": (event.clientY + docScrollTop + 3) + \"px\",\r\n\t\t\t\t\t\t\"left\": (event.clientX + docScrollLeft + 3) + \"px\"\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tvar dX = 0;\r\n\t\t\t\t\tvar dY = 0;\r\n\t\t\t\t\tif (tmpTarget && tmpTarget.attr(\"id\")!=targetSetting.treeId) {\r\n\t\t\t\t\t\tvar tmpTargetNode = tmpTargetNodeId == null ? null: data.getNodeCache(targetSetting, tmpTargetNodeId),\r\n\t\t\t\t\t\tisCopy = (event.ctrlKey && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy),\r\n\t\t\t\t\t\tisPrev = !!(preNode && tmpTargetNodeId === preNode.tId),\r\n\t\t\t\t\t\tisNext = !!(nextNode && tmpTargetNodeId === nextNode.tId),\r\n\t\t\t\t\t\tisInner = (tmpNode.parentTId && tmpNode.parentTId == tmpTargetNodeId),\r\n\t\t\t\t\t\tcanPrev = (isCopy || !isNext) && tools.apply(targetSetting.edit.drag.prev, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.prev),\r\n\t\t\t\t\t\tcanNext = (isCopy || !isPrev) && tools.apply(targetSetting.edit.drag.next, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.next),\r\n\t\t\t\t\t\tcanInner = (isCopy || !isInner) && !(targetSetting.data.keep.leaf && !tmpTargetNode.isParent) && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, tmpTargetNode], !!targetSetting.edit.drag.inner);\r\n\t\t\t\t\t\tif (!canPrev && !canNext && !canInner) {\r\n\t\t\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t\t\t\ttmpTargetNodeId = \"\";\r\n\t\t\t\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t\t\t\t\ttmpArrow.css({\r\n\t\t\t\t\t\t\t\t\"display\":\"none\"\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\tif (window.zTreeMoveTimer) {\r\n\t\t\t\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tvar tmpTargetA = $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget),\r\n\t\t\t\t\t\t\ttmpNextA = tmpTargetNode.isLastNode ? null : $(\"#\" + tmpTargetNode.getNextNode().tId + consts.id.A, tmpTarget.next()),\r\n\t\t\t\t\t\t\ttmpTop = tmpTargetA.offset().top,\r\n\t\t\t\t\t\t\ttmpLeft = tmpTargetA.offset().left,\r\n\t\t\t\t\t\t\tprevPercent = canPrev ? (canInner ? 0.25 : (canNext ? 0.5 : 1) ) : -1,\r\n\t\t\t\t\t\t\tnextPercent = canNext ? (canInner ? 0.75 : (canPrev ? 0.5 : 0) ) : -1,\r\n\t\t\t\t\t\t\tdY_percent = (event.clientY + docScrollTop - tmpTop)/tmpTargetA.height();\r\n\t\t\t\t\t\t\tif ((prevPercent==1 ||dY_percent<=prevPercent && dY_percent>=-.2) && canPrev) {\r\n\t\t\t\t\t\t\t\tdX = 1 - tmpArrow.width();\r\n\t\t\t\t\t\t\t\tdY = tmpTop - tmpArrow.height()/2;\r\n\t\t\t\t\t\t\t\tmoveType = consts.move.TYPE_PREV;\r\n\t\t\t\t\t\t\t} else if ((nextPercent==0 || dY_percent>=nextPercent && dY_percent<=1.2) && canNext) {\r\n\t\t\t\t\t\t\t\tdX = 1 - tmpArrow.width();\r\n\t\t\t\t\t\t\t\tdY = (tmpNextA == null || (tmpTargetNode.isParent && tmpTargetNode.open)) ? (tmpTop + tmpTargetA.height() - tmpArrow.height()/2) : (tmpNextA.offset().top - tmpArrow.height()/2);\r\n\t\t\t\t\t\t\t\tmoveType = consts.move.TYPE_NEXT;\r\n\t\t\t\t\t\t\t}else {\r\n\t\t\t\t\t\t\t\tdX = 5 - tmpArrow.width();\r\n\t\t\t\t\t\t\t\tdY = tmpTop;\r\n\t\t\t\t\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\ttmpArrow.css({\r\n\t\t\t\t\t\t\t\t\"display\":\"block\",\r\n\t\t\t\t\t\t\t\t\"top\": dY + \"px\",\r\n\t\t\t\t\t\t\t\t\"left\": (tmpLeft + dX) + \"px\"\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\ttmpTargetA.addClass(consts.node.TMPTARGET_NODE + \"_\" + moveType);\r\n\r\n\t\t\t\t\t\t\tif (preTmpTargetNodeId != tmpTargetNodeId || preTmpMoveType != moveType) {\r\n\t\t\t\t\t\t\t\tstartTime = (new Date()).getTime();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (tmpTargetNode && tmpTargetNode.isParent && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\t\t\t\tvar startTimer = true;\r\n\t\t\t\t\t\t\t\tif (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId !== tmpTargetNode.tId) {\r\n\t\t\t\t\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null;\r\n\t\t\t\t\t\t\t\t} else if (window.zTreeMoveTimer && window.zTreeMoveTargetNodeTId === tmpTargetNode.tId) {\r\n\t\t\t\t\t\t\t\t\tstartTimer = false;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tif (startTimer) {\r\n\t\t\t\t\t\t\t\t\twindow.zTreeMoveTimer = setTimeout(function() {\r\n\t\t\t\t\t\t\t\t\t\tif (moveType != consts.move.TYPE_INNER) return;\r\n\t\t\t\t\t\t\t\t\t\tif (tmpTargetNode && tmpTargetNode.isParent && !tmpTargetNode.open && (new Date()).getTime() - startTime > targetSetting.edit.drag.autoOpenTime\r\n\t\t\t\t\t\t\t\t\t\t\t&& tools.apply(targetSetting.callback.beforeDragOpen, [targetSetting.treeId, tmpTargetNode], true)) {\r\n\t\t\t\t\t\t\t\t\t\t\tview.switchNode(targetSetting, tmpTargetNode);\r\n\t\t\t\t\t\t\t\t\t\t\tif (targetSetting.edit.drag.autoExpandTrigger) {\r\n\t\t\t\t\t\t\t\t\t\t\t\ttargetSetting.treeObj.trigger(consts.event.EXPAND, [targetSetting.treeId, tmpTargetNode]);\r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t}, targetSetting.edit.drag.autoOpenTime+50);\r\n\t\t\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = tmpTargetNode.tId;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t\t\t\tif (tmpTarget && tools.apply(targetSetting.edit.drag.inner, [targetSetting.treeId, nodes, null], !!targetSetting.edit.drag.inner)) {\r\n\t\t\t\t\t\t\ttmpTarget.addClass(consts.node.TMPTARGET_TREE);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\ttmpArrow.css({\r\n\t\t\t\t\t\t\t\"display\":\"none\"\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t\tif (window.zTreeMoveTimer) {\r\n\t\t\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tpreTmpTargetNodeId = tmpTargetNodeId;\r\n\t\t\t\t\tpreTmpMoveType = moveType;\r\n\t\t\t\t}\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tdoc.bind(\"mouseup\", _docMouseUp);\r\n\t\t\tfunction _docMouseUp(event) {\r\n\t\t\t\tif (window.zTreeMoveTimer) {\r\n\t\t\t\t\tclearTimeout(window.zTreeMoveTimer);\r\n\t\t\t\t\twindow.zTreeMoveTargetNodeTId = null;\r\n\t\t\t\t}\r\n\t\t\t\tpreTmpTargetNodeId = null;\r\n\t\t\t\tpreTmpMoveType = null;\r\n\t\t\t\tdoc.unbind(\"mousemove\", _docMouseMove);\r\n\t\t\t\tdoc.unbind(\"mouseup\", _docMouseUp);\r\n\t\t\t\tdoc.unbind(\"selectstart\", _docSelect);\r\n\t\t\t\t$(\"body\").css(\"cursor\", \"auto\");\r\n\t\t\t\tif (tmpTarget) {\r\n\t\t\t\t\ttmpTarget.removeClass(consts.node.TMPTARGET_TREE);\r\n\t\t\t\t\tif (tmpTargetNodeId) $(\"#\" + tmpTargetNodeId + consts.id.A, tmpTarget).removeClass(consts.node.TMPTARGET_NODE + \"_\" + consts.move.TYPE_PREV)\r\n\t\t\t\t\t\t\t.removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_NEXT).removeClass(consts.node.TMPTARGET_NODE + \"_\" + _consts.move.TYPE_INNER);\r\n\t\t\t\t}\r\n\t\t\t\ttools.showIfameMask(setting, false);\r\n\r\n\t\t\t\troot.showHoverDom = true;\r\n\t\t\t\tif (root.dragFlag == 0) return;\r\n\t\t\t\troot.dragFlag = 0;\r\n\r\n\t\t\t\tvar i, l, tmpNode;\r\n\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\ttmpNode = nodes[i];\r\n\t\t\t\t\tif (tmpNode.isParent && root.dragNodeShowBefore[tmpNode.tId] && !tmpNode.open) {\r\n\t\t\t\t\t\tview.expandCollapseNode(setting, tmpNode, !tmpNode.open);\r\n\t\t\t\t\t\tdelete root.dragNodeShowBefore[tmpNode.tId];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (curNode) curNode.remove();\r\n\t\t\t\tif (tmpArrow) tmpArrow.remove();\r\n\r\n\t\t\t\tvar isCopy = (event.ctrlKey && setting.edit.drag.isMove && setting.edit.drag.isCopy) || (!setting.edit.drag.isMove && setting.edit.drag.isCopy);\r\n\t\t\t\tif (!isCopy && tmpTarget && tmpTargetNodeId && nodes[0].parentTId && tmpTargetNodeId==nodes[0].parentTId && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\ttmpTarget = null;\r\n\t\t\t\t}\r\n\t\t\t\tif (tmpTarget) {\r\n\t\t\t\t\tvar dragTargetNode = tmpTargetNodeId == null ? null: data.getNodeCache(targetSetting, tmpTargetNodeId);\r\n\t\t\t\t\tif (tools.apply(setting.callback.beforeDrop, [targetSetting.treeId, nodes, dragTargetNode, moveType, isCopy], true) == false) return;\r\n\t\t\t\t\tvar newNodes = isCopy ? tools.clone(nodes) : nodes;\r\n\t\t\t\t\t\r\n\t\t\t\t\tfunction dropCallback() {\r\n\t\t\t\t\t\tif (isOtherTree) {\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tif (!isCopy) {\r\n\t\t\t\t\t\t\t\tfor(var i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\t\t\tview.removeNode(setting, nodes[i]);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode, newNodes);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode.getParentNode(), newNodes);\r\n\t\t\t\t\t\t\t\tif (moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\t\t\t\t\t\tfor (i=0, l=newNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[i], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tfor (i=-1, l=newNodes.length-1; i<l; l--) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[l], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tif (isCopy && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode, newNodes);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tif (isCopy) {\r\n\t\t\t\t\t\t\t\t\tview.addNodes(targetSetting, dragTargetNode.getParentNode(), newNodes);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tif (moveType != consts.move.TYPE_NEXT) {\r\n\t\t\t\t\t\t\t\t\tfor (i=0, l=newNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[i], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tfor (i=-1, l=newNodes.length-1; i<l; l--) {\r\n\t\t\t\t\t\t\t\t\t\tview.moveNode(targetSetting, dragTargetNode, newNodes[l], moveType, false);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tfor (i=0, l=newNodes.length; i<l; i++) {\r\n\t\t\t\t\t\t\tview.selectNode(targetSetting, newNodes[i], i>0);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t$(\"#\" + newNodes[0].tId).focus().blur();\r\n\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.DROP, [event, targetSetting.treeId, newNodes, dragTargetNode, moveType, isCopy]);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (moveType == consts.move.TYPE_INNER && tools.canAsync(targetSetting, dragTargetNode)) {\r\n\t\t\t\t\t\tview.asyncNode(targetSetting, dragTargetNode, false, dropCallback);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tdropCallback();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\t\t\t\t\tfor (i=0, l=nodes.length; i<l; i++) {\r\n\t\t\t\t\t\tview.selectNode(targetSetting, nodes[i], i>0);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.DROP, [event, setting.treeId, nodes, null, null, null]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tdoc.bind(\"selectstart\", _docSelect);\r\n\t\t\tfunction _docSelect() {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\t//Avoid FireFox's Bug\r\n\t\t\t//If zTree Div CSS set 'overflow', so drag node outside of zTree, and event.target is error.\r\n\t\t\tif(eventMouseDown.preventDefault) {\r\n\t\t\t\teventMouseDown.preventDefault();\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t},\r\n\t//method of tools for zTree\r\n\t_tools = {\r\n\t\tgetAbs: function (obj) {\r\n\t\t\tvar oRect = obj.getBoundingClientRect();\r\n\t\t\treturn [oRect.left,oRect.top]\r\n\t\t},\r\n\t\tinputFocus: function(inputObj) {\r\n\t\t\tif (inputObj.get(0)) {\r\n\t\t\t\tinputObj.focus();\r\n\t\t\t\ttools.setCursorPosition(inputObj.get(0), inputObj.val().length);\r\n\t\t\t}\r\n\t\t},\r\n\t\tinputSelect: function(inputObj) {\r\n\t\t\tif (inputObj.get(0)) {\r\n\t\t\t\tinputObj.focus();\r\n\t\t\t\tinputObj.select();\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetCursorPosition: function(obj, pos){\r\n\t\t\tif(obj.setSelectionRange) {\r\n\t\t\t\tobj.focus();\r\n\t\t\t\tobj.setSelectionRange(pos,pos);\r\n\t\t\t} else if (obj.createTextRange) {\r\n\t\t\t\tvar range = obj.createTextRange();\r\n\t\t\t\trange.collapse(true);\r\n\t\t\t\trange.moveEnd('character', pos);\r\n\t\t\t\trange.moveStart('character', pos);\r\n\t\t\t\trange.select();\r\n\t\t\t}\r\n\t\t},\r\n\t\tshowIfameMask: function(setting, showSign) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\t//clear full mask\r\n\t\t\twhile (root.dragMaskList.length > 0) {\r\n\t\t\t\troot.dragMaskList[0].remove();\r\n\t\t\t\troot.dragMaskList.shift();\r\n\t\t\t}\r\n\t\t\tif (showSign) {\r\n\t\t\t\t//show mask\r\n\t\t\t\tvar iframeList = $(\"iframe\");\r\n\t\t\t\tfor (var i = 0, l = iframeList.length; i < l; i++) {\r\n\t\t\t\t\tvar obj = iframeList.get(i),\r\n\t\t\t\t\tr = tools.getAbs(obj),\r\n\t\t\t\t\tdragMask = $(\"<div id='zTreeMask_\" + i + \"' class='zTreeMask' style='top:\" + r[1] + \"px; left:\" + r[0] + \"px; width:\" + obj.offsetWidth + \"px; height:\" + obj.offsetHeight + \"px;'></div>\");\r\n\t\t\t\t\tdragMask.appendTo(\"body\");\r\n\t\t\t\t\troot.dragMaskList.push(dragMask);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate ztree dom\r\n\t_view = {\r\n\t\taddEditBtn: function(setting, node) {\r\n\t\t\tif (node.editNameFlag || $(\"#\" + node.tId + consts.id.EDIT).length > 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!tools.apply(setting.edit.showRenameBtn, [setting.treeId, node], setting.edit.showRenameBtn)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\teditStr = \"<span class='\" + consts.className.BUTTON + \" edit' id='\" + node.tId + consts.id.EDIT + \"' title='\"+tools.apply(setting.edit.renameTitle, [setting.treeId, node], setting.edit.renameTitle)+\"' treeNode\"+consts.id.EDIT+\" style='display:none;'></span>\";\r\n\t\t\taObj.append(editStr);\r\n\r\n\t\t\t$(\"#\" + node.tId + consts.id.EDIT).bind('click',\r\n\t\t\t\tfunction() {\r\n\t\t\t\t\tif (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeEditName, [setting.treeId, node], true) == false) return false;\r\n\t\t\t\t\tview.editNode(setting, node);\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t\t).show();\r\n\t\t},\r\n\t\taddRemoveBtn: function(setting, node) {\r\n\t\t\tif (node.editNameFlag || $(\"#\" + node.tId + consts.id.REMOVE).length > 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!tools.apply(setting.edit.showRemoveBtn, [setting.treeId, node], setting.edit.showRemoveBtn)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\tremoveStr = \"<span class='\" + consts.className.BUTTON + \" remove' id='\" + node.tId + consts.id.REMOVE + \"' title='\"+tools.apply(setting.edit.removeTitle, [setting.treeId, node], setting.edit.removeTitle)+\"' treeNode\"+consts.id.REMOVE+\" style='display:none;'></span>\";\r\n\t\t\taObj.append(removeStr);\r\n\r\n\t\t\t$(\"#\" + node.tId + consts.id.REMOVE).bind('click',\r\n\t\t\t\tfunction() {\r\n\t\t\t\t\tif (!tools.uCanDo(setting) || tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return false;\r\n\t\t\t\t\tview.removeNode(setting, node);\r\n\t\t\t\t\tsetting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]);\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t\t).bind('mousedown',\r\n\t\t\t\tfunction(eventMouseDown) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t\t).show();\r\n\t\t},\r\n\t\taddHoverDom: function(setting, node) {\r\n\t\t\tif (data.getRoot(setting).showHoverDom) {\r\n\t\t\t\tnode.isHover = true;\r\n\t\t\t\tif (setting.edit.enable) {\r\n\t\t\t\t\tview.addEditBtn(setting, node);\r\n\t\t\t\t\tview.addRemoveBtn(setting, node);\r\n\t\t\t\t}\r\n\t\t\t\ttools.apply(setting.view.addHoverDom, [setting.treeId, node]);\r\n\t\t\t}\r\n\t\t},\r\n\t\tcancelCurEditNode: function (setting, forceName) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tnameKey = setting.data.key.name,\r\n\t\t\tnode = root.curEditNode;\r\n\t\t\t\r\n\t\t\tif (node) {\r\n\t\t\t\tvar inputObj = root.curEditInput;\r\n\t\t\t\tvar newName = forceName ? forceName:inputObj.val();\r\n\t\t\t\tif (!forceName && tools.apply(setting.callback.beforeRename, [setting.treeId, node, newName], true) === false) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnode[nameKey] = newName ? newName:inputObj.val();\r\n\t\t\t\t\tif (!forceName) {\r\n\t\t\t\t\t\tsetting.treeObj.trigger(consts.event.RENAME, [setting.treeId, node]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tvar aObj = $(\"#\" + node.tId + consts.id.A);\r\n\t\t\t\taObj.removeClass(consts.node.CURSELECTED_EDIT);\r\n\t\t\t\tinputObj.unbind();\r\n\t\t\t\tview.setNodeName(setting, node);\r\n\t\t\t\tnode.editNameFlag = false;\r\n\t\t\t\troot.curEditNode = null;\r\n\t\t\t\troot.curEditInput = null;\r\n\t\t\t\tview.selectNode(setting, node, false);\r\n\t\t\t}\r\n\t\t\troot.noSelection = true;\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\teditNode: function(setting, node) {\r\n\t\t\tvar root = data.getRoot(setting);\r\n\t\t\tview.editNodeBlur = false;\r\n\t\t\tif (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) {\r\n\t\t\t\tsetTimeout(function() {tools.inputFocus(root.curEditInput);}, 0);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar nameKey = setting.data.key.name;\r\n\t\t\tnode.editNameFlag = true;\r\n\t\t\tview.removeTreeDom(setting, node);\r\n\t\t\tview.cancelCurEditNode(setting);\r\n\t\t\tview.selectNode(setting, node, false);\r\n\t\t\t$(\"#\" + node.tId + consts.id.SPAN).html(\"<input type=text class='rename' id='\" + node.tId + consts.id.INPUT + \"' treeNode\" + consts.id.INPUT + \" >\");\r\n\t\t\tvar inputObj = $(\"#\" + node.tId + consts.id.INPUT);\r\n\t\t\tinputObj.attr(\"value\", node[nameKey]);\r\n\t\t\tif (setting.edit.editNameSelectAll) {\r\n\t\t\t\ttools.inputSelect(inputObj);\r\n\t\t\t} else {\r\n\t\t\t\ttools.inputFocus(inputObj);\r\n\t\t\t}\r\n\r\n\t\t\tinputObj.bind('blur', function(event) {\r\n\t\t\t\tif (!view.editNodeBlur) {\r\n\t\t\t\t\tview.cancelCurEditNode(setting);\r\n\t\t\t\t}\r\n\t\t\t}).bind('keydown', function(event) {\r\n\t\t\t\tif (event.keyCode==\"13\") {\r\n\t\t\t\t\tview.editNodeBlur = true;\r\n\t\t\t\t\tview.cancelCurEditNode(setting, null, true);\r\n\t\t\t\t} else if (event.keyCode==\"27\") {\r\n\t\t\t\t\tview.cancelCurEditNode(setting, node[nameKey]);\r\n\t\t\t\t}\r\n\t\t\t}).bind('click', function(event) {\r\n\t\t\t\treturn false;\r\n\t\t\t}).bind('dblclick', function(event) {\r\n\t\t\t\treturn false;\r\n\t\t\t});\r\n\r\n\t\t\t$(\"#\" + node.tId + consts.id.A).addClass(consts.node.CURSELECTED_EDIT);\r\n\t\t\troot.curEditInput = inputObj;\r\n\t\t\troot.noSelection = false;\r\n\t\t\troot.curEditNode = node;\r\n\t\t},\r\n\t\tmoveNode: function(setting, targetNode, node, moveType, animateFlag, isSilent) {\r\n\t\t\tvar root = data.getRoot(setting),\r\n\t\t\tchildKey = setting.data.key.children;\r\n\t\t\tif (targetNode == node) return;\r\n\t\t\tif (setting.data.keep.leaf && targetNode && !targetNode.isParent && moveType == consts.move.TYPE_INNER) return;\r\n\t\t\tvar oldParentNode = (node.parentTId ? node.getParentNode(): root),\r\n\t\t\ttargetNodeIsRoot = (targetNode === null || targetNode == root);\r\n\t\t\tif (targetNodeIsRoot && targetNode === null) targetNode = root;\r\n\t\t\tif (targetNodeIsRoot) moveType = consts.move.TYPE_INNER;\r\n\t\t\tvar targetParentNode = (targetNode.parentTId ? targetNode.getParentNode() : root);\r\n\r\n\t\t\tif (moveType != consts.move.TYPE_PREV && moveType != consts.move.TYPE_NEXT) {\r\n\t\t\t\tmoveType = consts.move.TYPE_INNER;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\tif (targetNodeIsRoot) {\r\n\t\t\t\t\t//parentTId of root node is null\r\n\t\t\t\t\tnode.parentTId = null;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (!targetNode.isParent) {\r\n\t\t\t\t\t\ttargetNode.isParent = true;\r\n\t\t\t\t\t\ttargetNode.open = !!targetNode.open;\r\n\t\t\t\t\t\tview.setNodeLineIcos(setting, targetNode);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tnode.parentTId = targetNode.tId;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t//move node Dom\r\n\t\t\tvar targetObj, target_ulObj;\r\n\t\t\tif (targetNodeIsRoot) {\r\n\t\t\t\ttargetObj = setting.treeObj;\r\n\t\t\t\ttarget_ulObj = targetObj;\r\n\t\t\t} else {\r\n\t\t\t\tif (!isSilent && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\t\tview.expandCollapseNode(setting, targetNode, true, false);\r\n\t\t\t\t} else if (!isSilent) {\r\n\t\t\t\t\tview.expandCollapseNode(setting, targetNode.getParentNode(), true, false);\r\n\t\t\t\t}\r\n\t\t\t\ttargetObj = $(\"#\" + targetNode.tId);\r\n\t\t\t\ttarget_ulObj = $(\"#\" + targetNode.tId + consts.id.UL);\r\n\t\t\t\tif (!!targetObj.get(0) && !target_ulObj.get(0)) {\r\n\t\t\t\t\tvar ulstr = [];\r\n\t\t\t\t\tview.makeUlHtml(setting, targetNode, ulstr, '');\r\n\t\t\t\t\ttargetObj.append(ulstr.join(''));\r\n\t\t\t\t}\r\n\t\t\t\ttarget_ulObj = $(\"#\" + targetNode.tId + consts.id.UL);\r\n\t\t\t}\r\n\t\t\tvar nodeDom = $(\"#\" + node.tId);\r\n\t\t\tif (!nodeDom.get(0)) {\r\n\t\t\t\tnodeDom = view.appendNodes(setting, node.level, [node], null, false, true).join('');\r\n\t\t\t} else if (!targetObj.get(0)) {\r\n\t\t\t\tnodeDom.remove();\r\n\t\t\t}\r\n\t\t\tif (target_ulObj.get(0) && moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\ttarget_ulObj.append(nodeDom);\r\n\t\t\t} else if (targetObj.get(0) && moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\ttargetObj.before(nodeDom);\r\n\t\t\t} else if (targetObj.get(0) && moveType == consts.move.TYPE_NEXT) {\r\n\t\t\t\ttargetObj.after(nodeDom);\r\n\t\t\t}\r\n\r\n\t\t\t//repair the data after move\r\n\t\t\tvar i,l,\r\n\t\t\ttmpSrcIndex = -1,\r\n\t\t\ttmpTargetIndex = 0,\r\n\t\t\toldNeighbor = null,\r\n\t\t\tnewNeighbor = null,\r\n\t\t\toldLevel = node.level;\r\n\t\t\tif (node.isFirstNode) {\r\n\t\t\t\ttmpSrcIndex = 0;\r\n\t\t\t\tif (oldParentNode[childKey].length > 1 ) {\r\n\t\t\t\t\toldNeighbor = oldParentNode[childKey][1];\r\n\t\t\t\t\toldNeighbor.isFirstNode = true;\r\n\t\t\t\t}\r\n\t\t\t} else if (node.isLastNode) {\r\n\t\t\t\ttmpSrcIndex = oldParentNode[childKey].length -1;\r\n\t\t\t\toldNeighbor = oldParentNode[childKey][tmpSrcIndex - 1];\r\n\t\t\t\toldNeighbor.isLastNode = true;\r\n\t\t\t} else {\r\n\t\t\t\tfor (i = 0, l = oldParentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\tif (oldParentNode[childKey][i].tId == node.tId) {\r\n\t\t\t\t\t\ttmpSrcIndex = i;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (tmpSrcIndex >= 0) {\r\n\t\t\t\toldParentNode[childKey].splice(tmpSrcIndex, 1);\r\n\t\t\t}\r\n\t\t\tif (moveType != consts.move.TYPE_INNER) {\r\n\t\t\t\tfor (i = 0, l = targetParentNode[childKey].length; i < l; i++) {\r\n\t\t\t\t\tif (targetParentNode[childKey][i].tId == targetNode.tId) tmpTargetIndex = i;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (moveType == consts.move.TYPE_INNER) {\r\n\t\t\t\tif (!targetNode[childKey]) targetNode[childKey] = new Array();\r\n\t\t\t\tif (targetNode[childKey].length > 0) {\r\n\t\t\t\t\tnewNeighbor = targetNode[childKey][targetNode[childKey].length - 1];\r\n\t\t\t\t\tnewNeighbor.isLastNode = false;\r\n\t\t\t\t}\r\n\t\t\t\ttargetNode[childKey].splice(targetNode[childKey].length, 0, node);\r\n\t\t\t\tnode.isLastNode = true;\r\n\t\t\t\tnode.isFirstNode = (targetNode[childKey].length == 1);\r\n\t\t\t} else if (targetNode.isFirstNode && moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex, 0, node);\r\n\t\t\t\tnewNeighbor = targetNode;\r\n\t\t\t\tnewNeighbor.isFirstNode = false;\r\n\t\t\t\tnode.parentTId = targetNode.parentTId;\r\n\t\t\t\tnode.isFirstNode = true;\r\n\t\t\t\tnode.isLastNode = false;\r\n\r\n\t\t\t} else if (targetNode.isLastNode && moveType == consts.move.TYPE_NEXT) {\r\n\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex + 1, 0, node);\r\n\t\t\t\tnewNeighbor = targetNode;\r\n\t\t\t\tnewNeighbor.isLastNode = false;\r\n\t\t\t\tnode.parentTId = targetNode.parentTId;\r\n\t\t\t\tnode.isFirstNode = false;\r\n\t\t\t\tnode.isLastNode = true;\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (moveType == consts.move.TYPE_PREV) {\r\n\t\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex, 0, node);\r\n\t\t\t\t} else {\r\n\t\t\t\t\ttargetParentNode[childKey].splice(tmpTargetIndex + 1, 0, node);\r\n\t\t\t\t}\r\n\t\t\t\tnode.parentTId = targetNode.parentTId;\r\n\t\t\t\tnode.isFirstNode = false;\r\n\t\t\t\tnode.isLastNode = false;\r\n\t\t\t}\r\n\t\t\tdata.fixPIdKeyValue(setting, node);\r\n\t\t\tdata.setSonNodeLevel(setting, node.getParentNode(), node);\r\n\r\n\t\t\t//repair node what been moved\r\n\t\t\tview.setNodeLineIcos(setting, node);\r\n\t\t\tview.repairNodeLevelClass(setting, node, oldLevel)\r\n\r\n\t\t\t//repair node's old parentNode dom\r\n\t\t\tif (!setting.data.keep.parent && oldParentNode[childKey].length < 1) {\r\n\t\t\t\t//old parentNode has no child nodes\r\n\t\t\t\toldParentNode.isParent = false;\r\n\t\t\t\toldParentNode.open = false;\r\n\t\t\t\tvar tmp_ulObj = $(\"#\" + oldParentNode.tId + consts.id.UL),\r\n\t\t\t\ttmp_switchObj = $(\"#\" + oldParentNode.tId + consts.id.SWITCH),\r\n\t\t\t\ttmp_icoObj = $(\"#\" + oldParentNode.tId + consts.id.ICON);\r\n\t\t\t\tview.replaceSwitchClass(oldParentNode, tmp_switchObj, consts.folder.DOCU);\r\n\t\t\t\tview.replaceIcoClass(oldParentNode, tmp_icoObj, consts.folder.DOCU);\r\n\t\t\t\ttmp_ulObj.css(\"display\", \"none\");\r\n\r\n\t\t\t} else if (oldNeighbor) {\r\n\t\t\t\t//old neigbor node\r\n\t\t\t\tview.setNodeLineIcos(setting, oldNeighbor);\r\n\t\t\t}\r\n\r\n\t\t\t//new neigbor node\r\n\t\t\tif (newNeighbor) {\r\n\t\t\t\tview.setNodeLineIcos(setting, newNeighbor);\r\n\t\t\t}\r\n\r\n\t\t\t//repair checkbox / radio\r\n\t\t\tif (!!setting.check && setting.check.enable && view.repairChkClass) {\r\n\t\t\t\tview.repairChkClass(setting, oldParentNode);\r\n\t\t\t\tview.repairParentChkClassWithSelf(setting, oldParentNode);\r\n\t\t\t\tif (oldParentNode != node.parent)\r\n\t\t\t\t\tview.repairParentChkClassWithSelf(setting, node);\r\n\t\t\t}\r\n\r\n\t\t\t//expand parents after move\r\n\t\t\tif (!isSilent) {\r\n\t\t\t\tview.expandCollapseParentNode(setting, node.getParentNode(), true, animateFlag);\r\n\t\t\t}\r\n\t\t},\r\n\t\tremoveEditBtn: function(node) {\r\n\t\t\t$(\"#\" + node.tId + consts.id.EDIT).unbind().remove();\r\n\t\t},\r\n\t\tremoveRemoveBtn: function(node) {\r\n\t\t\t$(\"#\" + node.tId + consts.id.REMOVE).unbind().remove();\r\n\t\t},\r\n\t\tremoveTreeDom: function(setting, node) {\r\n\t\t\tnode.isHover = false;\r\n\t\t\tview.removeEditBtn(node);\r\n\t\t\tview.removeRemoveBtn(node);\r\n\t\t\ttools.apply(setting.view.removeHoverDom, [setting.treeId, node]);\r\n\t\t},\r\n\t\trepairNodeLevelClass: function(setting, node, oldLevel) {\r\n\t\t\tif (oldLevel === node.level) return;\r\n\t\t\tvar liObj = $(\"#\" + node.tId),\r\n\t\t\taObj = $(\"#\" + node.tId + consts.id.A),\r\n\t\t\tulObj = $(\"#\" + node.tId + consts.id.UL),\r\n\t\t\toldClass = consts.className.LEVEL + oldLevel,\r\n\t\t\tnewClass = consts.className.LEVEL + node.level;\r\n\t\t\tliObj.removeClass(oldClass);\r\n\t\t\tliObj.addClass(newClass);\r\n\t\t\taObj.removeClass(oldClass);\r\n\t\t\taObj.addClass(newClass);\r\n\t\t\tulObj.removeClass(oldClass);\r\n\t\t\tulObj.addClass(newClass);\r\n\t\t}\r\n\t},\r\n\r\n\t_z = {\r\n\t\ttools: _tools,\r\n\t\tview: _view,\r\n\t\tevent: _event,\r\n\t\tdata: _data\r\n\t};\r\n\t$.extend(true, $.fn.zTree.consts, _consts);\r\n\t$.extend(true, $.fn.zTree._z, _z);\r\n\r\n\tvar zt = $.fn.zTree,\r\n\ttools = zt._z.tools,\r\n\tconsts = zt.consts,\r\n\tview = zt._z.view,\r\n\tdata = zt._z.data,\r\n\tevent = zt._z.event;\r\n\r\n\tdata.exSetting(_setting);\r\n\tdata.addInitBind(_bindEvent);\r\n\tdata.addInitUnBind(_unbindEvent);\r\n\tdata.addInitCache(_initCache);\r\n\tdata.addInitNode(_initNode);\r\n\tdata.addInitProxy(_eventProxy);\r\n\tdata.addInitRoot(_initRoot);\r\n\tdata.addZTreeTools(_zTreeTools);\r\n\r\n\tvar _cancelPreSelectedNode = view.cancelPreSelectedNode;\r\n\tview.cancelPreSelectedNode = function (setting, node) {\r\n\t\tvar list = data.getRoot(setting).curSelectedList;\r\n\t\tfor (var i=0, j=list.length; i<j; i++) {\r\n\t\t\tif (!node || node === list[i]) {\r\n\t\t\t\tview.removeTreeDom(setting, list[i]);\r\n\t\t\t\tif (node) break;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (_cancelPreSelectedNode) _cancelPreSelectedNode.apply(view, arguments);\r\n\t}\r\n\r\n\tvar _createNodes = view.createNodes;\r\n\tview.createNodes = function(setting, level, nodes, parentNode) {\r\n\t\tif (_createNodes) {\r\n\t\t\t_createNodes.apply(view, arguments);\r\n\t\t}\r\n\t\tif (!nodes) return;\r\n\t\tif (view.repairParentChkClassWithSelf) {\r\n\t\t\tview.repairParentChkClassWithSelf(setting, parentNode);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _makeNodeUrl = view.makeNodeUrl;\r\n\tview.makeNodeUrl = function(setting, node) {\r\n\t\treturn setting.edit.enable ? null : (_makeNodeUrl.apply(view, arguments));\r\n\t}\r\n\r\n\tvar _removeNode = view.removeNode;\r\n\tview.removeNode = function(setting, node) {\r\n\t\tvar root = data.getRoot(setting);\r\n\t\tif (root.curEditNode === node) root.curEditNode = null;\r\n\t\tif (_removeNode) {\r\n\t\t\t_removeNode.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _selectNode = view.selectNode;\r\n\tview.selectNode = function(setting, node, addFlag) {\r\n\t\tvar root = data.getRoot(setting);\r\n\t\tif (data.isSelectedNode(setting, node) && root.curEditNode == node && node.editNameFlag) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (_selectNode) _selectNode.apply(view, arguments);\r\n\t\tview.addHoverDom(setting, node);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tvar _uCanDo = tools.uCanDo;\r\n\ttools.uCanDo = function(setting, e) {\r\n\t\tvar root = data.getRoot(setting);\r\n\t\tif (e && (tools.eqs(e.type, \"mouseover\") || tools.eqs(e.type, \"mouseout\") || tools.eqs(e.type, \"mousedown\") || tools.eqs(e.type, \"mouseup\"))) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn (!root.curEditNode) && (_uCanDo ? _uCanDo.apply(view, arguments) : true);\r\n\t}\r\n})(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/js/jquery.ztree.exhide-3.5.js",
    "content": "/*\r\n * JQuery zTree exHideNodes 3.5.12\r\n * http://zTree.me/\r\n *\r\n * Copyright (c) 2010 Hunter.z\r\n *\r\n * Licensed same as jquery - MIT License\r\n * http://www.opensource.org/licenses/mit-license.php\r\n *\r\n * email: hunter.z@263.net\r\n * Date: 2013-03-11\r\n */\r\n(function($){\r\n\t//default init node of exLib\r\n\tvar _initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (typeof n.isHidden == \"string\") n.isHidden = tools.eqs(n.isHidden, \"true\");\r\n\t\tn.isHidden = !!n.isHidden;\r\n\t\tdata.initHideForExCheck(setting, n);\r\n\t},\r\n\t//add dom for check\r\n\t_beforeA = function(setting, node, html) {},\r\n\t//update zTreeObj, add method of exLib\r\n\t_zTreeTools = function(setting, zTreeTools) {\r\n\t\tzTreeTools.showNodes = function(nodes, options) {\r\n\t\t\tview.showNodes(setting, nodes, options);\r\n\t\t}\r\n\t\tzTreeTools.showNode = function(node, options) {\r\n\t\t\tif (!node) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tview.showNodes(setting, [node], options);\r\n\t\t}\r\n\t\tzTreeTools.hideNodes = function(nodes, options) {\r\n\t\t\tview.hideNodes(setting, nodes, options);\r\n\t\t}\r\n\t\tzTreeTools.hideNode = function(node, options) {\r\n\t\t\tif (!node) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tview.hideNodes(setting, [node], options);\r\n\t\t}\r\n\r\n\t\tvar _checkNode = zTreeTools.checkNode;\r\n\t\tif (_checkNode) {\r\n\t\t\tzTreeTools.checkNode = function(node, checked, checkTypeFlag, callbackFlag) {\r\n\t\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t_checkNode.apply(zTreeTools, arguments);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate data\r\n\t_data = {\r\n\t\tinitHideForExCheck: function(setting, n) {\r\n\t\t\tif (n.isHidden && setting.check && setting.check.enable) {\r\n\t\t\t\tif(typeof n._nocheck == \"undefined\") {\r\n\t\t\t\t\tn._nocheck = !!n.nocheck\r\n\t\t\t\t\tn.nocheck = true;\r\n\t\t\t\t}\r\n\t\t\t\tn.check_Child_State = -1;\r\n\t\t\t\tif (view.repairParentChkClassWithSelf) {\r\n\t\t\t\t\tview.repairParentChkClassWithSelf(setting, n);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tinitShowForExCheck: function(setting, n) {\r\n\t\t\tif (!n.isHidden && setting.check && setting.check.enable) {\r\n\t\t\t\tif(typeof n._nocheck != \"undefined\") {\r\n\t\t\t\t\tn.nocheck = n._nocheck;\r\n\t\t\t\t\tdelete n._nocheck;\r\n\t\t\t\t}\r\n\t\t\t\tif (view.setChkClass) {\r\n\t\t\t\t\tvar checkObj = $(\"#\" + n.tId + consts.id.CHECK);\r\n\t\t\t\t\tview.setChkClass(setting, checkObj, n);\r\n\t\t\t\t}\r\n\t\t\t\tif (view.repairParentChkClassWithSelf) {\r\n\t\t\t\t\tview.repairParentChkClassWithSelf(setting, n);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\t//method of operate ztree dom\r\n\t_view = {\r\n\t\tclearOldFirstNode: function(setting, node) {\r\n\t\t\tvar n = node.getNextNode();\r\n\t\t\twhile(!!n){\r\n\t\t\t\tif (n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = false;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (n.isLastNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tn = n.getNextNode();\r\n\t\t\t}\r\n\t\t},\r\n\t\tclearOldLastNode: function(setting, node) {\r\n\t\t\tvar n = node.getPreNode();\r\n\t\t\twhile(!!n){\r\n\t\t\t\tif (n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = false;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (n.isFirstNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tn = n.getPreNode();\r\n\t\t\t}\r\n\t\t},\r\n\t\tmakeDOMNodeMainBefore: function(html, setting, node) {\r\n\t\t\thtml.push(\"<li \", (node.isHidden ? \"style='display:none;' \" : \"\"), \"id='\", node.tId, \"' class='\", consts.className.LEVEL, node.level,\"' tabindex='0' hidefocus='true' treenode>\");\r\n\t\t},\r\n\t\tshowNode: function(setting, node, options) {\r\n\t\t\tnode.isHidden = false;\r\n\t\t\tdata.initShowForExCheck(setting, node);\r\n\t\t\t$(\"#\" + node.tId).show();\r\n\t\t},\r\n\t\tshowNodes: function(setting, nodes, options) {\r\n\t\t\tif (!nodes || nodes.length == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar pList = {}, i, j;\r\n\t\t\tfor (i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tvar n = nodes[i];\r\n\t\t\t\tif (!pList[n.parentTId]) {\r\n\t\t\t\t\tvar pn = n.getParentNode();\r\n\t\t\t\t\tpList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode();\r\n\t\t\t\t}\r\n\t\t\t\tview.showNode(setting, n, options);\r\n\t\t\t}\r\n\t\t\tfor (var tId in pList) {\r\n\t\t\t\tvar children = pList[tId][setting.data.key.children];\r\n\t\t\t\tview.setFirstNodeForShow(setting, children);\r\n\t\t\t\tview.setLastNodeForShow(setting, children);\r\n\t\t\t}\r\n\t\t},\r\n\t\thideNode: function(setting, node, options) {\r\n\t\t\tnode.isHidden = true;\r\n\t\t\tnode.isFirstNode = false;\r\n\t\t\tnode.isLastNode = false;\r\n\t\t\tdata.initHideForExCheck(setting, node);\r\n\t\t\tview.cancelPreSelectedNode(setting, node);\r\n\t\t\t$(\"#\" + node.tId).hide();\r\n\t\t},\r\n\t\thideNodes: function(setting, nodes, options) {\r\n\t\t\tif (!nodes || nodes.length == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar pList = {}, i, j;\r\n\t\t\tfor (i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tvar n = nodes[i];\r\n\t\t\t\tif ((n.isFirstNode || n.isLastNode) && !pList[n.parentTId]) {\r\n\t\t\t\t\tvar pn = n.getParentNode();\r\n\t\t\t\t\tpList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode();\r\n\t\t\t\t}\r\n\t\t\t\tview.hideNode(setting, n, options);\r\n\t\t\t}\r\n\t\t\tfor (var tId in pList) {\r\n\t\t\t\tvar children = pList[tId][setting.data.key.children];\r\n\t\t\t\tview.setFirstNodeForHide(setting, children);\r\n\t\t\t\tview.setLastNodeForHide(setting, children);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetFirstNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif (childLength > 0 && !parentNode[childKey][0].isHidden) {\r\n\t\t\t\tparentNode[childKey][0].isFirstNode = true;\r\n\t\t\t} else if (childLength > 0) {\r\n\t\t\t\tview.setFirstNodeForHide(setting, parentNode[childKey]);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetLastNode: function(setting, parentNode) {\r\n\t\t\tvar childKey = setting.data.key.children, childLength = parentNode[childKey].length;\r\n\t\t\tif (childLength > 0 && !parentNode[childKey][0].isHidden) {\r\n\t\t\t\tparentNode[childKey][childLength - 1].isLastNode = true;\r\n\t\t\t} else if (childLength > 0) {\r\n\t\t\t\tview.setLastNodeForHide(setting, parentNode[childKey]);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsetFirstNodeForHide: function(setting, nodes) {\r\n\t\t\tvar n,i,j;\r\n\t\t\tfor (i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (n.isFirstNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (!n.isHidden && !n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = true;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn n;\r\n\t\t},\r\n\t\tsetFirstNodeForShow: function(setting, nodes) {\r\n\t\t\tvar n,i,j, first, old;\r\n\t\t\tfor(i=0, j=nodes.length; i<j; i++) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (!first && !n.isHidden && n.isFirstNode) {\r\n\t\t\t\t\tfirst = n;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else if (!first && !n.isHidden && !n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = true;\r\n\t\t\t\t\tfirst = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t} else if (first && n.isFirstNode) {\r\n\t\t\t\t\tn.isFirstNode = false;\r\n\t\t\t\t\told = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn {\"new\":first, \"old\":old};\r\n\t\t},\r\n\t\tsetLastNodeForHide: function(setting, nodes) {\r\n\t\t\tvar n,i;\r\n\t\t\tfor (i=nodes.length-1; i>=0; i--) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (n.isLastNode) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (!n.isHidden && !n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = true;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn n;\r\n\t\t},\r\n\t\tsetLastNodeForShow: function(setting, nodes) {\r\n\t\t\tvar n,i,j, last, old;\r\n\t\t\tfor (i=nodes.length-1; i>=0; i--) {\r\n\t\t\t\tn = nodes[i];\r\n\t\t\t\tif (!last && !n.isHidden && n.isLastNode) {\r\n\t\t\t\t\tlast = n;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else if (!last && !n.isHidden && !n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = true;\r\n\t\t\t\t\tlast = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t} else if (last && n.isLastNode) {\r\n\t\t\t\t\tn.isLastNode = false;\r\n\t\t\t\t\told = n;\r\n\t\t\t\t\tview.setNodeLineIcos(setting, n);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tn = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn {\"new\":last, \"old\":old};\r\n\t\t}\r\n\t},\r\n\r\n\t_z = {\r\n\t\tview: _view,\r\n\t\tdata: _data\r\n\t};\r\n\t$.extend(true, $.fn.zTree._z, _z);\r\n\r\n\tvar zt = $.fn.zTree,\r\n\ttools = zt._z.tools,\r\n\tconsts = zt.consts,\r\n\tview = zt._z.view,\r\n\tdata = zt._z.data,\r\n\tevent = zt._z.event;\r\n\r\n\tdata.addInitNode(_initNode);\r\n\tdata.addBeforeA(_beforeA);\r\n\tdata.addZTreeTools(_zTreeTools);\r\n\r\n//\tOverride method in core\r\n\tvar _dInitNode = data.initNode;\r\n\tdata.tmpHideParent = -1;\r\n\tdata.initNode = function(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag) {\r\n\t\tif (data.tmpHideParent !== parentNode) {\r\n\t\t\tdata.tmpHideParent = parentNode;\r\n\t\t\tvar tmpPNode = (parentNode) ? parentNode: data.getRoot(setting),\r\n\t\t\tchildren = tmpPNode[setting.data.key.children];\r\n\t\t\tdata.tmpHideFirstNode = view.setFirstNodeForHide(setting, children);\r\n\t\t\tdata.tmpHideLastNode = view.setLastNodeForHide(setting, children);\r\n\t\t\tview.setNodeLineIcos(setting, data.tmpHideFirstNode);\r\n\t\t\tview.setNodeLineIcos(setting, data.tmpHideLastNode);\r\n\t\t}\r\n\t\tisFirstNode = (data.tmpHideFirstNode === node);\r\n\t\tisLastNode = (data.tmpHideLastNode === node);\r\n\t\tif (_dInitNode) _dInitNode.apply(data, arguments);\r\n\t\tif (isLastNode) {\r\n\t\t\tview.clearOldLastNode(setting, node);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _makeChkFlag = data.makeChkFlag;\r\n\tif (!!_makeChkFlag) {\r\n\t\tdata.makeChkFlag = function(setting, node) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_makeChkFlag.apply(data, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _getTreeCheckedNodes = data.getTreeCheckedNodes;\r\n\tif (!!_getTreeCheckedNodes) {\r\n\t\tdata.getTreeCheckedNodes = function(setting, nodes, checked, results) {\r\n\t\t\tif (!!nodes && nodes.length > 0) {\r\n\t\t\t\tvar p = nodes[0].getParentNode();\r\n\t\t\t\tif (!!p && !!p.isHidden) {\r\n\t\t\t\t\treturn [];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn _getTreeCheckedNodes.apply(data, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _getTreeChangeCheckedNodes = data.getTreeChangeCheckedNodes;\r\n\tif (!!_getTreeChangeCheckedNodes) {\r\n\t\tdata.getTreeChangeCheckedNodes = function(setting, nodes, results) {\r\n\t\t\tif (!!nodes && nodes.length > 0) {\r\n\t\t\t\tvar p = nodes[0].getParentNode();\r\n\t\t\t\tif (!!p && !!p.isHidden) {\r\n\t\t\t\t\treturn [];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn _getTreeChangeCheckedNodes.apply(data, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _expandCollapseSonNode = view.expandCollapseSonNode;\r\n\tif (!!_expandCollapseSonNode) {\r\n\t\tview.expandCollapseSonNode = function(setting, node, expandFlag, animateFlag, callback) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_expandCollapseSonNode.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _setSonNodeCheckBox = view.setSonNodeCheckBox;\r\n\tif (!!_setSonNodeCheckBox) {\r\n\t\tview.setSonNodeCheckBox = function(setting, node, value, srcNode) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_setSonNodeCheckBox.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n\r\n\tvar _repairParentChkClassWithSelf = view.repairParentChkClassWithSelf;\r\n\tif (!!_repairParentChkClassWithSelf) {\r\n\t\tview.repairParentChkClassWithSelf = function(setting, node) {\r\n\t\t\tif (!!node && !!node.isHidden) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t_repairParentChkClassWithSelf.apply(view, arguments);\r\n\t\t}\r\n\t}\r\n})(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jquery-ztree/3.5/log v3.x.txt",
    "content": "﻿=ZTree v3.x (JQuery Tree插件) 更新日志=\r\n\r\n<font color=\"red\">为了更好的优化及扩展zTree, 因此决定升级为v3.x，并且对之前的v2.x不兼容，会有很多结构上的修改，对此深感无奈与抱歉，请大家谅解。</font>\r\n<font color=\"red\">\r\n\r\n具体修改内容可参考：\r\n\r\n   * [http://www.ztree.me/v3/api.php zTree v3.0 API 文档]\r\n\r\n   * [http://www.ztree.me/v3/demo.php#_101 zTree v3.0 Demo 演示]\r\n\r\n   * [http://www.ztree.me/v3/faq.php#_101 zTree v3.0 常见问题]\r\n\r\n</font>\r\n\r\n<font color=#041594>\r\n*2013.03.11* v3.5.12\r\n   * 【修改】由于 jquery 1.9 中移除 event.srcElement 导致的 js 报错的bug。\r\n   * 【修改】在异步加载模式下，使用 moveNode 方法，且 moveType != \"inner\" 时，也会导致 targetNode 自动加载子节点的 bug\r\n   * 【修改】对已经显示的节点(nochecked=true)使用 showNodes 或 showNode 方法后，导致勾选框出现的bug。\r\n   * 【修改】对已经隐藏的节点(nochecked=false)使用 hideNodes 或 hideNode 方法后，导致勾选框消失的bug。\r\n   * 【修改】getNodesByParamFuzzy 支持 大小写模糊。\r\n   * 【修改】className 结构，提取 _consts.className.BUTTON / LEVEL / ICO_LOADING / SWITCH，便于快速修改 css 冲突。\r\n     例如：与 WordPress 产生冲突后，直接修改 core 中的 \"button\" 和 \"level\" 即可。  Issue: https://github.com/zTree/zTree_v3/issues/2\r\n\r\n*2013.01.28* v3.5.02\r\n   * 【增加】setting.check.chkDisabledInherit 属性，用于设置 chkDisabled 在初始化时子节点是否可以继承父节点的 chkDisabled 属性\r\n   * 【删除】内部 noSel 方法，使用 selectstart事件 和 \"-moz-user-select\"样式 处理禁止 节点文字被选择的功能\r\n   * 【修改】不兼容 jQuery 1.9 的bug\r\n   * 【修改】onDrop 的触发规则，保证异步加载模式下，可以在延迟加载结束后触发，避免 onDrop 中被拖拽的节点是已经更新后的数据。\r\n   * 【修改】setChkDisabled 方法，增加 inheritParent, inheritChildren 参数设置是否让父子节点继承 disabled\r\n   * 【修改】异步加载时 拼接参数的方法，由 string 修改为 json 对象\r\n   * 【修正】1-2-3 3级节点时，如果 2级节点 全部设置为 nocheck 或 chkDisabled后，勾选3级节点时，1级节点的半勾选状态错误的 bug\r\n   * 【修改】Demo: checkbox_nocheck.html & checkbox_chkDisabled.html;\r\n   * 【修改】Demo: edit_super.html，增加 showRenameBtn & showRemoveBtn 的演示\r\n   * 【修改】Demo: asyncForAll, 将 post 修改为 get；为了避免由于 IE10 的 bug 造成的客户端 以及 服务端崩溃\r\n      IE10 ajax Post 无法提交参数的bug (http://bugs.jquery.com/ticket/12790)\r\n\r\n*2012.12.21* v3.5.01\r\n   * 【优化】clone 方法\r\n   * 【修正】对于初始化无 children 属性的父节点进行 reAsyncChildNodes 操作时出错的 bug\r\n   * 【修正】beforeRename 回调中使用 cancelEditName 方法后，再 return false 导致无法重新进行编辑的 bug\r\n   * 【修正】exedit 扩展包让 setting.data.key.url 失效的 bug\r\n   * 【修正】setting.check.autoCheckTrigger 设置为 true 时，onCheck 回调缺少 event 参数的 bug\r\n   * 【修正】singlepath.html Demo 中的 bug\r\n\r\n*2012.11.20* v3.5\r\n   * 【优化】原先的 clone 方法 （特别感谢：愚人码头）\r\n   * 【修改】隐藏父节点后，使用 expandAll 方法导致 父节点展开的 bug\r\n   * 【修改】使用 jQuery v1.7 以上时，设置 zTree 容器 ul 隐藏（visibility: hidden;）后， 调用 selectNode 导致 IE 浏览器报错 Can't move focus 的 bug\r\n   * 【修改】正在异步加载时，执行 destory 或 init 方法后，异步加载的节点影响新树的 bug\r\n   * 【修改】方法 reAsyncChildNodes 在 refresh 的时候未清空内部 cache 导致内存泄露 的 bug\r\n   * 【修改】批量节点拖拽到其他父节点内（inner）时，导致顺序反转 的 bug\r\n   * 【修改】对于 使用 html格式的 节点无法触发 双击事件 的 bug\r\n   * 【修改】onCheck 回调中的 event ，保证与触发事件中的 event 一致\r\n   * 【修改】异步加载时，在 onNodeCreated 中执行 selectNode 后，导致节点折叠的 bug\r\n   * 【修改】API 中 dataFilter 的参数名称 childNodes ->  responseData\r\n   * 【修改】API 中 iconSkin 的 举例内容\r\n   * 【修改】API 中 chkDisabled 的说明\r\n   * 【修改】Demo 中 index.html 内的 loadReady 重复绑定问题\r\n\r\n*2012.09.03* v3.4\r\n   * 【增加】 Demo —— OutLook 样式的左侧菜单\r\n   * 【增加】清空 zTree 的方法 $.fn.zTree.destory(treeId) & zTree.destory()\r\n\r\n   * 【修改】core核心文件内 _eventProxy 方法中获取 tId 的方法，提高 DOM 的灵活性\r\n   * 【修改】初始化时 多层父节点的 checkbox 半选状态计算错误的 bug\r\n   * 【修改】同时选中父、子节点后，利用 getSelectedNodes 获取选中节点并利用 removeNode 删除时报错的 bug\r\n   * 【修改】treeNode.chkDisabled / nocheck 属性，支持字符串格式的 \"false\"/\"true\"\r\n   * 【修改】异步加载模式下无法利用 server 返回 xml 并且 在 dataFilter 中继续处理的 bug\r\n   * 【修改】title 只允许设置为 string 类型值的问题。 修正后允许设置为 number 类型的值\r\n   * 【修改】zId 计数规则 & Cache 保存，减少 IE9 的 bug 造成的内存泄漏\r\n   * 【修改】API 页面搜索功能导致 IE 崩溃的 bug\r\n\r\n*2012.07.16* v3.3\r\n   * 【增加】扩展库 exhide -- 节点隐藏功能\r\n\r\n   * 【修改】getNodesByFilter 方法，添加 invokeParam 自定义参数\r\n   * 【修改】拖拽中测试代码未删除，导致出现黄颜色的 iframe 遮罩层的 bug\r\n   * 【修改】延迟加载方法 对于使用 expandAll 进行全部展开时，导致 onNodeCreated 回调 和 addDiyDom 方法触发过早的 bug\r\n   * 【修改】使用 moveNode 移动尚未生成 DOM 的节点时，视图会出现异常的 bug\r\n   * 【修改】删除节点后，相关节点的 isFirstNode 属性未重置的 bug\r\n   * 【修改】getPreNode(),getNextNode() 方法在对于特殊情况时计算错误的 bug\r\n   * 【修改】设置 title 之后，如果重新将 title 内容设置为空后，会导致无法更新 title 的 bug\r\n   * 【修改】针对 setting.check.chkStyle==\"radio\" && setting.check.radioType==\"all\" 的情况时，getTreeCheckedNodes方法优化，找到一个结果就 break\r\n   * 【修改】zTreeObj.getCheckedNodes(false) 在 radioType = \"all\" 时计算错误的 bug\r\n   * 【修改】完善 API 中 beforeDrop / onDrop 的关于 treeId 的说明\r\n\r\n*2012.05.13* v3.2\r\n   * 【增加】setting.data.key.url 允许修改 treeNode.url 属性\r\n   * 【增加】getNodesByFilter(filter, isSingle) 方法\r\n   * 【增加】\"与其他 DOM 拖拽互动\" 的 Demo (http://www.ztree.me/v3/demo.php#_511)\r\n   * 【增加】\"异步加载模式下全部展开\" 的 Demo (http://www.ztree.me/v3/demo.php#_512)\r\n\r\n   * 【修改】代码结构，将 addNodes、removeNode、removeChildNodes 方法 和 beforeRemove、onRemove 回调 转移到 core 内\r\n   * 【修改】IE7的环境下无子节点的父节点反复展开出现多余空行的 bug\r\n   * 【修改】异步加载时，如果出现网络异常等，会导致 图标显示错误的 bug\r\n   * 【修改】dataFilter中 return null 导致异常 的 bug\r\n   * 【修改】removeChildNodes 方法清空子节点后，无法正常添加节点的 bug\r\n   * 【修改】moveNode 后节点中的自定义元素的事件丢失的 bug\r\n   * 【修改】moveNode 方法中设置 isSilent = true 时，如果移动到已展开的 父节点后，出现异常的 bug\r\n   * 【修改】onClick/onDrag/onDrop 回调中 event 不是原始 event 的 bug\r\n   * 【修改】onDrop 回调中 当拖拽无效时，无法获得 treeNodes 的 bug\r\n   * 【修改】onDrop 无法判断拖拽是 移动还是复制的问题\r\n   * 【修改】未开启异步加载模式时，拖拽节点到子节点为空的父节点内时 出现异常 的 bug\r\n   * 【修改】拖拽过程中，反复在 父节点图标上划动时，会出现停顿的 bug\r\n            (需要css 结构—— button -> span.button)\r\n\r\n   * 【修改】拖拽操作时箭头 与 targetNode 背景之间的细节现实问题，便于用户拖拽时更容易区分 prev、next 和 inner 操作\r\n   * 【修改】拖拽操作时IE6/7 下 在 节点<a> 右侧 10px 内会导致 targetNode = root 的 bug\r\n   * 【修改】编辑模式下 默认的编辑按钮、删除按钮点击后，如果相应的 before 回调 return false 时会触发 onClick 回调的 bug\r\n\r\n*2012.02.14* v3.1\r\n   * 【增加】ajax 的参数 setting.async.contentType ，让提交参数适用于 json 数据提交 （主要适用于 .Net 的开发）。\r\n   * 【增加】setting.edit.editNameSelectAll, 用于设定编辑节点名称时初次显示 input 后 text 内容为全选\r\n   * 【修改】异步加载 规则，不再仅仅依靠父节点的子节点数来判定，增加内部属性 zAsync，保证默认状态下父节点及时无子节点也只能异步加载一次，除非使用 reAsyncChildNodes 方法强行控制异步加载。\r\n   * 【修改】放大浏览器后导致 界面出现多余连接线的bug （需要更新：icon 图标和 css ）\r\n   * 【修改】在编辑状态，如果节点名超过编辑框宽度，左右键在框内不起作用的bug（IE 6 7 8 出现）\r\n      CSS 中 filter:alpha(opacity=80) 造成的，应该是 ie 的 bug，需要更新 css 文件\r\n   * 【修改】title 设置后，如果属性不存在，则默认为 title 为空，便于数据容错和用户灵活使用\r\n   * 【修改】editName 方法如果针对尚未展开的 父节点，会导致该父节点自动展开的 bug\r\n   * 【修改】title 中存在标签时导致 title 显示异常的bug（例如：蓝色字22%\"'`<input/>`）\r\n\r\n*2012.01.10* v3.0\r\n   * 【增加】setting.check.autoCheckTrigger 默认值 false，可以设置联动选中时是否触发事件回调函数\r\n   * 【增加】setting.callback.beforeEditName 回调函数，以保证用户可以捕获点击编辑按钮的事件\r\n   * 【增加】treeNode.chkDisabled 属性，显示 checkbox 但是用户无法修改 checkbox 状态，并且该 checkbox 会影响父节点的 checkbox 的半选状态\r\n   * 【增加】setting.check.nocheckInherit 属性，用户设置子节点继承 nocheck 属性，用于批量初始化节点，不适用于已经显示的节点\r\n   * 【增加】setting.edit.drag.autoExpandTrigger 默认值 false，可以设置自动展开、折叠操作时是否触发事件回调函数\r\n   * 【增加】setting.view.nameIsHTML 默认值 false，允许用户对 name 设置 DOM 对象\r\n   * 【增加】treeNode.click 属性的说明文档\r\n   * 【增加】treeObj.setChkDisabled 方法用于设置 checkbox / radio disabled 状态\r\n   * 【增加】treeNode.halfCheck 属性，用于强制设定节点的半选状态\r\n\r\n   * 【修改】异步加载 & 编辑功能 共存时，拖拽节点 或 增加节点 导致 ie 上报错的 bug （apply 方法引起）\r\n   * 【修改】zTreeStyle 样式冲突\r\n   * 【修改】setting.data.key.title 默认值设置为 \"\"，初始化时自动赋值为 setting.data.key.name 这样可避免希望 title 与 name 一致的用户反复设置参数\r\n   * 【修改】点击叶子节点的连接线会触发 expand 事件的 bug\r\n   * 【修改】IE 下 点击叶子节点连线会出现虚线框的 bug\r\n   * 【修改】updateNode 导致 checkbox 半选状态错误的 bug\r\n   * 【修改】checkNode 方法实现 toggle 操作, 取消 expandAll 方法的 toggle 操作\r\n   * 【修改】zTree 内鼠标移动会抢页面上 input 内的焦点的 bug\r\n   * 【修改】beforeRename / onRename 的触发方式——即使名称内容未改变也会触发，便于用户配合 beforeEditName 捕获编辑状态的结束，赋予用户更多调整规则的权利\r\n   * 【修改】与 easyUI 共存时无法拖拽的bug\r\n   * 【修改】beforeRename 在 Firefox 下如果利用 alert，会触发两次的 bug\r\n   * 【修改】checkNode/expandNode/removeNode 方法，默认不触发回调函数，恢复 v2.6 的默认状态，同时增加 callbackFlag 参数，设置为 true 时，可以触发回调函数\r\n   * 【修改】IE9下“根据参数查找节点”的Demo 报错：行14 重新声明常量属性(Demo 自身的问题，定义了history变量)\r\n   * 【修改】初始化 zTree 时 onNodeCreated 事件回调函数中无法 用 getZTreeObj 获取 zTree 对象的 bug\r\n   * 【修改】setting.edit.drag.prev / next / inner 参数，增加被拖拽的节点集合\r\n   * 【修改】异步加载模式下，otherParam 使用Array数组会出错的 bug。例如： [\"id\", \"1\", \"name\", \"test\"]\r\n   * 【修改】FireFox 下多棵树拖拽异常的 bug\r\n   * 【修改】exedit 中调用 excheck库的方法时没有进行容错处理，导致如果只加入 exedit 而没有 excheck的时候，会出现 js 错误\r\n   * 【修改】显示 checkbox 的 zTree 在编辑模式下，移动节点不会更新父节点半选状态的 bug\r\n   * 【修改】treeNode.childs --> children; treeObject.removeChilds --> removeChildNodes; setting.data.key.childs --> children（英文不好惹的祸！抱歉了！）\r\n   * 【修改】onRemove 回调中得到的 treeNode 还可以查找 preNode、nextNode 的bug。 修正后，getPreNode 和 getNextNode 都返回 null； 为了便于查找父节点，getParentNode 仍保留\r\n   * 【修改】简单数据模式下，如果 id 与 pId 的值相同会导致该节点无法正常加载的 bug\r\n   * 【修改】移动或删除中间节点会导致最后一个节点连接线图标变小的 bug\r\n\r\n*2011.09.05* v3.0 beta\r\n   * 【修改】zTree 的 js 代码架构全面修改，并且拆分\r\n   * 【修改】zTree 的 css 样式全面修改，对浏览器可以更好地兼容，同时解决了以前1个像素差的问题\r\n   * 【优化】采用延迟加载技术，一次性加载大数据量的节点性能飞速提升\r\n   * 【增加】支持多节点同时选中、拖拽\r\n   * 【增加】checkNode、checkAllNodes 等多种方法\r\n   * 【增加】IE6 自动取消动画展开、折叠的功能\r\n   * 【修正】异步加载 & 编辑模式 能够更完美的共存\r\n   * 【修正】setting 配置更加合理，并且增加了若干项配置参数\r\n   * 【修正】treeNode 节点数据的属性更加合理，并且增加了一些方法\r\n   * 【修正】拖拽操作更加灵活方便，更容易制定自己的规则\r\n   * 【修正】其他若干修改，详细对比请参考 url：[http://www.ztree.me/v3/faq.php#_101 zTree v3.0 常见问题]\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jsonview/jquery.jsonview.css",
    "content": "@charset \"UTF-8\";\n.jsonview {\n  font-family: monospace;\n  font-size: 1.1em;\n  white-space: pre-wrap; }\n  .jsonview .prop {\n    font-weight: bold; }\n  .jsonview .null {\n    color: red; }\n  .jsonview .bool {\n    color: blue; }\n  .jsonview .num {\n    color: blue; }\n  .jsonview .string {\n    color: green;\n    white-space: pre-wrap; }\n    .jsonview .string.multiline {\n      display: inline-block;\n      vertical-align: text-top; }\n  .jsonview .collapser {\n    position: absolute;\n    left: -1em;\n    cursor: pointer; }\n  .jsonview .collapsible {\n    transition: height 1.2s;\n    transition: width 1.2s; }\n  .jsonview .collapsible.collapsed {\n    height: .8em;\n    width: 1em;\n    display: inline-block;\n    overflow: hidden;\n    margin: 0; }\n  .jsonview .collapsible.collapsed:before {\n    content: \"…\";\n    width: 1em;\n    margin-left: .2em; }\n  .jsonview .collapser.collapsed {\n    transform: rotate(0deg); }\n  .jsonview .q {\n    display: inline-block;\n    width: 0px;\n    color: transparent; }\n  .jsonview li {\n    position: relative; }\n  .jsonview ul {\n    list-style: none;\n    margin: 0 0 0 2em;\n    padding: 0; }\n  .jsonview h1 {\n    font-size: 1.2em; }\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/jsonview/jquery.jsonview.js",
    "content": "(function(jQuery) {\n  var $, Collapser, JSONFormatter, JSONView;\n  JSONFormatter = (function() {\n    function JSONFormatter(options) {\n      if (options == null) {\n        options = {};\n      }\n      this.options = options;\n    }\n\n    JSONFormatter.prototype.htmlEncode = function(html) {\n      if (html !== null) {\n        return html.toString().replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n      } else {\n        return '';\n      }\n    };\n\n    JSONFormatter.prototype.jsString = function(s) {\n      s = JSON.stringify(s).slice(1, -1);\n      return this.htmlEncode(s);\n    };\n\n    JSONFormatter.prototype.decorateWithSpan = function(value, className) {\n      return \"<span class=\\\"\" + className + \"\\\">\" + (this.htmlEncode(value)) + \"</span>\";\n    };\n\n    JSONFormatter.prototype.valueToHTML = function(value, level) {\n      var valueType;\n      if (level == null) {\n        level = 0;\n      }\n      valueType = Object.prototype.toString.call(value).match(/\\s(.+)]/)[1].toLowerCase();\n      return this[\"\" + valueType + \"ToHTML\"].call(this, value, level);\n    };\n\n    JSONFormatter.prototype.nullToHTML = function(value) {\n      return this.decorateWithSpan('null', 'null');\n    };\n\n    JSONFormatter.prototype.numberToHTML = function(value) {\n      return this.decorateWithSpan(value, 'num');\n    };\n\n    JSONFormatter.prototype.stringToHTML = function(value) {\n      var multilineClass, newLinePattern;\n      if (/^(http|https|file):\\/\\/[^\\s]+$/i.test(value)) {\n        return \"<a href=\\\"\" + (this.htmlEncode(value)) + \"\\\"><span class=\\\"q\\\">\\\"</span>\" + (this.jsString(value)) + \"<span class=\\\"q\\\">\\\"</span></a>\";\n      } else {\n        multilineClass = '';\n        value = this.jsString(value);\n        if (this.options.nl2br) {\n          newLinePattern = /([^>\\\\r\\\\n]?)(\\\\r\\\\n|\\\\n\\\\r|\\\\r|\\\\n)/g;\n          if (newLinePattern.test(value)) {\n            multilineClass = ' multiline';\n            value = (value + '').replace(newLinePattern, '$1' + '<br />');\n          }\n        }\n        return \"<span class=\\\"string\" + multilineClass + \"\\\">\\\"\" + value + \"\\\"</span>\";\n      }\n    };\n\n    JSONFormatter.prototype.booleanToHTML = function(value) {\n      return this.decorateWithSpan(value, 'bool');\n    };\n\n    JSONFormatter.prototype.arrayToHTML = function(array, level) {\n      var collapsible, hasContents, index, numProps, output, value, _i, _len;\n      if (level == null) {\n        level = 0;\n      }\n      hasContents = false;\n      output = '';\n      numProps = array.length;\n      for (index = _i = 0, _len = array.length; _i < _len; index = ++_i) {\n        value = array[index];\n        hasContents = true;\n        output += '<li>' + this.valueToHTML(value, level + 1);\n        if (numProps > 1) {\n          output += ',';\n        }\n        output += '</li>';\n        numProps--;\n      }\n      if (hasContents) {\n        collapsible = level === 0 ? '' : ' collapsible';\n        return \"[<ul class=\\\"array level\" + level + collapsible + \"\\\">\" + output + \"</ul>]\";\n      } else {\n        return '[ ]';\n      }\n    };\n\n    JSONFormatter.prototype.objectToHTML = function(object, level) {\n      var collapsible, hasContents, numProps, output, prop, value;\n      if (level == null) {\n        level = 0;\n      }\n      hasContents = false;\n      output = '';\n      numProps = 0;\n      for (prop in object) {\n        numProps++;\n      }\n      for (prop in object) {\n        value = object[prop];\n        hasContents = true;\n        output += \"<li><span class=\\\"prop\\\"><span class=\\\"q\\\">\\\"</span>\" + (this.jsString(prop)) + \"<span class=\\\"q\\\">\\\"</span></span>: \" + (this.valueToHTML(value, level + 1));\n        if (numProps > 1) {\n          output += ',';\n        }\n        output += '</li>';\n        numProps--;\n      }\n      if (hasContents) {\n        collapsible = level === 0 ? '' : ' collapsible';\n        return \"{<ul class=\\\"obj level\" + level + collapsible + \"\\\">\" + output + \"</ul>}\";\n      } else {\n        return '{ }';\n      }\n    };\n\n    JSONFormatter.prototype.jsonToHTML = function(json) {\n      return \"<div class=\\\"jsonview\\\">\" + (this.valueToHTML(json)) + \"</div>\";\n    };\n\n    return JSONFormatter;\n\n  })();\n  (typeof module !== \"undefined\" && module !== null) && (module.exports = JSONFormatter);\n  Collapser = {\n    bindEvent: function(item, collapsed) {\n      var collapser;\n      collapser = document.createElement('div');\n      collapser.className = 'collapser';\n      collapser.innerHTML = collapsed ? '+' : '-';\n      collapser.addEventListener('click', (function(_this) {\n        return function(event) {\n          return _this.toggle(event.target);\n        };\n      })(this));\n      item.insertBefore(collapser, item.firstChild);\n      if (collapsed) {\n        return this.collapse(collapser);\n      }\n    },\n    expand: function(collapser) {\n      var ellipsis, target;\n      target = this.collapseTarget(collapser);\n      ellipsis = target.parentNode.getElementsByClassName('ellipsis')[0];\n      target.parentNode.removeChild(ellipsis);\n      target.style.display = '';\n      return collapser.innerHTML = '-';\n    },\n    collapse: function(collapser) {\n      var ellipsis, target;\n      target = this.collapseTarget(collapser);\n      target.style.display = 'none';\n      ellipsis = document.createElement('span');\n      ellipsis.className = 'ellipsis';\n      ellipsis.innerHTML = ' &hellip; ';\n      target.parentNode.insertBefore(ellipsis, target);\n      return collapser.innerHTML = '+';\n    },\n    toggle: function(collapser) {\n      var target;\n      target = this.collapseTarget(collapser);\n      if (target.style.display === 'none') {\n        return this.expand(collapser);\n      } else {\n        return this.collapse(collapser);\n      }\n    },\n    collapseTarget: function(collapser) {\n      var target, targets;\n      targets = collapser.parentNode.getElementsByClassName('collapsible');\n      if (!targets.length) {\n        return;\n      }\n      return target = targets[0];\n    }\n  };\n  $ = jQuery;\n  JSONView = {\n    collapse: function(el) {\n      if (el.innerHTML === '-') {\n        return Collapser.collapse(el);\n      }\n    },\n    expand: function(el) {\n      if (el.innerHTML === '+') {\n        return Collapser.expand(el);\n      }\n    },\n    toggle: function(el) {\n      return Collapser.toggle(el);\n    }\n  };\n  return $.fn.JSONView = function() {\n    var args, defaultOptions, formatter, json, method, options, outputDoc;\n    args = arguments;\n    if (JSONView[args[0]] != null) {\n      method = args[0];\n      return this.each(function() {\n        var $this, level;\n        $this = $(this);\n        if (args[1] != null) {\n          level = args[1];\n          return $this.find(\".jsonview .collapsible.level\" + level).siblings('.collapser').each(function() {\n            return JSONView[method](this);\n          });\n        } else {\n          return $this.find('.jsonview > ul > li > .collapsible').siblings('.collapser').each(function() {\n            return JSONView[method](this);\n          });\n        }\n      });\n    } else {\n      json = args[0];\n      options = args[1] || {};\n      defaultOptions = {\n        collapsed: false,\n        nl2br: false\n      };\n      options = $.extend(defaultOptions, options);\n      formatter = new JSONFormatter({\n        nl2br: options.nl2br\n      });\n      if (Object.prototype.toString.call(json) === '[object String]') {\n        json = JSON.parse(json);\n      }\n      outputDoc = formatter.jsonToHTML(json);\n      return this.each(function() {\n        var $this, item, items, _i, _len, _results;\n        $this = $(this);\n        $this.html(outputDoc);\n        items = $this[0].getElementsByClassName('collapsible');\n        _results = [];\n        for (_i = 0, _len = items.length; _i < _len; _i++) {\n          item = items[_i];\n          if (item.parentNode.nodeName === 'LI') {\n            _results.push(Collapser.bindEvent(item.parentNode, options.collapsed));\n          } else {\n            _results.push(void 0);\n          }\n        }\n        return _results;\n      });\n    }\n  };\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/layer/css/layer.css",
    "content": "html #layuicss-layer{display: none; position: absolute; width: 1989px;}\n\n/* common */\n.layui-layer-shade, .layui-layer{position:fixed; _position:absolute; pointer-events: auto;}\n.layui-layer-shade{top:0; left:0; width:100%; height:100%; _height:expression(document.body.offsetHeight+\"px\");}\n.layui-layer{-webkit-overflow-scrolling: touch;}\n.layui-layer{top:150px; left: 0; margin:0; padding:0; background-color:#fff; -webkit-background-clip: content; border-radius: 2px; box-shadow: 1px 1px 50px rgba(0,0,0,.3);}\n.layui-layer-close{position:absolute;}\n.layui-layer-content{position:relative;}\n.layui-layer-border{border: 1px solid #B2B2B2; border: 1px solid rgba(0,0,0,.1); box-shadow: 1px 1px 5px rgba(0,0,0,.2);}\n.layui-layer-setwin span,\n.layui-layer-btn a{display: inline-block; vertical-align: middle; *display: inline; *zoom:1; }\n\n.layui-layer-move{display: none; position: fixed; *position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; cursor: move; opacity: 0; filter:alpha(opacity=0); background-color: #fff; z-index: 2147483647;}\n.layui-layer-resize{position: absolute; width: 15px; height: 15px; right: 0; bottom: 0; cursor: se-resize;}\n\n/* 动画 */\n.layer-anim{-webkit-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration:.3s; animation-duration:.3s;}\n\n@-webkit-keyframes layer-bounceIn { /* 默认 */\n\t0% {opacity: 0; -webkit-transform: scale(.5); transform: scale(.5)}\n\t100% {opacity: 1; -webkit-transform: scale(1); transform: scale(1)}\n}\n@keyframes layer-bounceIn {\n\t0% {opacity: 0; -webkit-transform: scale(.5); -ms-transform: scale(.5); transform: scale(.5)}\n\t100% {opacity: 1; -webkit-transform: scale(1); -ms-transform: scale(1); transform: scale(1)}\n}\n.layer-anim-00{-webkit-animation-name: layer-bounceIn;animation-name: layer-bounceIn}\n\n@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}\n\n@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}\n\n@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}\n\n@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);-ms-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}\n\n@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}\n\n@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}\n\n/* 从上往下 */\n@keyframes layer-slide-down {\n  from {\n    transform: translate3d(0,-100%,0);\n  } to {\n    transform: translate3d(0,0,0);\n  }\n}\n@keyframes layer-slide-down-out {\n  from {\n    transform: translate3d(0,0,0);\n  } to {\n    transform: translate3d(0,-100%,0);\n  }\n}\n.layer-anim-slide-down{animation-name: layer-slide-down}\n.layer-anim-slide-down-out{animation-name: layer-slide-down-out}\n\n/* 从右往左 */\n@keyframes layer-slide-left {\n  from {\n    transform: translate3d(100%,0,0);\n  } to {\n    transform: translate3d(0,0,0);\n  }\n}\n@keyframes layer-slide-left-out {\n  from {\n    transform: translate3d(0,0,0);\n  } to {\n    transform: translate3d(100%,0,0);\n  }\n}\n.layer-anim-slide-left{animation-name: layer-slide-left}\n.layer-anim-slide-left-out{animation-name: layer-slide-left-out}\n\n/* 从下往上 */\n@keyframes layer-slide-up {\n  from {\n    transform: translate3d(0,100%,0);\n  } to {\n    transform: translate3d(0,0,0);\n  }\n}\n@keyframes layer-slide-up-out {\n  from {\n    transform: translate3d(0,0,0);\n  } to {\n    transform: translate3d(0,100%,0);\n  }\n}\n.layer-anim-slide-up{animation-name: layer-slide-up}\n.layer-anim-slide-up-out{animation-name: layer-slide-up-out}\n\n/* 从左往右 */\n@keyframes layer-slide-right {\n  from {\n    transform: translate3d(-100%,0,0);\n  } to {\n    transform: translate3d(0,0,0);\n  }\n}\n@keyframes layer-slide-right-out {\n  from {\n    transform: translate3d(0,0,0);\n  } to {\n    transform: translate3d(-100%,0,0);\n  }\n}\n.layer-anim-slide-right{animation-name: layer-slide-right;}\n.layer-anim-slide-right-out{animation-name: layer-slide-right-out;}\n\n\n\n/* 标题栏 */\n.layui-layer-title{padding: 0 81px 0 16px; height: 50px; line-height: 50px; border-bottom:1px solid #F0F0F0; font-size: 14px; color:#333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: 2px 2px 0 0;}\n.layui-layer-setwin{position:absolute; right: 15px; *right:0; top: 16px; font-size:0; line-height: initial;}\n.layui-layer-setwin span{position:relative; width: 16px; height: 16px; line-height: 18px; margin-left: 10px; text-align: center; font-size: 16px; cursor: pointer; color: #000; _overflow: hidden; box-sizing: border-box;}\n.layui-layer-setwin .layui-layer-min:before{content: ''; position: absolute; width: 12px; border-bottom: 1px solid #2E2D3C; left: 50%; top: 50%; margin: -0.5px 0 0 -6px; cursor: pointer; _overflow:hidden;}\n.layui-layer-setwin .layui-layer-min:hover:before{background-color: #2D93CA}\n.layui-layer-setwin .layui-layer-max:hover:before,\n.layui-layer-setwin .layui-layer-max:hover:after{border-color: #2D93CA;}\n.layui-layer-setwin .layui-layer-min:hover:before{background-color: #2D93CA}\n.layui-layer-setwin .layui-layer-maxmin:before,\n.layui-layer-setwin .layui-layer-maxmin:after{width: 7px; height: 7px; margin: -3px 0 0 -3px; background-color: #fff;}\n.layui-layer-setwin .layui-layer-maxmin:after{z-index: 0; margin: -5px 0 0 -1px;}\n.layui-layer-setwin .layui-layer-close{cursor: pointer;}\n.layui-layer-setwin .layui-layer-close:hover{opacity:0.7;}\n.layui-layer-setwin .layui-layer-close2{position:absolute; right: -28px; top: -28px; color: #fff; background-color: #787878; padding: 3px; width: 16px; height: 20px; font-size: 16px; font-weight: bolder; border-radius: 50%; margin-left: 0; *right:-18px; _display:none;}\n.layui-layer-setwin .layui-layer-close2:hover{opacity: unset; background-color: #3888f6;}\n\n/* 按钮栏 */\n.layui-layer-btn{text-align: right; padding: 0 15px 12px; pointer-events: auto; user-select: none; -webkit-user-select: none;}\n.layui-layer-btn a{height: 30px; line-height: 30px; margin: 5px 5px 0; padding: 0 16px; border: 1px solid #dedede; background-color: #fff; color: #333; border-radius: 2px; font-weight: 400; cursor: pointer; text-decoration: none; box-sizing: border-box;}\n.layui-layer-btn a:hover{opacity: 0.9; text-decoration: none;}\n.layui-layer-btn a:active{opacity: 0.8;}\n.layui-layer-btn .layui-layer-btn0{border-color: transparent; background-color: #1E9FFF; color:#fff;}\n.layui-layer-btn-l{text-align: left;}\n.layui-layer-btn-c{text-align: center;}\n\n/* 定制化 */\n.layui-layer-dialog{min-width: 240px;}\n.layui-layer-dialog .layui-layer-content{position: relative; padding: 16px; line-height: 24px; word-break: break-all; overflow:hidden; font-size:14px; overflow-x: hidden; overflow-y:auto;}\n.layui-layer-dialog .layui-layer-content .layui-layer-face{position: absolute; top: 18px; left: 16px; color: #959595; font-size: 32px; _left: -40px;}\n.layui-layer-dialog .layui-layer-content .layui-icon-tips{color: #F39B12;}\n.layui-layer-dialog .layui-layer-content .layui-icon-success{color: #16b777;}\n.layui-layer-dialog .layui-layer-content .layui-icon-error{top: 19px; color: #FF5722;}\n.layui-layer-dialog .layui-layer-content .layui-icon-question{color: #FFB800;}\n.layui-layer-dialog .layui-layer-content .layui-icon-lock{color: #787878;}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color: #FF5722;}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color: #16b777;}\n\n.layui-layer-rim{border:6px solid #8D8D8D; border:6px solid rgba(0,0,0,.3); border-radius:5px; box-shadow: none;}\n.layui-layer-msg{min-width:180px; border:1px solid #D3D4D3; box-shadow: none;}\n.layui-layer-hui{min-width:100px;  background-color: #000; filter:alpha(opacity=60); background-color: rgba(0,0,0,0.6); color: #fff; border:none;}\n.layui-layer-hui .layui-layer-close{color: #fff;}\n.layui-layer-hui .layui-layer-content{padding: 11px 24px; text-align: center;}\n.layui-layer-dialog .layui-layer-padding{padding: 18px 24px 18px 58px; text-align: left;}\n.layui-layer-page .layui-layer-content{position:relative; overflow:auto;}\n.layui-layer-page .layui-layer-btn,.layui-layer-iframe .layui-layer-btn{padding-top:10px;}\n.layui-layer-nobg{background:none;}\n.layui-layer-iframe iframe{display: block; width: 100%;}\n\n.layui-layer-loading{border-radius:100%; background:none;  box-shadow:none;  border:none;}\n.layui-layer-loading .layui-layer-content{width: 76px; height: 38px; line-height: 38px; text-align: center;}\n.layui-layer-loading-icon{font-size: 38px; color: #959595;}\n.layui-layer-loading2{text-align: center;}\n.layui-layer-loading-2{position: relative; height: 38px;}\n.layui-layer-loading-2:before,\n.layui-layer-loading-2:after{content: ''; position: absolute; left: 50%; top: 50%; width: 38px; height: 38px; margin: -19px 0 0 -19px; border-radius: 50%; border: 3px solid #d2d2d2; box-sizing: border-box;}\n.layui-layer-loading-2:after{border-color: transparent; border-left-color: #1E9FFF;}\n\n\n.layui-layer-tips{background: none; box-shadow:none; border:none;}\n.layui-layer-tips .layui-layer-content{position: relative; line-height: 22px; min-width: 12px; padding: 8px 15px; font-size: 12px; _float:left; border-radius: 2px; box-shadow: 1px 1px 3px rgba(0,0,0,.2); background-color: #000; color: #fff;}\n.layui-layer-tips .layui-layer-close{right:-2px; top:-1px;}\n.layui-layer-tips i.layui-layer-TipsG{ position:absolute;  width:0; height:0; border-width:8px; border-color:transparent; border-style:dashed; *overflow:hidden;}\n.layui-layer-tips i.layui-layer-TipsT, .layui-layer-tips i.layui-layer-TipsB{left:5px; border-right-style:solid; border-right-color: #000;}\n.layui-layer-tips i.layui-layer-TipsT{bottom:-8px;}\n.layui-layer-tips i.layui-layer-TipsB{top:-8px;}\n.layui-layer-tips i.layui-layer-TipsR, .layui-layer-tips i.layui-layer-TipsL{top: 5px; border-bottom-style:solid; border-bottom-color: #000;}\n.layui-layer-tips i.layui-layer-TipsR{left:-8px;}\n.layui-layer-tips i.layui-layer-TipsL{right:-8px;}\n\n/* 内置 skin */\n.layui-layer-lan .layui-layer-title{background:#4476A7; color:#fff; border: none;}\n.layui-layer-lan .layui-layer-btn{padding: 5px 10px 10px; border-top:1px solid #E9E7E7}\n.layui-layer-lan .layui-layer-btn a{background: #fff; border-color: #E9E7E7; color: #333;}\n.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5;}\n.layui-layer-molv .layui-layer-title{background: #009f95; color:#fff; border: none;}\n.layui-layer-molv .layui-layer-btn a{background: #009f95; border-color: #009f95;}\n.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1;}\n.layui-layer-lan .layui-layer-setwin .layui-icon,\n.layui-layer-molv .layui-layer-setwin .layui-icon{color: #fff;}\n\n/* Windows 10 风格主题  */\n.layui-layer-win10{border: 1px solid #aaa; box-shadow: 1px 1px 6px rgba(0,0,0,.3); border-radius: none;}\n.layui-layer-win10 .layui-layer-title{height: 32px; line-height: 32px; padding-left: 8px; border-bottom: none; font-size: 12px;}\n.layui-layer-win10 .layui-layer-setwin{right: 0; top: 0;}\n.layui-layer-win10 .layui-layer-setwin span{margin-left: 0; width: 32px; height: 32px; padding: 8px;}\n.layui-layer-win10.layui-layer-page .layui-layer-setwin span{width: 38px;}\n.layui-layer-win10 .layui-layer-setwin span:hover{background-color: #E5E5E5;}\n.layui-layer-win10 .layui-layer-setwin span.layui-icon-close:hover{background-color: #E81123; color: #fff;}\n.layui-layer-win10.layui-layer-dialog .layui-layer-content{padding: 8px 16px 32px; color: #0033BC;}\n.layui-layer-win10.layui-layer-dialog .layui-layer-padding{padding-top: 18px; padding-left: 58px;}\n.layui-layer-win10 .layui-layer-btn{padding: 5px 5px 10px; border-top:1px solid #DFDFDF; background-color: #F0F0F0;}\n.layui-layer-win10 .layui-layer-btn a{height: 20px; line-height: 18px; background-color: #E1E1E1; border-color: #ADADAD; color: #000; font-size: 12px; transition: all .3s;}\n.layui-layer-win10 .layui-layer-btn a:hover{border-color: #2A8EDD; background-color: #E5F1FB;}\n.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color: #0078D7;}\n\n\n/**\n \n @Name: layer拓展样式\n \n */\n\n/* prompt模式 */\n.layui-layer-prompt .layui-layer-input{display: block; width: 260px; height: 36px; margin: 0 auto; line-height: 30px; padding-left: 10px; border: 1px solid #e6e6e6; color: #333;}\n.layui-layer-prompt textarea.layui-layer-input{width: 300px; height: 100px; line-height: 20px; padding: 6px 10px;}\n.layui-layer-prompt .layui-layer-content{padding: 16px;}\n.layui-layer-prompt .layui-layer-btn{padding-top: 0;}\n\n/* tab模式 */\n.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4);}\n.layui-layer-tab .layui-layer-title{padding-left:0; overflow: visible;}\n.layui-layer-tab .layui-layer-title span{position:relative; display: inline-block; vertical-align: top; border-left: 1px solid transparent; border-right: 1px solid transparent; min-width:80px; max-width: 300px; padding:0 16px; text-align:center; cursor:default; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; cursor: pointer;}\n.layui-layer-tab .layui-layer-title span.layui-this{height: 51px; border-left-color: #eee; border-right-color: #eee; background-color: #fff; z-index: 10;}\n.layui-layer-tab .layui-layer-title span:first-child{border-left-color: transparent;}\n.layui-layer-tabmain{line-height:24px; clear: both;}\n.layui-layer-tabmain .layui-layer-tabli{display:none;}\n.layui-layer-tabmain .layui-layer-tabli.layui-this{display: block;}\n\n/* photos */\n.layui-layer-photos{background: none; box-shadow: none;}\n.layui-layer-photos .layui-layer-content{overflow: visible; text-align: center;}\n.layui-layer-photos .layer-layer-photos-main img{position: relative; width:100%; display: inline-block; *display:inline; *zoom:1; vertical-align:top;}\n.layui-layer-photos-prev,\n.layui-layer-photos-next{position: fixed; top: 50%; width: 52px; height: 52px; line-height: 52px; margin-top: -26px; cursor: pointer; font-size: 52px; color: #717171;}\n.layui-layer-photos-prev{left: 32px;}\n.layui-layer-photos-next{right: 32px;}\n.layui-layer-photos-prev:hover,\n.layui-layer-photos-next:hover{color: #959595;}\n\n.layui-layer-photos-toolbar{position: fixed; left: 0; right: 0; bottom: 0; width: 100%; height: 52px; line-height: 52px; background-color: #000\\9; filter: Alpha(opacity=60); background-color: rgba(0,0,0,.32); color: #fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;}\n.layui-layer-photos-toolbar > *{display:inline-block; vertical-align: top; padding: 0 16px; font-size: 12px; color: #fff; *display:inline; *zoom: 1;}\n.layui-layer-photos-toolbar *{font-size: 12px;}\n.layui-layer-photos-header{top: 0; bottom: auto;}\n.layui-layer-photos-header > span{cursor: pointer;}\n.layui-layer-photos-header > span:hover{background-color: rgba(51,51,51,.32);}\n.layui-layer-photos-header .layui-icon{font-size: 18px;}\n.layui-layer-photos-footer > h3{max-width: 65%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;}\n.layui-layer-photos-footer a:hover{text-decoration: underline;}\n.layui-layer-photos-footer em{font-style: normal;}\n\n\n/* 关闭动画 */\n@-webkit-keyframes layer-bounceOut {\n  100% {opacity: 0; -webkit-transform: scale(.7); transform: scale(.7)}\n  30% {-webkit-transform: scale(1.05); transform: scale(1.05)}\n  0% {-webkit-transform: scale(1); transform: scale(1);}\n}\n@keyframes layer-bounceOut {\n  100% {opacity: 0; -webkit-transform: scale(.7); -ms-transform: scale(.7); transform: scale(.7);}\n  30% {-webkit-transform: scale(1.05); -ms-transform: scale(1.05); transform: scale(1.05);}\n  0% {-webkit-transform: scale(1); -ms-transform: scale(1);transform: scale(1);}\n}\n.layer-anim-close{-webkit-animation-name: layer-bounceOut; animation-name: layer-bounceOut; -webkit-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration:.2s; animation-duration:.2s;}\n\n@media screen and (max-width: 1100px) {\n  .layui-layer-iframe{overflow-y: auto; -webkit-overflow-scrolling: touch;}\n}\n\n/* 其他样式 */\n.layui-layer-lan[type=dialog] {min-width: 280px}\n.layui-layer-lan .layui-layer-title {background: #4476a7; color: #fff; border: 0}\n.layui-layer-lan .layui-layer-btn {padding: 5px 10px 10px; text-align: right; border-top: 1px solid #e9e7e7}\n.layui-layer-lan .layui-layer-btn a {background: #fff; border-color: #e9e7e7; color: #333}\n.layui-layer-lan .layui-layer-btn .layui-layer-btn1 {background: #c9c5c5}\n.layui-layer-gray[type=dialog] {min-width: 280px}\n.layui-layer-gray .layui-layer-title {background: #f8f8f8; color: #333; border: 0}\n.layui-layer-gray .layui-layer-btn {padding: 5px 10px 10px; text-align: right; border-top: 1px solid #e9e7e7}\n.layui-layer-gray .layui-layer-btn a {background: #fff; border-color: #e9e7e7; color: #333}\n.layui-layer-gray .layui-layer-btn .layui-layer-btn1 {background: #c9c5c5}\n.layui-layer-tab .layui-layer-content {width: 100%}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/layer/theme/moon/style.css",
    "content": "/**\n * layer皮肤\n * Copyright (c) 2019 ruoyi\n */\nhtml #layui_layer_skinmoonstylecss {\n\tdisplay: none;\n\tposition: absolute;\n\twidth: 1989px;\n}\n\nbody .layer-ext-moon[type=\"dialog\"] {\n\tmin-width: 320px;\n}\nbody .layer-ext-moon-msg[type=\"dialog\"]{min-width:200px;}\nbody .layer-ext-moon .layui-layer-title {\n\tbackground: #F8F8F8;\n\tcolor: #333;\n\tfont-size: 14px;\n\theight: 42px;\n\tline-height: 42px;\n    border: none;\n}\n\nbody .layer-ext-moon .layui-layer-content .layui-layer-face {\n\theight: 32px;\n\twidth: 32px;\n\ttop:18.5px;\n}\nbody .layer-ext-moon .layui-icon-tips {\n\tbackground: url(default.png) no-repeat -96px 0;\n}\nbody .layer-ext-moon .layui-icon-success {\n\tbackground: url(default.png) no-repeat -224px 0;\n}\nbody .layer-ext-moon .layui-icon-error {\n\tbackground: url(default.png) no-repeat -192px 0;\n}\nbody .layer-ext-moon .layui-icon-question {\n\tbackground: url(default.png) no-repeat -160px 0;\n}\nbody .layer-ext-moon .layui-icon-lock {\n\tbackground: url(default.png) no-repeat -320px 0;\n}\nbody .layer-ext-moon .layui-icon-face-cry {\n\tbackground: url(default.png) no-repeat -288px 0;\n}\nbody .layer-ext-moon .layui-icon-face-smile {\n\tbackground: url(default.png) -256px 0;\n}\nbody .layer-ext-moon .layui-layer-download {\n\tbackground: url(default.png) no-repeat -128px 0;\n}\nbody .layer-ext-moon .layui-layer-setwin {\n\ttop: 15px;\n\tright: 15px;\n}\nbody .layer-ext-moon .layui-layer-setwin a {\n\twidth: 16px;\n\theight: 16px;\n}\nbody .layer-ext-moon .layui-layer-setwin .layui-layer-min cite:hover {\n\tbackground-color: #56abe4;\n}\nbody .layer-ext-moon .layui-layer-setwin .layui-layer-max {\n\tbackground: url(default.png) no-repeat -80px 0;\n}\nbody .layer-ext-moon .layui-layer-setwin .layui-layer-max:hover {\n\tbackground: url(default.png) no-repeat -64px 0;\n}\nbody .layer-ext-moon .layui-layer-setwin .layui-layer-maxmin {\n\tbackground: url(default.png) no-repeat -32px 0;\n}\nbody .layer-ext-moon .layui-layer-setwin .layui-layer-maxmin:hover {\n\tbackground: url(default.png) no-repeat -16px 0;\n}\nbody .layer-ext-moon .layui-layer-setwin .layui-layer-close1,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2, body .layui-layer-tab .layui-layer-setwin .layui-layer-close1,body .layui-layer-tab .layui-layer-setwin .layui-layer-close2 {\n\tbackground: url(default.png) 0 0;\n}\nbody .layer-ext-moon .layui-layer-setwin .layui-layer-close1:hover,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2:hover, body .layui-layer-tab .layui-layer-setwin .layui-layer-close1:hover,body .layui-layer-tab .layui-layer-setwin .layui-layer-close2:hover {\n\tbackground: url(default.png) -48px 0;\n}\nbody .layer-ext-moon .layui-layer-padding{padding-top: 24px;}\nbody .layer-ext-moon .layui-layer-btn {\n    text-align: right;\n    padding: 10px 15px 12px;\n\tbackground: #f0f4f7;\n\tborder-top: 1px #c7c7c7 solid;\n}\nbody .layer-ext-moon .layui-layer-btn a {\n\tfont-size: 12px;\n\tfont-weight: normal;\n\tmargin: 0 3px;\n\tmargin-right: 7px;\n\tmargin-left: 7px;\n\tpadding: 0 15px;\n\tcolor: #fff;\n\tborder: 1px solid #0064b6;\n\tbackground: #0071ce;\n\tborder-radius: 3px;\n\tdisplay: inline-block;\n\theight: 30px;\n\tline-height: 30px;\n\ttext-align: center;\n\tvertical-align: middle;\n\tbackground-repeat: no-repeat;\n\ttext-decoration: none;\n\toutline: none;\n\t-moz-box-sizing: content-box;\n\t-webkit-box-sizing: content-box;\n\tbox-sizing: content-box;\n}\nbody .layer-ext-moon .layui-layer-btn .layui-layer-btn0 {\n\tbackground: #0071ce;\n}\nbody .layer-ext-moon .layui-layer-btn .layui-layer-btn1 {\n\tbackground: #fff;\n\tcolor: #404a58;\n\tborder: 1px solid #c0c4cd;\n\tborder-radius: 3px;\n}\nbody .layer-ext-moon .layui-layer-btn .layui-layer-btn2 {\n\tbackground: #fff;\n\tcolor: #404a58;\n\tborder: 1px solid #c0c4cd;\n\tborder-radius: 3px;\n}\nbody .layer-ext-moon .layui-layer-btn .layui-layer-btn3 {\n\tbackground: #f00;\n\tcolor: #fff;\n\tborder: 1px solid #f00;\n\tborder-radius: 3px;\n}\n\nbody .layer-ext-moon .layui-layer-title span.layui-layer-tabnow{\n\theight:47px;\n}\n\n/** 图标字体 **/\n@font-face {\n  font-family: 'layui-icon';\n  src: url('../../../../../fonts/iconfont.woff?v=282') format('woff');\n}\n\n.layui-icon{\n  font-family:\"layui-icon\" !important;\n  font-style: normal;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n/* font-class */\n.layui-icon-left:before{content:\"\\e603\"}\n.layui-icon-right:before{content:\"\\e602\"}\n.layui-icon-refresh:before{content:\"\\e669\"}\n.layui-icon-slider:before{content:\"\\e714\"}\n.layui-icon-add-circle:before{content:\"\\e61f\"}\n.layui-icon-reduce-circle:before{content:\"\\e616\"}\n.layui-icon-refresh-1:before{content:\"\\e666\"}\n.layui-icon-loading:before{content:\"\\e63d\"}\n.layui-icon-loading-1:before{content:\"\\e63e\"}\n\n/** 循环旋转动画 **/\n.layui-anim{-webkit-animation-duration: 0.3s; -webkit-animation-fill-mode: both; animation-duration: 0.3s; animation-fill-mode: both;}\n.layui-anim.layui-icon{display: inline-block;}\n.layui-anim-loop{-webkit-animation-iteration-count: infinite; animation-iteration-count: infinite;}\n.layui-trans,\n.layui-trans a{transition: all .2s; -webkit-transition: all .2s;}\n@-webkit-keyframes layui-rotate{from {-webkit-transform: rotate(0deg);} to {-webkit-transform: rotate(360deg);}}\n@keyframes layui-rotate{from {transform: rotate(0deg);} to {transform: rotate(360deg);}}\n.layui-anim-rotate{-webkit-animation-name: layui-rotate; animation-name: layui-rotate; -webkit-animation-duration: 1s; animation-duration: 1s;  -webkit-animation-timing-function: linear; animation-timing-function: linear;}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/layui/css/modules/laydate.css",
    "content": "/*! laydate-v5.5.0 日期与时间组件 */\n@font-face{font-family: 'laydate-icon';src: url('../../../../../fonts/iconfont.woff?v=282') format('woff');}.laydate-icon{font-family:\"laydate-icon\"!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate,.layui-laydate *{box-sizing:border-box}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-laydate-main{width:272px}.layui-laydate-header *,.layui-laydate-content td,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate{animation-name:laydate-downbit}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-prev-m,.laydate-ym-show .laydate-next-m{display:none!important}.laydate-ym-show .laydate-prev-y,.laydate-ym-show .laydate-next-y{display:inline-block!important}.laydate-ym-show .laydate-set-ym span[lay-type=\"month\"]{display:none!important}.laydate-time-show .layui-laydate-header .layui-icon,.laydate-time-show .laydate-set-ym span[lay-type=\"year\"],.laydate-time-show .laydate-set-ym span[lay-type=\"month\"]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;padding:0 5px;color:#999;font-size:18px;cursor:pointer}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;box-sizing:border-box;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-set-ym span{padding:0 10px;cursor:pointer}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content th,.layui-laydate-content td{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content th{font-weight:400}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.laydate-day-holidays:before{position:absolute;left:0;top:0;font-size:12px;transform:scale(.7)}.laydate-day-holidays:before{content:'\\4F11';color:#ff5722}.laydate-day-holidays[type=\"work\"]:before{content:'\\73ED';color:inherit}.layui-laydate .layui-this .laydate-day-holidays:before{color:#fff}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px}.layui-laydate-footer span{display:inline-block;vertical-align:top;height:26px;line-height:24px;padding:0 10px;border:1px solid #c9c9c9;border-radius:2px;background-color:#fff;font-size:12px;cursor:pointer;white-space:nowrap;transition:all .3s}.layui-laydate-footer span:hover{color:#5fb878}.layui-laydate-footer span.layui-laydate-preview{cursor:default;border-color:transparent!important}.layui-laydate-footer span.layui-laydate-preview:hover{color:#666}.layui-laydate-footer span:first-child.layui-laydate-preview{padding-left:0}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{margin:0 0 0 -1px}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;box-sizing:border-box;background-color:#fff}.layui-laydate-list>li{position:relative;display:inline-block;width:33.3%;height:36px;line-height:36px;margin:3px 0;vertical-align:middle;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;height:30px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px;color:#ff5722}.layui-laydate-range{width:546px}.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-range .laydate-main-list-1 .layui-laydate-header,.layui-laydate-range .laydate-main-list-1 .layui-laydate-content{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5fb878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#b5fff8}.laydate-selected:hover{background-color:#00f7de!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0}.layui-laydate-content .laydate-day-prev,.layui-laydate-content .laydate-day-next{color:#d2d2d2}.laydate-selected.laydate-day-prev,.laydate-selected.laydate-day-next{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#ff5722}.laydate-day-mark::after{background-color:#5fb878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=\"date\"]{color:#5fb878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:none!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:0}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:0;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:0;border-bottom:0}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .laydate-month-list>li{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-prev,.laydate-theme-grid .laydate-selected.laydate-day-next{color:#d2d2d2!important}.laydate-theme-grid .laydate-year-list,.laydate-theme-grid .laydate-month-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .laydate-month-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/layui/modules/laydate.js",
    "content": "/*! laydate-v5.5.0 日期与时间组件 */\r\n!function(window){var MOD_NAME=\"lay\";var document=window.document;var lay=function(selector){return new Class(selector)};var Class=function(selector){var that=this;var elem=typeof selector===\"object\"?function(){return layui.isArray(selector)?selector:[selector]}():(this.selector=selector,document.querySelectorAll(selector||null));lay.each(elem,function(index,item){that.push(elem[index])})};Array.prototype.indexOf=Array.prototype.indexOf||function(searchElement,fromIndex){var rst=-1;fromIndex=fromIndex||0;layui.each(this,function(index,val){if(searchElement===val&&index>=fromIndex){rst=index;return !0}});return rst};Class.fn=Class.prototype=[];Class.fn.constructor=Class;lay.extend=function(){var ai=1;var length;var args=arguments;var clone=function(target,obj){target=target||(layui.type(obj)===\"array\"?[]:{});for(var i in obj){target[i]=(obj[i]&&obj[i].constructor===Object)?clone(target[i],obj[i]):obj[i]}return target};args[0]=typeof args[0]===\"object\"?args[0]:{};length=args.length;for(;ai<length;ai++){if(typeof args[ai]===\"object\"){clone(args[0],args[ai])}}return args[0]};lay.ie=function(){var agent=navigator.userAgent.toLowerCase();return(!!window.ActiveXObject||\"ActiveXObject\" in window)?((agent.match(/msie\\s(\\d+)/)||[])[1]||\"11\"):false}();lay.layui=layui||{};lay.getPath=layui.cache.dir;lay.stope=layui.stope;lay.each=function(){layui.each.apply(layui,arguments);return this};lay.digit=function(num,length){if(!(typeof num===\"string\"||typeof num===\"number\")){return\"\"}var str=\"\";num=String(num);length=length||2;for(var i=num.length;i<length;i++){str+=\"0\"}return num<Math.pow(10,length)?str+num:num};lay.elem=function(elemName,attr){var elem=document.createElement(elemName);lay.each(attr||{},function(key,value){elem.setAttribute(key,value)});return elem};lay.hasScrollbar=function(){return document.body.scrollHeight>(window.innerHeight||document.documentElement.clientHeight)};lay.getStyleRules=function(style,callback){if(!style){return}var sheet=style.sheet||style.styleSheet||{};var rules=sheet.cssRules||sheet.rules;if(typeof callback===\"function\"){layui.each(rules,function(i,item){if(callback(item,i)){return true}})}return rules};lay.style=function(options){options=options||{};var style=lay.elem(\"style\");var styleText=options.text||\"\";var target=options.target;if(!styleText){return}if(\"styleSheet\" in style){style.setAttribute(\"type\",\"text/css\");style.styleSheet.cssText=styleText}else{style.innerHTML=styleText}style.id=\"LAY-STYLE-\"+(options.id||function(index){lay.style.index++;return\"DF-\"+index}(lay.style.index||0));if(target){var styleElem=lay(target).find(\"#\"+style.id);styleElem[0]&&styleElem.remove();lay(target).append(style)}return style};lay.position=function(target,elem,opts){if(!elem){return}opts=opts||{};if(target===document||target===lay(\"body\")[0]){opts.clickType=\"right\"}var rect=opts.clickType===\"right\"?function(){var e=opts.e||window.event||{};return{left:e.clientX,top:e.clientY,right:e.clientX,bottom:e.clientY}}():target.getBoundingClientRect();var elemWidth=elem.offsetWidth;var elemHeight=elem.offsetHeight;var scrollArea=function(type){type=type?\"scrollLeft\":\"scrollTop\";return document.body[type]|document.documentElement[type]};var winArea=function(type){return document.documentElement[type?\"clientWidth\":\"clientHeight\"]};var margin=\"margin\" in opts?opts.margin:5;var left=rect.left;var top=rect.bottom;if(opts.align===\"center\"){left=left-(elemWidth-target.offsetWidth)/2}else{if(opts.align===\"right\"){left=left-elemWidth+target.offsetWidth}}if(left+elemWidth+margin>winArea(\"width\")){left=winArea(\"width\")-elemWidth-margin}if(left<margin){left=margin}if(rect.bottom+elemHeight+margin>winArea()){if(rect.top>elemHeight+margin&&rect.top<=winArea()){top=rect.top-elemHeight-margin*2}else{if(!opts.allowBottomOut){top=winArea()-elemHeight-margin*2;if(top<0){top=0}}}}var position=opts.position;if(position){elem.style.position=position}elem.style.left=left+(position===\"fixed\"?0:scrollArea(1))+\"px\";elem.style.top=top+(position===\"fixed\"?0:scrollArea())+\"px\";if(!lay.hasScrollbar()){var rect1=elem.getBoundingClientRect();if(!opts.SYSTEM_RELOAD&&(rect1.bottom+margin)>winArea()){opts.SYSTEM_RELOAD=true;setTimeout(function(){lay.position(target,elem,opts)},50)}}};lay.options=function(elem,opts){opts=typeof opts===\"object\"?opts:{attr:opts};if(elem===document){return{}}var othis=lay(elem);var attrName=opts.attr||\"lay-options\";var attrValue=othis.attr(attrName);try{return new Function(\"return \"+(attrValue||\"{}\"))()}catch(ev){layui.hint().error(opts.errorText||[attrName+'=\"'+attrValue+'\"',\"\\n parseerror: \"+ev].join(\"\\n\"),\"error\");return{}}};lay.isTopElem=function(elem){var topElems=[document,lay(\"body\")[0]],matched=false;lay.each(topElems,function(index,item){if(item===elem){return matched=true}});return matched};lay.clipboard={writeText:function(options){var text=String(options.text);try{navigator.clipboard.writeText(text).then(options.done)[\"catch\"](options.error)}catch(e){var elem=document.createElement(\"textarea\");elem.value=text;elem.style.position=\"fixed\";elem.style.opacity=\"0\";elem.style.top=\"0px\";elem.style.left=\"0px\";document.body.appendChild(elem);elem.select();try{document.execCommand(\"copy\");typeof options.done===\"function\"&&options.done()}catch(err){typeof options.error===\"function\"&&options.error(err)}finally{elem.remove?elem.remove():document.body.removeChild(elem)}}}};Class.addStr=function(str,new_str){str=str.replace(/\\s+/,\" \");new_str=new_str.replace(/\\s+/,\" \").split(\" \");lay.each(new_str,function(ii,item){if(!new RegExp(\"\\\\b\"+item+\"\\\\b\").test(str)){str=str+\" \"+item}});return str.replace(/^\\s|\\s$/,\"\")};Class.removeStr=function(str,new_str){str=str.replace(/\\s+/,\" \");new_str=new_str.replace(/\\s+/,\" \").split(\" \");lay.each(new_str,function(ii,item){var exp=new RegExp(\"\\\\b\"+item+\"\\\\b\");if(exp.test(str)){str=str.replace(exp,\"\")}});return str.replace(/\\s+/,\" \").replace(/^\\s|\\s$/,\"\")};Class.fn.find=function(selector){var that=this;var elem=[];var isObject=typeof selector===\"object\";this.each(function(i,item){var children=isObject&&item.contains(selector)?selector:item.querySelectorAll(selector||null);lay.each(children,function(index,child){elem.push(child)})});return lay(elem)};Class.fn.each=function(fn){return lay.each.call(this,this,fn)};Class.fn.addClass=function(className,type){return this.each(function(index,item){item.className=Class[type?\"removeStr\":\"addStr\"](item.className,className)})};Class.fn.removeClass=function(className){return this.addClass(className,true)};Class.fn.hasClass=function(className){var has=false;this.each(function(index,item){if(new RegExp(\"\\\\b\"+className+\"\\\\b\").test(item.className)){has=true}});return has};Class.fn.css=function(key,value){var that=this;var parseValue=function(v){return isNaN(v)?v:(v+\"px\")};return(typeof key===\"string\"&&value===undefined)?function(){if(that.length>0){return that[0].style[key]}}():that.each(function(index,item){typeof key===\"object\"?lay.each(key,function(thisKey,thisValue){item.style[thisKey]=parseValue(thisValue)}):item.style[key]=parseValue(value)})};Class.fn.width=function(value){var that=this;return value===undefined?function(){if(that.length>0){return that[0].offsetWidth}}():that.each(function(index,item){that.css(\"width\",value)})};Class.fn.height=function(value){var that=this;return value===undefined?function(){if(that.length>0){return that[0].offsetHeight}}():that.each(function(index,item){that.css(\"height\",value)})};Class.fn.attr=function(key,value){var that=this;return value===undefined?function(){if(that.length>0){return that[0].getAttribute(key)}}():that.each(function(index,item){item.setAttribute(key,value)})};Class.fn.removeAttr=function(key){return this.each(function(index,item){item.removeAttribute(key)})};Class.fn.html=function(html){var that=this;return html===undefined?function(){if(that.length>0){return that[0].innerHTML}}():this.each(function(index,item){item.innerHTML=html})};Class.fn.val=function(value){var that=this;return value===undefined?function(){if(that.length>0){return that[0].value}}():this.each(function(index,item){item.value=value})};Class.fn.append=function(elem){return this.each(function(index,item){typeof elem===\"object\"?item.appendChild(elem):item.innerHTML=item.innerHTML+elem})};Class.fn.remove=function(elem){return this.each(function(index,item){elem?item.removeChild(elem):item.parentNode.removeChild(item)})};Class.fn.on=function(eventName,fn){return this.each(function(index,item){item.attachEvent?item.attachEvent(\"on\"+eventName,function(e){e.target=e.srcElement;fn.call(item,e)}):item.addEventListener(eventName,fn,false)})};Class.fn.off=function(eventName,fn){return this.each(function(index,item){item.detachEvent?item.detachEvent(\"on\"+eventName,fn):item.removeEventListener(eventName,fn,false)})};window.lay=lay;if(window.layui&&layui.define){layui.define(function(exports){exports(MOD_NAME,lay)})}}(window,window.document);!function(window,document){var isLayui=window.layui&&layui.define,ready={getPath:(window.lay&&lay.getPath)?lay.getPath:\"\",link:function(href,fn,cssname){if(!laydate.path){return}if(window.lay&&lay.layui){lay.layui.link(laydate.path+href,fn,cssname)}}};var GLOBAL=window.LAYUI_GLOBAL||{};var MOD_NAME=\"laydate\";var MOD_ID=\"layui-\"+MOD_NAME+\"-id\";var laydate={v:\"5.5.0\",config:{weekStart:0,},index:(window.laydate&&window.laydate.v)?100000:0,path:GLOBAL.laydate_dir||ready.getPath,set:function(options){var that=this;that.config=lay.extend({},that.config,options);return that},ready:function(callback){var cssname=\"laydate\";var ver=\"\";var path=(isLayui?\"modules/\":\"\")+\"laydate.css?v=\"+laydate.v+ver;isLayui?(layui[\"layui.all\"]?(typeof callback===\"function\"&&callback()):layui.addcss(path,callback,cssname)):ready.link(path,callback,cssname);return this}};var thisModule=function(){var that=this;var options=that.config;var id=options.id;thisModule.that[id]=that;return that.inst={hint:function(content){that.hint.call(that,content)},reload:function(options){that.reload.call(that,options)},config:that.config}};var MOD_NAME=\"laydate\";var ELEM=\".layui-laydate\";var THIS=\"layui-this\";var SHOW=\"layui-show\";var HIDE=\"layui-hide\";var DISABLED=\"laydate-disabled\";var LIMIT_YEAR=[100,200000];var ELEM_STATIC=\"layui-laydate-static\";var ELEM_LIST=\"layui-laydate-list\";var ELEM_SELECTED=\"laydate-selected\";var ELEM_HINT=\"layui-laydate-hint\";var ELEM_DAY_NOW=\"laydate-day-now\";var ELEM_PREV=\"laydate-day-prev\";var ELEM_NEXT=\"laydate-day-next\";var ELEM_FOOTER=\"layui-laydate-footer\";var ELEM_SHORTCUT=\"layui-laydate-shortcut\";var ELEM_NOW=\".laydate-btns-now\";var ELEM_CONFIRM=\".laydate-btns-confirm\";var ELEM_TIME_TEXT=\"laydate-time-text\";var ELEM_TIME_BTN=\"laydate-btns-time\";var ELEM_PREVIEW=\"layui-laydate-preview\";var ELEM_MAIN=\"layui-laydate-main\";var ELEM_SHADE=\"layui-laydate-shade\";var Class=function(options){var that=this;that.index=++laydate.index;that.config=lay.extend({},that.config,laydate.config,options);var elem=lay(options.elem||that.config.elem);if(elem.length>1){lay.each(elem,function(){laydate.render(lay.extend({},that.config,{elem:this}))});return that}options=lay.extend(that.config,lay.options(elem[0]));if(elem[0]&&elem.attr(MOD_ID)){var newThat=thisModule.getThis(elem.attr(MOD_ID));if(!newThat){return}return newThat.reload(options)}options.id=\"id\" in options?options.id:(elem.attr(\"id\")||that.index);options.index=that.index;laydate.ready(function(){that.init()})};var dateType=\"yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s\";thisModule.formatArr=function(format){return(format||\"\").match(new RegExp(dateType+\"|.\",\"g\"))||[]};Class.isLeapYear=function(year){return(year%4===0&&year%100!==0)||year%400===0};Class.prototype.config={type:\"date\",range:false,format:\"yyyy-MM-dd\",value:null,isInitValue:true,min:\"1900-1-1\",max:\"2099-12-31\",trigger:\"click\",show:false,showBottom:true,isPreview:true,btns:[\"clear\",\"now\",\"confirm\"],lang:\"cn\",theme:\"default\",position:null,calendar:false,mark:{},holidays:null,zIndex:null,done:null,change:null,autoConfirm:true,shade:0};Class.prototype.lang=function(){var that=this,options=that.config,text={cn:{weeks:[\"日\",\"一\",\"二\",\"三\",\"四\",\"五\",\"六\"],time:[\"时\",\"分\",\"秒\"],timeTips:\"选择时间\",startTime:\"开始时间\",endTime:\"结束时间\",dateTips:\"返回日期\",month:[\"一\",\"二\",\"三\",\"四\",\"五\",\"六\",\"七\",\"八\",\"九\",\"十\",\"十一\",\"十二\"],tools:{confirm:\"确定\",clear:\"清空\",now:\"现在\"},timeout:\"结束时间不能早于开始时间<br>请重新选择\",invalidDate:\"不在有效日期或时间范围内\",formatError:[\"日期格式不合法<br>必须遵循下述格式：<br>\",\"<br>已为你重置\"],preview:\"当前选中的结果\"},en:{weeks:[\"Su\",\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"],time:[\"Hours\",\"Minutes\",\"Seconds\"],timeTips:\"Select Time\",startTime:\"Start Time\",endTime:\"End Time\",dateTips:\"Select Date\",month:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"],tools:{confirm:\"Confirm\",clear:\"Clear\",now:\"Now\"},timeout:\"End time cannot be less than start Time<br>Please re-select\",invalidDate:\"Invalid date\",formatError:[\"The date format error<br>Must be followed：<br>\",\"<br>It has been reset\"],preview:\"The selected result\"}};return text[options.lang]||text[\"cn\"]};Class.prototype.reload=function(options){var that=this;that.config=lay.extend({},that.config,options);that.init()};Class.prototype.init=function(){var that=this,options=that.config,isStatic=options.position===\"static\",format={year:\"yyyy\",month:\"yyyy-MM\",date:\"yyyy-MM-dd\",time:\"HH:mm:ss\",datetime:\"yyyy-MM-dd HH:mm:ss\"};options.elem=lay(options.elem);options.eventElem=lay(options.eventElem);if(!options.elem[0]){return}layui.type(options.theme)!==\"array\"&&(options.theme=[options.theme]);if(options.fullPanel){if(options.type!==\"datetime\"||options.range){delete options.fullPanel}}that.rangeStr=options.range?(typeof options.range===\"string\"?options.range:\"-\"):\"\";that.rangeLinked=!!(options.range&&options.rangeLinked&&(options.type===\"date\"||options.type===\"datetime\"));that.autoCalendarModel=function(){var state=that.rangeLinked;that.rangeLinked=(options.range&&(options.type===\"date\"||options.type===\"datetime\"))&&((!that.startDate||!that.endDate)||(that.startDate&&that.endDate&&that.startDate.year===that.endDate.year&&that.startDate.month===that.endDate.month));lay(that.elem)[that.rangeLinked?\"addClass\":\"removeClass\"](\"layui-laydate-linkage\");return that.rangeLinked!=state};that.autoCalendarModel.auto=that.rangeLinked&&options.rangeLinked===\"auto\";if(layui.type(options.range)===\"array\"){that.rangeElem=[lay(options.range[0]),lay(options.range[1])]}if(!format[options.type]){window.console&&console.error&&console.error(\"laydate type error:'\"+options.type+\"' is not supported\");options.type=\"date\"}if(options.format===format.date){options.format=format[options.type]||format.date}that.format=thisModule.formatArr(options.format);if(options.weekStart){if(!/^[0-6]$/.test(options.weekStart)){var lang=that.lang();options.weekStart=lang.weeks.indexOf(options.weekStart);if(options.weekStart===-1){options.weekStart=0}}}that.EXP_IF=\"\";that.EXP_SPLIT=\"\";lay.each(that.format,function(i,item){var EXP=new RegExp(dateType).test(item)?\"\\\\d{\"+function(){if(new RegExp(dateType).test(that.format[i===0?i+1:i-1]||\"\")){if(/^yyyy|y$/.test(item)){return 4}return item.length}if(/^yyyy$/.test(item)){return\"1,4\"}if(/^y$/.test(item)){return\"1,308\"}return\"1,2\"}()+\"}\":\"\\\\\"+item;that.EXP_IF=that.EXP_IF+EXP;that.EXP_SPLIT=that.EXP_SPLIT+\"(\"+EXP+\")\"});that.EXP_IF_ONE=new RegExp(\"^\"+that.EXP_IF+\"$\");that.EXP_IF=new RegExp(\"^\"+(options.range?that.EXP_IF+\"\\\\s\\\\\"+that.rangeStr+\"\\\\s\"+that.EXP_IF:that.EXP_IF)+\"$\");that.EXP_SPLIT=new RegExp(\"^\"+that.EXP_SPLIT+\"$\",\"\");if(!that.isInput(options.elem[0])){if(options.trigger===\"focus\"){options.trigger=\"click\"}}options.elem.attr(\"lay-key\",that.index);options.eventElem.attr(\"lay-key\",that.index);options.elem.attr(MOD_ID,options.id);options.mark=lay.extend({},(options.calendar&&options.lang===\"cn\")?{\"0-1-1\":\"元旦\",\"0-2-14\":\"情人\",\"0-3-8\":\"妇女\",\"0-3-12\":\"植树\",\"0-4-1\":\"愚人\",\"0-5-1\":\"劳动\",\"0-5-4\":\"青年\",\"0-6-1\":\"儿童\",\"0-9-10\":\"教师\",\"0-10-1\":\"国庆\",\"0-12-25\":\"圣诞\"}:{},options.mark);lay.each([\"min\",\"max\"],function(i,item){var ymd=[];var hms=[];if(typeof options[item]===\"number\"){var day=options[item],tDate=new Date(),time=that.newDate({year:tDate.getFullYear(),month:tDate.getMonth(),date:tDate.getDate(),hours:i?23:0,minutes:i?59:0,seconds:i?59:0}).getTime(),STAMP=86400000,thisDate=new Date(day?(day<STAMP?time+day*STAMP:day):time);ymd=[thisDate.getFullYear(),thisDate.getMonth()+1,thisDate.getDate()];hms=[thisDate.getHours(),thisDate.getMinutes(),thisDate.getSeconds()]}else{if(typeof options[item]===\"string\"){ymd=(options[item].match(/\\d+-\\d+-\\d+/)||[\"\"])[0].split(\"-\");hms=(options[item].match(/\\d+:\\d+:\\d+/)||[\"\"])[0].split(\":\")}else{if(typeof options[item]===\"object\"){return options[item]}}}options[item]={year:ymd[0]|0||new Date().getFullYear(),month:ymd[1]?(ymd[1]|0)-1:new Date().getMonth(),date:ymd[2]|0||new Date().getDate(),hours:hms[0]|0,minutes:hms[1]|0,seconds:hms[2]|0}});that.elemID=\"layui-laydate\"+options.elem.attr(\"lay-key\");if(options.show||isStatic){that.render()}isStatic||that.events();if(options.value&&options.isInitValue){if(layui.type(options.value)===\"date\"){that.setValue(that.parse(0,that.systemDate(options.value)))}else{that.setValue(options.value)}}};Class.prototype.render=function(){var that=this,options=that.config,lang=that.lang(),isStatic=options.position===\"static\",elem=that.elem=lay.elem(\"div\",{id:that.elemID,\"class\":[\"layui-laydate\",options.range?\" layui-laydate-range\":\"\",that.rangeLinked?\" layui-laydate-linkage\":\"\",isStatic?(\" \"+ELEM_STATIC):\"\",options.fullPanel?\" laydate-theme-fullpanel\":\"\",(function(){var themeStr=\"\";lay.each(options.theme,function(index,theme){if(theme!==\"default\"&&!/^#/.test(theme)){themeStr+=\" laydate-theme-\"+theme}});return themeStr})()].join(\"\")}),elemMain=that.elemMain=[],elemHeader=that.elemHeader=[],elemCont=that.elemCont=[],elemTable=that.table=[],divFooter=that.footer=lay.elem(\"div\",{\"class\":ELEM_FOOTER}),divShortcut=that.shortcut=lay.elem(\"ul\",{\"class\":ELEM_SHORTCUT});if(options.zIndex){elem.style.zIndex=options.zIndex}lay.each(new Array(2),function(i){if(!options.range&&i>0){return true}var divHeader=lay.elem(\"div\",{\"class\":\"layui-laydate-header\"}),headerChild=[function(){var elem=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-y\"});elem.innerHTML=\"&#xe65a;\";return elem}(),function(){var elem=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-m\"});elem.innerHTML=\"&#xe603;\";return elem}(),function(){var elem=lay.elem(\"div\",{\"class\":\"laydate-set-ym\"}),spanY=lay.elem(\"span\"),spanM=lay.elem(\"span\");elem.appendChild(spanY);elem.appendChild(spanM);return elem}(),function(){var elem=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-m\"});elem.innerHTML=\"&#xe602;\";return elem}(),function(){var elem=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-y\"});elem.innerHTML=\"&#xe65b;\";return elem}()],divContent=lay.elem(\"div\",{\"class\":\"layui-laydate-content\"}),table=lay.elem(\"table\"),thead=lay.elem(\"thead\"),theadTr=lay.elem(\"tr\");lay.each(headerChild,function(i,item){divHeader.appendChild(item)});thead.appendChild(theadTr);lay.each(new Array(6),function(i){var tr=table.insertRow(0);lay.each(new Array(7),function(j){if(i===0){var th=lay.elem(\"th\");th.innerHTML=lang.weeks[(j+options.weekStart)%7];theadTr.appendChild(th)}tr.insertCell(j)})});table.insertBefore(thead,table.children[0]);divContent.appendChild(table);elemMain[i]=lay.elem(\"div\",{\"class\":ELEM_MAIN+\" laydate-main-list-\"+i});elemMain[i].appendChild(divHeader);elemMain[i].appendChild(divContent);elemHeader.push(headerChild);elemCont.push(divContent);elemTable.push(table)});lay(divFooter).html(function(){var html=[],btns=[];if(options.type===\"datetime\"){html.push('<span lay-type=\"datetime\" class=\"'+ELEM_TIME_BTN+'\">'+lang.timeTips+\"</span>\")}if(!(!options.range&&options.type===\"datetime\")||options.fullPanel){html.push('<span class=\"'+ELEM_PREVIEW+'\" title=\"'+lang.preview+'\"></span>')}lay.each(options.btns,function(i,item){var title=lang.tools[item]||\"btn\";if(options.range&&item===\"now\"){return}if(isStatic&&item===\"clear\"){title=options.lang===\"cn\"?\"重置\":\"Reset\"}btns.push('<span lay-type=\"'+item+'\" class=\"laydate-btns-'+item+'\">'+title+\"</span>\")});html.push('<div class=\"laydate-footer-btns\">'+btns.join(\"\")+\"</div>\");return html.join(\"\")}());if(options.shortcuts){elem.appendChild(divShortcut);lay(divShortcut).html(function(){var shortcutBtns=[];lay.each(options.shortcuts,function(i,item){shortcutBtns.push('<li data-index=\"'+i+'\">'+item.text+\"</li>\")});return shortcutBtns.join(\"\")}()).find(\"li\").on(\"click\",function(event){var btnSetting=options.shortcuts[this.dataset[\"index\"]]||{};var value=(typeof btnSetting.value===\"function\"?btnSetting.value():btnSetting.value)||[];if(!layui.isArray(value)){value=[value]}var type=options.type;lay.each(value,function(i,item){var dateTime=[options.dateTime,that.endDate][i];if(type===\"time\"&&layui.type(item)!==\"date\"){if(that.EXP_IF.test(item)){item=(item.match(that.EXP_SPLIT)||[]).slice(1);lay.extend(dateTime,{hours:item[0]|0,minutes:item[2]|0,seconds:item[4]|0})}}else{lay.extend(dateTime,that.systemDate(layui.type(item)===\"date\"?item:new Date(item)))}if(type===\"time\"||type===\"datetime\"){that[[\"startTime\",\"endTime\"][i]]={hours:dateTime.hours,minutes:dateTime.minutes,seconds:dateTime.seconds,}}if(i===0){that.startDate=lay.extend({},dateTime)}else{that.endState=true}if(type===\"year\"||type===\"month\"||type===\"time\"){that.listYM[i]=[dateTime.year,dateTime.month+1]}else{if(i){that.autoCalendarModel.auto&&that.autoCalendarModel()}}});that.checkDate(\"limit\").calendar(null,null,\"init\");var timeBtn=lay(that.footer).find(\".\"+ELEM_TIME_BTN).removeClass(DISABLED);timeBtn&&timeBtn.attr(\"lay-type\")===\"date\"&&timeBtn[0].click();that.done(null,\"change\");lay(this).addClass(THIS);if(options.position!==\"static\"){that.setValue(that.parse()).done().remove()}})}lay.each(elemMain,function(i,main){elem.appendChild(main)});options.showBottom&&elem.appendChild(divFooter);var style=lay.elem(\"style\");var styleText=[];var colorTheme;var isPrimaryColor=true;lay.each(options.theme,function(index,theme){if(isPrimaryColor&&/^#/.test(theme)){colorTheme=true;isPrimaryColor=false;styleText.push([\"#{{id}} .layui-laydate-header{background-color:{{theme}};}\",\"#{{id}} li.layui-this,#{{id}} td.layui-this>div{background-color:{{theme}} !important;}\",options.theme.indexOf(\"circle\")!==-1?\"\":\"#{{id}} .layui-this{background-color:{{theme}} !important;}\",\"#{{id}} .laydate-day-now{color:{{theme}} !important;}\",\"#{{id}} .laydate-day-now:after{border-color:{{theme}} !important;}\"].join(\"\").replace(/{{id}}/g,that.elemID).replace(/{{theme}}/g,theme));return}if(!isPrimaryColor&&/^#/.test(theme)){styleText.push([\"#{{id}} .laydate-selected>div{background-color:{{theme}} !important;}\",\"#{{id}} .laydate-selected:hover>div{background-color:{{theme}} !important;}\"].join(\"\").replace(/{{id}}/g,that.elemID).replace(/{{theme}}/g,theme))}});if(options.shortcuts&&options.range){styleText.push(\"#{{id}}.layui-laydate-range{width: 628px;}\".replace(/{{id}}/g,that.elemID))}if(styleText.length){styleText=styleText.join(\"\");if(\"styleSheet\" in style){style.setAttribute(\"type\",\"text/css\");style.styleSheet.cssText=styleText}else{style.innerHTML=styleText}colorTheme&&lay(elem).addClass(\"laydate-theme-molv\");elem.appendChild(style)}that.remove(Class.thisElemDate);laydate.thisId=options.id;isStatic?options.elem.append(elem):(document.body.appendChild(elem),that.position());var shade=options.shade?('<div class=\"'+ELEM_SHADE+'\" style=\"'+(\"z-index:\"+(parseInt(layui.getStyle(elem,\"z-index\"))-1)+\"; background-color: \"+(options.shade[1]||\"#000\")+\"; opacity: \"+(options.shade[0]||options.shade))+'\"></div>'):\"\";elem.insertAdjacentHTML(\"beforebegin\",shade);that.checkDate().calendar(null,0,\"init\");that.changeEvent();Class.thisElemDate=that.elemID;that.renderAdditional();typeof options.ready===\"function\"&&options.ready(lay.extend({},options.dateTime,{month:options.dateTime.month+1}));that.preview()};Class.prototype.remove=function(prev){var that=this,options=that.config,elem=lay(\"#\"+(prev||that.elemID));if(!elem[0]){return that}if(!elem.hasClass(ELEM_STATIC)){that.checkDate(function(){elem.remove();delete that.startDate;delete that.endDate;delete that.endState;delete that.startTime;delete that.endTime;delete laydate.thisId;typeof options.close===\"function\"&&options.close(that)})}lay(\".\"+ELEM_SHADE).remove();return that};Class.prototype.position=function(){var that=this,options=that.config;lay.position(options.elem[0],that.elem,{position:options.position});return that};Class.prototype.hint=function(opts){var that=this;var options=that.config;var div=lay.elem(\"div\",{\"class\":ELEM_HINT});if(!that.elem){return}if(typeof opts===\"object\"){opts=opts||{}}else{opts={content:opts}}div.innerHTML=opts.content||\"\";lay(that.elem).find(\".\"+ELEM_HINT).remove();that.elem.appendChild(div);clearTimeout(that.hinTimer);that.hinTimer=setTimeout(function(){lay(that.elem).find(\".\"+ELEM_HINT).remove()},\"ms\" in opts?opts.ms:3000)};Class.prototype.getAsYM=function(Y,M,type){type?M--:M++;if(M<0){M=11;Y--}if(M>11){M=0;Y++}return[Y,M]};Class.prototype.systemDate=function(newDate){var thisDate=newDate||new Date();return{year:thisDate.getFullYear(),month:thisDate.getMonth(),date:thisDate.getDate(),hours:newDate?newDate.getHours():0,minutes:newDate?newDate.getMinutes():0,seconds:newDate?newDate.getSeconds():0}};Class.prototype.checkDate=function(fn){var that=this,thisDate=new Date(),options=that.config,lang=that.lang(),dateTime=options.dateTime=options.dateTime||that.systemDate(),thisMaxDate,error,elem=options.elem[0],valType=that.isInput(elem)?\"val\":\"html\",value=function(){if(that.rangeElem){var vals=[that.rangeElem[0].val(),that.rangeElem[1].val()];if(vals[0]&&vals[1]){return vals.join(\" \"+that.rangeStr+\" \")}}return that.isInput(elem)?elem.value:(options.position===\"static\"?\"\":lay(elem).attr(\"lay-date\"))}(),checkValid=function(dateTime){if(!dateTime){return}if(dateTime.year>LIMIT_YEAR[1]){dateTime.year=LIMIT_YEAR[1],error=true}if(dateTime.month>11){dateTime.month=11,error=true}if(dateTime.seconds>59){dateTime.seconds=0,dateTime.minutes++,error=true}if(dateTime.minutes>59){dateTime.minutes=0,dateTime.hours++,error=true}if(dateTime.hours>23){dateTime.hours=0,error=true}thisMaxDate=laydate.getEndDate(dateTime.month+1,dateTime.year);if(dateTime.date>thisMaxDate){dateTime.date=thisMaxDate,error=true}},initDate=function(dateTime,value,index){var startEnd=[\"startTime\",\"endTime\"];value=(value.match(that.EXP_SPLIT)||[]).slice(1);index=index||0;if(options.range){that[startEnd[index]]=that[startEnd[index]]||{}}lay.each(that.format,function(i,item){var thisv=parseFloat(value[i]);if(value[i].length<item.length){error=true}if(/yyyy|y/.test(item)){if(thisv<LIMIT_YEAR[0]){thisv=LIMIT_YEAR[0],error=true}dateTime.year=thisv}else{if(/MM|M/.test(item)){if(thisv<1){thisv=1,error=true}dateTime.month=thisv-1}else{if(/dd|d/.test(item)){if(thisv<1){thisv=1,error=true}dateTime.date=thisv}else{if(/HH|H/.test(item)){if(thisv<0){thisv=0,error=true}if(thisv>23){thisv=23,error=true}dateTime.hours=thisv;options.range&&(that[startEnd[index]].hours=thisv)}else{if(/mm|m/.test(item)){if(thisv<0){thisv=0,error=true}if(thisv>59){thisv=59,error=true}dateTime.minutes=thisv;options.range&&(that[startEnd[index]].minutes=thisv)}else{if(/ss|s/.test(item)){if(thisv<0){thisv=0,error=true}if(thisv>59){thisv=59,error=true}dateTime.seconds=thisv;options.range&&(that[startEnd[index]].seconds=thisv)}}}}}}});checkValid(dateTime)};if(fn===\"limit\"){if(options.range){checkValid(that.rangeLinked?that.startDate:dateTime);that.endDate&&checkValid(that.endDate)}else{checkValid(dateTime)}return that}value=value||options.value;if(typeof value===\"string\"){value=value.replace(/\\s+/g,\" \").replace(/^\\s|\\s$/g,\"\")}var getEndDate=function(){if(options.range){that.endDate=that.endDate||lay.extend({},options.dateTime,function(){var obj={},dateTime=options.dateTime,EYM=that.getAsYM(dateTime.year,dateTime.month);if(options.type===\"year\"){obj.year=dateTime.year+1}else{if(options.type!==\"time\"){obj.year=EYM[0];obj.month=EYM[1]}}if(options.type===\"datetime\"||options.type===\"time\"){obj.hours=23;obj.minutes=obj.seconds=59}return obj}())}};getEndDate();if(typeof value===\"string\"&&value){if(that.EXP_IF.test(value)){if(options.range){value=value.split(\" \"+that.rangeStr+\" \");lay.each([options.dateTime,that.endDate],function(i,item){initDate(item,value[i],i)})}else{initDate(dateTime,value)}}else{that.hint(lang.formatError[0]+(options.range?(options.format+\" \"+that.rangeStr+\" \"+options.format):options.format)+lang.formatError[1]);error=true}}else{if(value&&layui.type(value)===\"date\"){options.dateTime=that.systemDate(value)}else{options.dateTime=that.systemDate();delete that.startTime;delete that.endDate;getEndDate();delete that.endTime}}(function(){if(that.rangeElem){var vals=[that.rangeElem[0].val(),that.rangeElem[1].val()],arrDate=[options.dateTime,that.endDate];lay.each(vals,function(_i,_v){if(that.EXP_IF_ONE.test(_v)){initDate(arrDate[_i],_v,_i)}})}})();checkValid(dateTime);if(options.range){checkValid(that.endDate)}if(error&&value){that.setValue(options.range?(that.endDate?that.parse():\"\"):that.parse())}var minMaxError;if(that.getDateTime(dateTime)>that.getDateTime(options.max)){dateTime=options.dateTime=lay.extend({},options.max);minMaxError=true}else{if(that.getDateTime(dateTime)<that.getDateTime(options.min)){dateTime=options.dateTime=lay.extend({},options.min);minMaxError=true}}if(options.range){if(that.getDateTime(that.endDate)<that.getDateTime(options.min)||that.getDateTime(that.endDate)>that.getDateTime(options.max)){that.endDate=lay.extend({},options.max);minMaxError=true}that.startTime={hours:options.dateTime.hours,minutes:options.dateTime.minutes,seconds:options.dateTime.seconds,};that.endTime={hours:that.endDate.hours,minutes:that.endDate.minutes,seconds:that.endDate.seconds,};if(options.type===\"month\"){options.dateTime.date=1;that.endDate.date=1}}if(minMaxError&&value){that.setValue(that.parse());that.hint(\"value \"+lang.invalidDate+lang.formatError[1])}that.startDate=that.startDate||value&&lay.extend({},options.dateTime);that.autoCalendarModel.auto&&that.autoCalendarModel();that.endState=!options.range||!that.rangeLinked||!!(that.startDate&&that.endDate);fn&&fn();return that};Class.prototype.mark=function(td,YMD){var that=this,mark,options=that.config;lay.each(options.mark,function(key,title){var keys=key.split(\"-\");if((keys[0]==YMD[0]||keys[0]==0)&&(keys[1]==YMD[1]||keys[1]==0)&&keys[2]==YMD[2]){mark=title||YMD[2]}});mark&&td.find(\"div\").html('<span class=\"laydate-day-mark\">'+mark+\"</span>\");return that};Class.prototype.holidays=function(td,YMD){var that=this;var options=that.config;var type=[\"\",\"work\"];if(layui.type(options.holidays)!==\"array\"){return that}lay.each(options.holidays,function(idx,item){lay.each(item,function(i,dayStr){if(dayStr===td.attr(\"lay-ymd\")){td.find(\"div\").html('<span class=\"laydate-day-holidays\"'+(type[idx]?('type=\"'+type[idx]+'\"'):\"\")+\">\"+YMD[2]+\"</span>\")}})});return that};Class.prototype.limit=function(opts){opts=opts||{};var that=this;var options=that.config;var timestamp={};var dateTime=opts.index>(opts.time?0:41)?that.endDate:options.dateTime;var isOut;lay.each({now:lay.extend({},dateTime,opts.date||{}),min:options.min,max:options.max},function(key,item){timestamp[key]=that.newDate(lay.extend({year:item.year,month:opts.type===\"year\"?0:item.month,date:(opts.type===\"year\"||opts.type===\"month\")?1:item.date},function(){var hms={};lay.each(opts.time,function(i,keys){hms[keys]=item[keys]});return hms}())).getTime()});isOut=timestamp.now<timestamp.min||timestamp.now>timestamp.max;opts.elem&&opts.elem[isOut?\"addClass\":\"removeClass\"](DISABLED);return isOut};Class.prototype.thisDateTime=function(index){var that=this,options=that.config;return index?that.endDate:options.dateTime};Class.prototype.calendar=function(value,index,type){index=index?1:0;var that=this,options=that.config,dateTime=value||that.thisDateTime(index),thisDate=new Date(),startWeek,prevMaxDate,thisMaxDate,lang=that.lang(),isAlone=options.type!==\"date\"&&options.type!==\"datetime\",tds=lay(that.table[index]).find(\"td\"),elemYM=lay(that.elemHeader[index][2]).find(\"span\");if(dateTime.year<LIMIT_YEAR[0]){dateTime.year=LIMIT_YEAR[0],that.hint(lang.invalidDate)}if(dateTime.year>LIMIT_YEAR[1]){dateTime.year=LIMIT_YEAR[1],that.hint(lang.invalidDate)}if(!that.firstDate){that.firstDate=lay.extend({},dateTime)}thisDate.setFullYear(dateTime.year,dateTime.month,1);startWeek=(thisDate.getDay()+(7-options.weekStart))%7;prevMaxDate=laydate.getEndDate(dateTime.month||12,dateTime.year);thisMaxDate=laydate.getEndDate(dateTime.month+1,dateTime.year);lay.each(tds,function(index_,item){var YMD=[dateTime.year,dateTime.month],st;item=lay(item);item.removeAttr(\"class\");if(index_<startWeek){st=prevMaxDate-startWeek+index_;item.addClass(\"laydate-day-prev\");YMD=that.getAsYM(dateTime.year,dateTime.month,\"sub\")}else{if(index_>=startWeek&&index_<thisMaxDate+startWeek){st=index_-startWeek;if(!that.rangeLinked){st+1===dateTime.date&&item.addClass(THIS)}}else{st=index_-thisMaxDate-startWeek;item.addClass(\"laydate-day-next\");YMD=that.getAsYM(dateTime.year,dateTime.month)}}YMD[1]++;YMD[2]=st+1;item.attr(\"lay-ymd\",YMD.join(\"-\")).html(\"<div>\"+YMD[2]+\"</div>\");that.mark(item,YMD).holidays(item,YMD).limit({elem:item,date:{year:YMD[0],month:YMD[1]-1,date:YMD[2]},index:index_})});lay(elemYM[0]).attr(\"lay-ym\",dateTime.year+\"-\"+(dateTime.month+1));lay(elemYM[1]).attr(\"lay-ym\",dateTime.year+\"-\"+(dateTime.month+1));if(options.lang===\"cn\"){lay(elemYM[0]).attr(\"lay-type\",\"year\").html(dateTime.year+\" 年\");lay(elemYM[1]).attr(\"lay-type\",\"month\").html((dateTime.month+1)+\" 月\")}else{lay(elemYM[0]).attr(\"lay-type\",\"month\").html(lang.month[dateTime.month]);lay(elemYM[1]).attr(\"lay-type\",\"year\").html(dateTime.year)}if(isAlone){if(options.range){if(value||type!==\"init\"){that.listYM=[[(that.startDate||options.dateTime).year,(that.startDate||options.dateTime).month+1],[that.endDate.year,that.endDate.month+1]];that.list(options.type,0).list(options.type,1);options.type===\"time\"?that.setBtnStatus(\"时间\",lay.extend({},that.systemDate(),that.startTime),lay.extend({},that.systemDate(),that.endTime)):that.setBtnStatus(true)}}else{that.listYM=[[dateTime.year,dateTime.month+1]];that.list(options.type,0)}}if(options.range&&type===\"init\"){if(that.rangeLinked){var EYM=that.getAsYM(dateTime.year,dateTime.month,index?\"sub\":null);that.calendar(lay.extend({},dateTime,{year:EYM[0],month:EYM[1]}),1-index)}else{that.calendar(null,1-index)}}if(!options.range){var timeParams=[\"hours\",\"minutes\",\"seconds\"];that.limit({elem:lay(that.footer).find(ELEM_NOW),date:that.systemDate(/^(datetime|time)$/.test(options.type)?new Date():null),index:0,time:timeParams});that.limit({elem:lay(that.footer).find(ELEM_CONFIRM),index:0,time:timeParams})}that.setBtnStatus();lay(that.shortcut).find(\"li.\"+THIS).removeClass(THIS);if(options.range&&!isAlone&&type!==\"init\"){that.stampRange()}return that};Class.prototype.list=function(type,index){var that=this,options=that.config,dateTime=that.rangeLinked?options.dateTime:[options.dateTime,that.endDate][index],lang=that.lang(),isAlone=options.range&&options.type!==\"date\"&&options.type!==\"datetime\",ul=lay.elem(\"ul\",{\"class\":ELEM_LIST+\" \"+({year:\"laydate-year-list\",month:\"laydate-month-list\",time:\"laydate-time-list\"})[type]}),elemHeader=that.elemHeader[index],elemYM=lay(elemHeader[2]).find(\"span\"),elemCont=that.elemCont[index||0],haveList=lay(elemCont).find(\".\"+ELEM_LIST)[0],isCN=options.lang===\"cn\",text=isCN?\"年\":\"\",listYM=that.listYM[index]||{},hms=[\"hours\",\"minutes\",\"seconds\"],startEnd=[\"startTime\",\"endTime\"][index];if(listYM[0]<1){listYM[0]=1}if(type===\"year\"){var yearNum,startY=yearNum=listYM[0]-7;if(startY<1){startY=yearNum=1}lay.each(new Array(15),function(i){var li=lay.elem(\"li\",{\"lay-ym\":yearNum}),ymd={year:yearNum,month:0,date:1};yearNum==listYM[0]&&lay(li).addClass(THIS);li.innerHTML=yearNum+text;ul.appendChild(li);that.limit({elem:lay(li),date:ymd,index:index,type:type});yearNum++});lay(elemYM[isCN?0:1]).attr(\"lay-ym\",(yearNum-8)+\"-\"+listYM[1]).html((startY+text)+\" - \"+(yearNum-1+text))}else{if(type===\"month\"){lay.each(new Array(12),function(i){var li=lay.elem(\"li\",{\"lay-ym\":i}),ymd={year:listYM[0],month:i,date:1};i+1==listYM[1]&&lay(li).addClass(THIS);li.innerHTML=lang.month[i]+(isCN?\"月\":\"\");ul.appendChild(li);that.limit({elem:lay(li),date:ymd,index:index,type:type})});lay(elemYM[isCN?0:1]).attr(\"lay-ym\",listYM[0]+\"-\"+listYM[1]).html(listYM[0]+text)}else{if(type===\"time\"){var setTimeStatus=function(){lay(ul).find(\"ol\").each(function(i,ol){lay(ol).find(\"li\").each(function(ii,li){that.limit({elem:lay(li),date:[{hours:ii},{hours:that[startEnd].hours,minutes:ii},{hours:that[startEnd].hours,minutes:that[startEnd].minutes,seconds:ii}][i],index:index,time:[[\"hours\"],[\"hours\",\"minutes\"],[\"hours\",\"minutes\",\"seconds\"]][i]})})});if(!options.range){that.limit({elem:lay(that.footer).find(ELEM_CONFIRM),date:that[startEnd],inedx:0,time:[\"hours\",\"minutes\",\"seconds\"]})}};if(options.range){if(!that[startEnd]){that[startEnd]=startEnd===\"startTime\"?dateTime:that.endDate}}else{that[startEnd]=dateTime}lay.each([24,60,60],function(i,item){var li=lay.elem(\"li\"),childUL=[\"<p>\"+lang.time[i]+\"</p><ol>\"];lay.each(new Array(item),function(ii){childUL.push(\"<li\"+(that[startEnd][hms[i]]===ii?' class=\"'+THIS+'\"':\"\")+\">\"+lay.digit(ii,2)+\"</li>\")});li.innerHTML=childUL.join(\"\")+\"</ol>\";ul.appendChild(li)});setTimeStatus()}}}if(haveList){elemCont.removeChild(haveList)}elemCont.appendChild(ul);if(type===\"year\"||type===\"month\"){lay(that.elemMain[index]).addClass(\"laydate-ym-show\");lay(ul).find(\"li\").on(\"click\",function(){var ym=lay(this).attr(\"lay-ym\")|0;if(lay(this).hasClass(DISABLED)){return}if(that.rangeLinked){lay.extend(dateTime,{year:type===\"year\"?ym:listYM[0],month:type===\"year\"?listYM[1]-1:ym})}else{dateTime[type]=ym}var isYearOrMonth=options.type===\"year\"||options.type===\"month\";if(isYearOrMonth){lay(ul).find(\".\"+THIS).removeClass(THIS);lay(this).addClass(THIS);if(options.type===\"month\"&&type===\"year\"){that.listYM[index][0]=ym;isAlone&&((index?that.endDate:dateTime).year=ym);that.list(\"month\",index)}}else{that.checkDate(\"limit\").calendar(dateTime,index,\"init\");that.closeList()}that.setBtnStatus();if(!options.range&&options.autoConfirm){if((options.type===\"month\"&&type===\"month\")||(options.type===\"year\"&&type===\"year\")){that.setValue(that.parse()).done().remove()}}(that.autoCalendarModel.auto&&!that.rangeLinked)?that.choose(lay(elemCont).find(\"td.layui-this\"),index):(that.endState&&that.done(null,\"change\"));lay(that.footer).find(\".\"+ELEM_TIME_BTN).removeClass(DISABLED)})}else{var span=lay.elem(\"span\",{\"class\":ELEM_TIME_TEXT}),scroll=function(){lay(ul).find(\"ol\").each(function(i){var ol=this,li=lay(ol).find(\"li\");ol.scrollTop=30*(that[startEnd][hms[i]]-2);if(ol.scrollTop<=0){li.each(function(ii,item){if(!lay(this).hasClass(DISABLED)){ol.scrollTop=30*(ii-2);return true}})}})},haveSpan=lay(elemHeader[2]).find(\".\"+ELEM_TIME_TEXT);scroll();span.innerHTML=options.range?[lang.startTime,lang.endTime][index]:lang.timeTips;lay(that.elemMain[index]).addClass(\"laydate-time-show\");if(haveSpan[0]){haveSpan.remove()}elemHeader[2].appendChild(span);lay(ul).find(\"ol\").each(function(i){var ol=this;lay(ol).find(\"li\").on(\"click\",function(){var value=this.innerHTML|0;if(lay(this).hasClass(DISABLED)){return}if(options.range){that[startEnd][hms[i]]=value}else{dateTime[hms[i]]=value}lay(ol).find(\".\"+THIS).removeClass(THIS);lay(this).addClass(THIS);setTimeStatus();scroll();(that.endDate||options.type===\"time\"||(options.type===\"datetime\"&&options.fullPanel))&&that.done(null,\"change\");that.setBtnStatus()})})}return that};Class.prototype.listYM=[];Class.prototype.closeList=function(){var that=this,options=that.config;lay.each(that.elemCont,function(index,item){lay(this).find(\".\"+ELEM_LIST).remove();lay(that.elemMain[index]).removeClass(\"laydate-ym-show laydate-time-show\")});lay(that.elem).find(\".\"+ELEM_TIME_TEXT).remove()};Class.prototype.setBtnStatus=function(tips,start,end){var that=this,options=that.config,lang=that.lang(),isOut,elemBtn=lay(that.footer).find(ELEM_CONFIRM);if(options.range&&options.type!==\"time\"){start=start||(that.rangeLinked?that.startDate:options.dateTime);end=end||that.endDate;isOut=!that.endState||that.newDate(start).getTime()>that.newDate(end).getTime();(that.limit({date:start})||that.limit({date:end}))?elemBtn.addClass(DISABLED):elemBtn[isOut?\"addClass\":\"removeClass\"](DISABLED);if(tips&&isOut){that.hint(typeof tips===\"string\"?lang.timeout.replace(/日期/g,tips):lang.timeout)}}};Class.prototype.parse=function(state,date){var that=this;var options=that.config;var startDate=(that.rangeLinked?that.startDate:options.dateTime);var dateTime=date||(state==\"end\"?lay.extend({},that.endDate,that.endTime):(options.range?lay.extend({},startDate||options.dateTime,that.startTime):options.dateTime));var format=laydate.parse(dateTime,that.format,1);if(options.range&&state===undefined){return format+\" \"+that.rangeStr+\" \"+that.parse(\"end\")}return format};Class.prototype.newDate=function(dateTime){dateTime=dateTime||{};return new Date(dateTime.year||1,dateTime.month||0,dateTime.date||1,dateTime.hours||0,dateTime.minutes||0,dateTime.seconds||0)};Class.prototype.getDateTime=function(obj){return this.newDate(obj).getTime()};Class.prototype.setValue=function(value){var that=this,options=that.config,elem=options.elem[0];if(options.position===\"static\"){return that}value=value||\"\";if(that.isInput(elem)){lay(elem).val(value)}else{var rangeElem=that.rangeElem;if(rangeElem){if(layui.type(value)!==\"array\"){value=value.split(\" \"+that.rangeStr+\" \")}rangeElem[0].val(value[0]||\"\");rangeElem[1].val(value[1]||\"\")}else{if(lay(elem).find(\"*\").length===0){lay(elem).html(value)}lay(elem).attr(\"lay-date\",value)}}return that};Class.prototype.preview=function(){var that=this,options=that.config;if(!options.isPreview){return}var elemPreview=lay(that.elem).find(\".\"+ELEM_PREVIEW),value=options.range?((that.rangeLinked?that.endState:that.endDate)?that.parse():\"\"):that.parse();elemPreview.html(value);var oldValue=elemPreview.html();oldValue&&(elemPreview.css({\"color\":\"#16b777\"}),setTimeout(function(){elemPreview.css({\"color\":\"#777\"})},300))};Class.prototype.renderAdditional=function(){var that=this;var options=that.config;if(options.fullPanel){that.list(\"time\",0)}};Class.prototype.stampRange=function(){var that=this,options=that.config,startTime=that.rangeLinked?that.startDate:options.dateTime,endTime,tds=lay(that.elem).find(\"td\");if(options.range&&!that.endState){lay(that.footer).find(ELEM_CONFIRM).addClass(DISABLED)}startTime=startTime&&that.newDate({year:startTime.year,month:startTime.month,date:startTime.date}).getTime();endTime=that.endState&&that.endDate&&that.newDate({year:that.endDate.year,month:that.endDate.month,date:that.endDate.date}).getTime();lay.each(tds,function(i,item){var ymd=lay(item).attr(\"lay-ymd\").split(\"-\");var thisTime=that.newDate({year:ymd[0],month:ymd[1]-1,date:ymd[2]}).getTime();if(options.rangeLinked&&!that.startDate){if(thisTime===that.newDate(that.systemDate()).getTime()){lay(item).addClass(lay(item).hasClass(ELEM_PREV)||lay(item).hasClass(ELEM_NEXT)?\"\":ELEM_DAY_NOW)}}lay(item).removeClass(ELEM_SELECTED+\" \"+THIS);if(thisTime===startTime||thisTime===endTime){(that.rangeLinked||(!that.rangeLinked&&(i<42?thisTime===startTime:thisTime===endTime)))&&lay(item).addClass(lay(item).hasClass(ELEM_PREV)||lay(item).hasClass(ELEM_NEXT)?ELEM_SELECTED:THIS)}if(thisTime>startTime&&thisTime<endTime){lay(item).addClass(ELEM_SELECTED)}})};Class.prototype.done=function(param,type){var that=this;var options=that.config;var start=lay.extend({},lay.extend(that.rangeLinked?that.startDate:options.dateTime,that.startTime));var end=lay.extend({},lay.extend(that.endDate,that.endTime));lay.each([start,end],function(i,item){if(!(\"month\" in item)){return}lay.extend(item,{month:item.month+1})});that.preview();param=param||[that.parse(),start,end];type===\"change\"&&that.renderAdditional();typeof options[type||\"done\"]===\"function\"&&options[type||\"done\"].apply(options,param);return that};Class.prototype.choose=function(td,index){if(td.hasClass(DISABLED)){return}var that=this,options=that.config,panelIndex=index;if(that.rangeLinked){if(that.endState||!that.startDate){index=0;that.endState=false;that.endDate={}}else{index=1;that.endState=true}}var dateTime=that.thisDateTime(index),tds=lay(that.elem).find(\"td\"),YMD=td.attr(\"lay-ymd\").split(\"-\");YMD={year:YMD[0]|0,month:(YMD[1]|0)-1,date:YMD[2]|0};lay.extend(dateTime,YMD);if(options.range){lay.each([\"startTime\",\"endTime\"],function(i,item){that[item]=that[item]||{hours:i?23:0,minutes:i?59:0,seconds:i?59:0};if(index===i){if(that.getDateTime(lay.extend({},dateTime,that[item]))<that.getDateTime(options.min)){that[item]={hours:options.min.hours,minutes:options.min.minutes,seconds:options.min.seconds};lay.extend(dateTime,that[item])}else{if(that.getDateTime(lay.extend({},dateTime,that[item]))>that.getDateTime(options.max)){that[item]={hours:options.max.hours,minutes:options.max.minutes,seconds:options.max.seconds};lay.extend(dateTime,that[item])}}}});if(!index){that.startDate=lay.extend({},dateTime)}if(that.endState&&!that.limit({date:that.thisDateTime(1-index)})){var isChange;if(that.endState&&that.autoCalendarModel.auto){isChange=that.autoCalendarModel()}if((isChange||that.rangeLinked&&that.endState)&&that.newDate(that.startDate)>that.newDate(that.endDate)){var isSameDate=that.startDate.year===that.endDate.year&&that.startDate.month===that.endDate.month&&that.startDate.date===that.endDate.date;var startDate=that.startDate;that.startDate=lay.extend({},that.endDate,isSameDate?{}:that.startTime);options.dateTime=lay.extend({},that.startDate);that.endDate=lay.extend({},startDate,isSameDate?{}:that.endTime);isSameDate&&(startDate=that.startTime,that.startTime=that.endTime,that.endTime=startDate)}isChange&&(options.dateTime=lay.extend({},that.startDate))}if(that.rangeLinked){var dateTimeTemp=lay.extend({},dateTime);if(panelIndex&&!index&&!isChange){var YM=that.getAsYM(dateTime.year,dateTime.month,\"sub\");lay.extend(options.dateTime,{year:YM[0],month:YM[1]})}that.calendar(dateTimeTemp,panelIndex,isChange?\"init\":null)}else{that.calendar(null,index,isChange?\"init\":null)}that.endState&&that.done(null,\"change\")}else{if(options.position===\"static\"){that.calendar().done().done(null,\"change\")}else{if(options.type===\"date\"){options.autoConfirm?that.setValue(that.parse()).done().remove():that.calendar().done(null,\"change\")}else{if(options.type===\"datetime\"){that.calendar().done(null,\"change\")}}}}};Class.prototype.tool=function(btn,type){var that=this,options=that.config,lang=that.lang(),dateTime=options.dateTime,isStatic=options.position===\"static\",active={datetime:function(){if(lay(btn).hasClass(DISABLED)){return}that.list(\"time\",0);options.range&&that.list(\"time\",1);lay(btn).attr(\"lay-type\",\"date\").html(that.lang().dateTips)},date:function(){that.closeList();lay(btn).attr(\"lay-type\",\"datetime\").html(that.lang().timeTips)},clear:function(){isStatic&&(lay.extend(dateTime,that.firstDate),that.calendar());options.range&&(delete options.dateTime,delete that.endDate,delete that.startTime,delete that.endTime);that.setValue(\"\");that.done(null,\"onClear\").done([\"\",{},{}]).remove()},now:function(){var thisDate=new Date();if(lay(btn).hasClass(DISABLED)){return that.hint(lang.tools.now+\", \"+lang.invalidDate)}lay.extend(dateTime,that.systemDate(),{hours:thisDate.getHours(),minutes:thisDate.getMinutes(),seconds:thisDate.getSeconds()});that.setValue(that.parse());isStatic&&that.calendar();that.done(null,\"onNow\").done().remove()},confirm:function(){if(options.range){if(lay(btn).hasClass(DISABLED)){return that.hint(options.type===\"time\"?lang.timeout.replace(/日期/g,\"时间\"):lang.timeout)}}else{if(lay(btn).hasClass(DISABLED)){return that.hint(lang.invalidDate)}}that.setValue(that.parse());that.done(null,\"onConfirm\").done().remove()}};active[type]&&active[type]()};Class.prototype.change=function(index){var that=this,options=that.config,dateTime=that.thisDateTime(index),isAlone=options.range&&(options.type===\"year\"||options.type===\"month\"),elemCont=that.elemCont[index||0],listYM=that.listYM[index],addSubYear=function(type){var isYear=lay(elemCont).find(\".laydate-year-list\")[0],isMonth=lay(elemCont).find(\".laydate-month-list\")[0];if(isYear){listYM[0]=type?listYM[0]-15:listYM[0]+15;that.list(\"year\",index)}if(isMonth){type?listYM[0]--:listYM[0]++;that.list(\"month\",index)}if(isYear||isMonth){lay.extend(dateTime,{year:listYM[0]});if(isAlone){dateTime.year=listYM[0]}options.range||that.done(null,\"change\");options.range||that.limit({elem:lay(that.footer).find(ELEM_CONFIRM),date:{year:listYM[0]}})}that.setBtnStatus();return isYear||isMonth};return{prevYear:function(){if(addSubYear(\"sub\")){return}if(that.rangeLinked){options.dateTime.year--;that.checkDate(\"limit\").calendar(null,null,\"init\")}else{dateTime.year--;that.checkDate(\"limit\").calendar(null,index);that.autoCalendarModel.auto?that.choose(lay(elemCont).find(\"td.layui-this\"),index):that.done(null,\"change\")}},prevMonth:function(){if(that.rangeLinked){dateTime=options.dateTime}var YM=that.getAsYM(dateTime.year,dateTime.month,\"sub\");lay.extend(dateTime,{year:YM[0],month:YM[1]});that.checkDate(\"limit\").calendar(null,null,\"init\");if(!that.rangeLinked){that.autoCalendarModel.auto?that.choose(lay(elemCont).find(\"td.layui-this\"),index):that.done(null,\"change\")}},nextMonth:function(){if(that.rangeLinked){dateTime=options.dateTime}var YM=that.getAsYM(dateTime.year,dateTime.month);lay.extend(dateTime,{year:YM[0],month:YM[1]});that.checkDate(\"limit\").calendar(null,null,\"init\");if(!that.rangeLinked){that.autoCalendarModel.auto?that.choose(lay(elemCont).find(\"td.layui-this\"),index):that.done(null,\"change\")}},nextYear:function(){if(addSubYear()){return}if(that.rangeLinked){options.dateTime.year++;that.checkDate(\"limit\").calendar(null,0,\"init\")}else{dateTime.year++;that.checkDate(\"limit\").calendar(null,index);that.autoCalendarModel.auto?that.choose(lay(elemCont).find(\"td.layui-this\"),index):that.done(null,\"change\")}}}};Class.prototype.changeEvent=function(){var that=this,options=that.config;lay(that.elem).on(\"click\",function(e){lay.stope(e)}).on(\"mousedown\",function(e){lay.stope(e)});lay.each(that.elemHeader,function(i,header){lay(header[0]).on(\"click\",function(e){that.change(i).prevYear()});lay(header[1]).on(\"click\",function(e){that.change(i).prevMonth()});lay(header[2]).find(\"span\").on(\"click\",function(e){var othis=lay(this),layYM=othis.attr(\"lay-ym\"),layType=othis.attr(\"lay-type\");if(!layYM){return}layYM=layYM.split(\"-\");that.listYM[i]=[layYM[0]|0,layYM[1]|0];that.list(layType,i);lay(that.footer).find(\".\"+ELEM_TIME_BTN).addClass(DISABLED)});lay(header[3]).on(\"click\",function(e){that.change(i).nextMonth()});lay(header[4]).on(\"click\",function(e){that.change(i).nextYear()})});lay.each(that.table,function(i,table){var tds=lay(table).find(\"td\");tds.on(\"click\",function(){that.choose(lay(this),i)})});lay(that.footer).find(\"span\").on(\"click\",function(){var type=lay(this).attr(\"lay-type\");that.tool(this,type)})};Class.prototype.isInput=function(elem){return/input|textarea/.test(elem.tagName.toLocaleLowerCase())||/INPUT|TEXTAREA/.test(elem.tagName)};Class.prototype.events=function(){var that=this;var options=that.config;if(!options.elem[0]||options.elem[0].eventHandler){return}var showEvent=function(){if(laydate.thisId===options.id){return}that.render()};options.elem.on(options.trigger,showEvent);options.elem[0].eventHandler=true;options.eventElem.on(options.trigger,showEvent);that.unbind=function(){that.remove();options.elem.off(options.trigger,showEvent);options.elem.removeAttr(\"lay-key\");options.elem.removeAttr(MOD_ID);options.elem[0].eventHandler=false;options.eventElem.off(options.trigger,showEvent);options.eventElem.removeAttr(\"lay-key\");delete thisModule.that[options.id]}};thisModule.that={};thisModule.getThis=function(id){var that=thisModule.that[id];if(!that&&isLayui){layui.hint().error(id?(MOD_NAME+\" instance with ID '\"+id+\"' not found\"):\"ID argument required\")}return that};ready.run=function(lay){lay(document).on(\"mousedown\",function(e){if(!laydate.thisId){return}var that=thisModule.getThis(laydate.thisId);if(!that){return}var options=that.config;if(e.target===options.elem[0]||e.target===options.eventElem[0]||e.target===lay(options.closeStop)[0]||(options.elem[0]&&options.elem[0].contains(e.target))){return}that.remove()}).on(\"keydown\",function(e){if(!laydate.thisId){return}var that=thisModule.getThis(laydate.thisId);if(!that){return}if(that.config.position===\"static\"){return}if(e.keyCode===13){if(lay(\"#\"+that.elemID)[0]&&that.elemID===Class.thisElemDate){e.preventDefault();lay(that.footer).find(ELEM_CONFIRM)[0].click()}}});lay(window).on(\"resize\",function(){if(!laydate.thisId){return}var that=thisModule.getThis(laydate.thisId);if(!that){return}if(!that.elem||!lay(ELEM)[0]){return false}that.position()})};laydate.render=function(options){var inst=new Class(options);return thisModule.call(inst)};laydate.reload=function(id,options){var that=thisModule.getThis(id);if(!that){return}return that.reload(options)};laydate.getInst=function(id){var that=thisModule.getThis(id);if(that){return that.inst}};laydate.hint=function(id,opts){var that=thisModule.getThis(id);if(!that){return}return that.hint(opts)};laydate.unbind=function(id){var that=thisModule.getThis(id);if(!that){return}return that.unbind()};laydate.close=function(id){var that=thisModule.getThis(id||laydate.thisId);if(!that){return}return that.remove()};laydate.parse=function(dateTime,format,one){dateTime=dateTime||{};if(typeof format===\"string\"){format=thisModule.formatArr(format)}format=(format||[]).concat();lay.each(format,function(i,item){if(/yyyy|y/.test(item)){format[i]=lay.digit(dateTime.year,item.length)}else{if(/MM|M/.test(item)){format[i]=lay.digit(dateTime.month+(one||0),item.length)}else{if(/dd|d/.test(item)){format[i]=lay.digit(dateTime.date,item.length)}else{if(/HH|H/.test(item)){format[i]=lay.digit(dateTime.hours,item.length)}else{if(/mm|m/.test(item)){format[i]=lay.digit(dateTime.minutes,item.length)}else{if(/ss|s/.test(item)){format[i]=lay.digit(dateTime.seconds,item.length)}}}}}}});return format.join(\"\")};laydate.getEndDate=function(month,year){var thisDate=new Date();thisDate.setFullYear(year||thisDate.getFullYear(),month||(thisDate.getMonth()+1),1);return new Date(thisDate.getTime()-1000*60*60*24).getDate()};isLayui?(laydate.ready(),layui.define(\"lay\",function(exports){laydate.path=layui.cache.dir;ready.run(lay);exports(MOD_NAME,laydate)})):((typeof define===\"function\"&&define.amd)?define(function(){ready.run(lay);return laydate}):function(){laydate.ready();ready.run(window.lay);window.laydate=laydate}())}(window,window.document);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/select2/select2.css",
    "content": ".select2-container {\n  box-sizing: border-box;\n  display: inline-block;\n  margin: 0;\n  position: relative;\n  vertical-align: middle; }\n  .select2-container .select2-selection--single {\n    box-sizing: border-box;\n    cursor: pointer;\n    display: block;\n    height: 28px;\n    user-select: none;\n    -webkit-user-select: none; }\n    .select2-container .select2-selection--single .select2-selection__rendered {\n      display: block;\n      padding-left: 8px;\n      padding-right: 20px;\n      overflow: hidden;\n      text-overflow: ellipsis;\n      white-space: nowrap; }\n    .select2-container .select2-selection--single .select2-selection__clear {\n      position: relative; }\n  .select2-container[dir=\"rtl\"] .select2-selection--single .select2-selection__rendered {\n    padding-right: 8px;\n    padding-left: 20px; }\n  .select2-container .select2-selection--multiple {\n    box-sizing: border-box;\n    cursor: pointer;\n    display: block;\n    min-height: 32px;\n    user-select: none;\n    -webkit-user-select: none; }\n    .select2-container .select2-selection--multiple .select2-selection__rendered {\n      display: inline-block;\n      overflow: hidden;\n      padding-left: 8px;\n      text-overflow: ellipsis;\n      white-space: nowrap; }\n  .select2-container .select2-search--inline {\n    float: left; }\n    .select2-container .select2-search--inline .select2-search__field {\n      box-sizing: border-box;\n      border: none;\n      font-size: 100%;\n      margin-top: 5px;\n      padding: 0; }\n      .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {\n        -webkit-appearance: none; }\n\n.select2-dropdown {\n  background-color: white;\n  border: 1px solid #aaa;\n  border-radius: 4px;\n  box-sizing: border-box;\n  display: block;\n  position: absolute;\n  left: -100000px;\n  width: 100%;\n  z-index: 1051; }\n\n.select2-results {\n  display: block; }\n\n.select2-results__options {\n  list-style: none;\n  margin: 0;\n  padding: 0; }\n\n.select2-results__option {\n  padding: 6px;\n  user-select: none;\n  -webkit-user-select: none; }\n  .select2-results__option[aria-selected] {\n    cursor: pointer; }\n\n.select2-container--open .select2-dropdown {\n  left: 0; }\n\n.select2-container--open .select2-dropdown--above {\n  border-bottom: none;\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0; }\n\n.select2-container--open .select2-dropdown--below {\n  border-top: none;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0; }\n\n.select2-search--dropdown {\n  display: block;\n  padding: 4px; }\n  .select2-search--dropdown .select2-search__field {\n    padding: 4px;\n    width: 100%;\n    box-sizing: border-box; }\n    .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {\n      -webkit-appearance: none; }\n  .select2-search--dropdown.select2-search--hide {\n    display: none; }\n\n.select2-close-mask {\n  border: 0;\n  margin: 0;\n  padding: 0;\n  display: block;\n  position: fixed;\n  left: 0;\n  top: 0;\n  min-height: 100%;\n  min-width: 100%;\n  height: auto;\n  width: auto;\n  opacity: 0;\n  z-index: 99;\n  background-color: #fff;\n  filter: alpha(opacity=0); }\n\n.select2-hidden-accessible {\n  border: 0 !important;\n  clip: rect(0 0 0 0) !important;\n  -webkit-clip-path: inset(50%) !important;\n  clip-path: inset(50%) !important;\n  height: 1px !important;\n  overflow: hidden !important;\n  padding: 0 !important;\n  position: absolute !important;\n  width: 1px !important;\n  white-space: nowrap !important; }\n\n.select2-container--default .select2-selection--single {\n  background-color: #fff;\n  border: 1px solid #aaa;\n  border-radius: 4px; }\n  .select2-container--default .select2-selection--single .select2-selection__rendered {\n    color: #444;\n    line-height: 28px; }\n  .select2-container--default .select2-selection--single .select2-selection__clear {\n    cursor: pointer;\n    float: right;\n    font-weight: bold; }\n  .select2-container--default .select2-selection--single .select2-selection__placeholder {\n    color: #999; }\n  .select2-container--default .select2-selection--single .select2-selection__arrow {\n    height: 26px;\n    position: absolute;\n    top: 1px;\n    right: 1px;\n    width: 20px; }\n    .select2-container--default .select2-selection--single .select2-selection__arrow b {\n      border-color: #888 transparent transparent transparent;\n      border-style: solid;\n      border-width: 5px 4px 0 4px;\n      height: 0;\n      left: 50%;\n      margin-left: -4px;\n      margin-top: -2px;\n      position: absolute;\n      top: 50%;\n      width: 0; }\n\n.select2-container--default[dir=\"rtl\"] .select2-selection--single .select2-selection__clear {\n  float: left; }\n\n.select2-container--default[dir=\"rtl\"] .select2-selection--single .select2-selection__arrow {\n  left: 1px;\n  right: auto; }\n\n.select2-container--default.select2-container--disabled .select2-selection--single {\n  background-color: #eee;\n  cursor: default; }\n  .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {\n    display: none; }\n\n.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {\n  border-color: transparent transparent #888 transparent;\n  border-width: 0 4px 5px 4px; }\n\n.select2-container--default .select2-selection--multiple {\n  background-color: white;\n  border: 1px solid #aaa;\n  border-radius: 4px;\n  cursor: text; }\n  .select2-container--default .select2-selection--multiple .select2-selection__rendered {\n    box-sizing: border-box;\n    list-style: none;\n    margin: 0;\n    padding: 0 5px;\n    width: 100%; }\n    .select2-container--default .select2-selection--multiple .select2-selection__rendered li {\n      list-style: none; }\n  .select2-container--default .select2-selection--multiple .select2-selection__clear {\n    cursor: pointer;\n    float: right;\n    font-weight: bold;\n    margin-top: 5px;\n    margin-right: 10px;\n    padding: 1px; }\n  .select2-container--default .select2-selection--multiple .select2-selection__choice {\n    background-color: #e4e4e4;\n    border: 1px solid #aaa;\n    border-radius: 4px;\n    cursor: default;\n    float: left;\n    margin-right: 5px;\n    margin-top: 5px;\n    padding: 0 5px; }\n  .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {\n    color: #999;\n    cursor: pointer;\n    display: inline-block;\n    font-weight: bold;\n    margin-right: 2px; }\n    .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {\n      color: #333; }\n\n.select2-container--default[dir=\"rtl\"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir=\"rtl\"] .select2-selection--multiple .select2-search--inline {\n  float: right; }\n\n.select2-container--default[dir=\"rtl\"] .select2-selection--multiple .select2-selection__choice {\n  margin-left: 5px;\n  margin-right: auto; }\n\n.select2-container--default[dir=\"rtl\"] .select2-selection--multiple .select2-selection__choice__remove {\n  margin-left: 2px;\n  margin-right: auto; }\n\n.select2-container--default.select2-container--focus .select2-selection--multiple {\n  border: solid black 1px;\n  outline: 0; }\n\n.select2-container--default.select2-container--disabled .select2-selection--multiple {\n  background-color: #eee;\n  cursor: default; }\n\n.select2-container--default.select2-container--disabled .select2-selection__choice__remove {\n  display: none; }\n\n.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0; }\n\n.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0; }\n\n.select2-container--default .select2-search--dropdown .select2-search__field {\n  border: 1px solid #aaa; }\n\n.select2-container--default .select2-search--inline .select2-search__field {\n  background: transparent;\n  border: none;\n  outline: 0;\n  box-shadow: none;\n  -webkit-appearance: textfield; }\n\n.select2-container--default .select2-results > .select2-results__options {\n  max-height: 200px;\n  overflow-y: auto; }\n\n.select2-container--default .select2-results__option[role=group] {\n  padding: 0; }\n\n.select2-container--default .select2-results__option[aria-disabled=true] {\n  color: #999; }\n\n.select2-container--default .select2-results__option[aria-selected=true] {\n  background-color: #ddd; }\n\n.select2-container--default .select2-results__option .select2-results__option {\n  padding-left: 1em; }\n  .select2-container--default .select2-results__option .select2-results__option .select2-results__group {\n    padding-left: 0; }\n  .select2-container--default .select2-results__option .select2-results__option .select2-results__option {\n    margin-left: -1em;\n    padding-left: 2em; }\n    .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {\n      margin-left: -2em;\n      padding-left: 3em; }\n      .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {\n        margin-left: -3em;\n        padding-left: 4em; }\n        .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {\n          margin-left: -4em;\n          padding-left: 5em; }\n          .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {\n            margin-left: -5em;\n            padding-left: 6em; }\n\n.select2-container--default .select2-results__option--highlighted[aria-selected] {\n  background-color: #5897fb;\n  color: white; }\n\n.select2-container--default .select2-results__group {\n  cursor: default;\n  display: block;\n  padding: 6px; }\n\n.select2-container--classic .select2-selection--single {\n  background-color: #f7f7f7;\n  border: 1px solid #aaa;\n  border-radius: 4px;\n  outline: 0;\n  background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);\n  background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);\n  background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }\n  .select2-container--classic .select2-selection--single:focus {\n    border: 1px solid #5897fb; }\n  .select2-container--classic .select2-selection--single .select2-selection__rendered {\n    color: #444;\n    line-height: 28px; }\n  .select2-container--classic .select2-selection--single .select2-selection__clear {\n    cursor: pointer;\n    float: right;\n    font-weight: bold;\n    margin-right: 10px; }\n  .select2-container--classic .select2-selection--single .select2-selection__placeholder {\n    color: #999; }\n  .select2-container--classic .select2-selection--single .select2-selection__arrow {\n    background-color: #ddd;\n    border: none;\n    border-left: 1px solid #aaa;\n    border-top-right-radius: 4px;\n    border-bottom-right-radius: 4px;\n    height: 26px;\n    position: absolute;\n    top: 1px;\n    right: 1px;\n    width: 20px;\n    background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);\n    background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);\n    background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);\n    background-repeat: repeat-x;\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }\n    .select2-container--classic .select2-selection--single .select2-selection__arrow b {\n      border-color: #888 transparent transparent transparent;\n      border-style: solid;\n      border-width: 5px 4px 0 4px;\n      height: 0;\n      left: 50%;\n      margin-left: -4px;\n      margin-top: -2px;\n      position: absolute;\n      top: 50%;\n      width: 0; }\n\n.select2-container--classic[dir=\"rtl\"] .select2-selection--single .select2-selection__clear {\n  float: left; }\n\n.select2-container--classic[dir=\"rtl\"] .select2-selection--single .select2-selection__arrow {\n  border: none;\n  border-right: 1px solid #aaa;\n  border-radius: 0;\n  border-top-left-radius: 4px;\n  border-bottom-left-radius: 4px;\n  left: 1px;\n  right: auto; }\n\n.select2-container--classic.select2-container--open .select2-selection--single {\n  border: 1px solid #5897fb; }\n  .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {\n    background: transparent;\n    border: none; }\n    .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {\n      border-color: transparent transparent #888 transparent;\n      border-width: 0 4px 5px 4px; }\n\n.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {\n  border-top: none;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n  background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);\n  background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);\n  background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }\n\n.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {\n  border-bottom: none;\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0;\n  background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);\n  background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);\n  background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }\n\n.select2-container--classic .select2-selection--multiple {\n  background-color: white;\n  border: 1px solid #aaa;\n  border-radius: 4px;\n  cursor: text;\n  outline: 0; }\n  .select2-container--classic .select2-selection--multiple:focus {\n    border: 1px solid #5897fb; }\n  .select2-container--classic .select2-selection--multiple .select2-selection__rendered {\n    list-style: none;\n    margin: 0;\n    padding: 0 5px; }\n  .select2-container--classic .select2-selection--multiple .select2-selection__clear {\n    display: none; }\n  .select2-container--classic .select2-selection--multiple .select2-selection__choice {\n    background-color: #e4e4e4;\n    border: 1px solid #aaa;\n    border-radius: 4px;\n    cursor: default;\n    float: left;\n    margin-right: 5px;\n    margin-top: 5px;\n    padding: 0 5px; }\n  .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {\n    color: #888;\n    cursor: pointer;\n    display: inline-block;\n    font-weight: bold;\n    margin-right: 2px; }\n    .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {\n      color: #555; }\n\n.select2-container--classic[dir=\"rtl\"] .select2-selection--multiple .select2-selection__choice {\n  float: right;\n  margin-left: 5px;\n  margin-right: auto; }\n\n.select2-container--classic[dir=\"rtl\"] .select2-selection--multiple .select2-selection__choice__remove {\n  margin-left: 2px;\n  margin-right: auto; }\n\n.select2-container--classic.select2-container--open .select2-selection--multiple {\n  border: 1px solid #5897fb; }\n\n.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {\n  border-top: none;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0; }\n\n.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {\n  border-bottom: none;\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0; }\n\n.select2-container--classic .select2-search--dropdown .select2-search__field {\n  border: 1px solid #aaa;\n  outline: 0; }\n\n.select2-container--classic .select2-search--inline .select2-search__field {\n  outline: 0;\n  box-shadow: none; }\n\n.select2-container--classic .select2-dropdown {\n  background-color: white;\n  border: 1px solid transparent; }\n\n.select2-container--classic .select2-dropdown--above {\n  border-bottom: none; }\n\n.select2-container--classic .select2-dropdown--below {\n  border-top: none; }\n\n.select2-container--classic .select2-results > .select2-results__options {\n  max-height: 200px;\n  overflow-y: auto; }\n\n.select2-container--classic .select2-results__option[role=group] {\n  padding: 0; }\n\n.select2-container--classic .select2-results__option[aria-disabled=true] {\n  color: grey; }\n\n.select2-container--classic .select2-results__option--highlighted[aria-selected] {\n  background-color: #3875d7;\n  color: white; }\n\n.select2-container--classic .select2-results__group {\n  cursor: default;\n  display: block;\n  padding: 6px; }\n\n.select2-container--classic.select2-container--open .select2-dropdown {\n  border-color: #5897fb; }\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/select2/select2.js",
    "content": "/*!\n * Select2 4.0.13\n * https://select2.github.io\n *\n * Released under the MIT license\n * https://github.com/select2/select2/blob/master/LICENSE.md\n */\n;(function (factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module.\n    define(['jquery'], factory);\n  } else if (typeof module === 'object' && module.exports) {\n    // Node/CommonJS\n    module.exports = function (root, jQuery) {\n      if (jQuery === undefined) {\n        // require('jQuery') returns a factory that requires window to\n        // build a jQuery instance, we normalize how we use modules\n        // that require this pattern but the window provided is a noop\n        // if it's defined (how jquery works)\n        if (typeof window !== 'undefined') {\n          jQuery = require('jquery');\n        }\n        else {\n          jQuery = require('jquery')(root);\n        }\n      }\n      factory(jQuery);\n      return jQuery;\n    };\n  } else {\n    // Browser globals\n    factory(jQuery);\n  }\n} (function (jQuery) {\n  // This is needed so we can catch the AMD loader configuration and use it\n  // The inner file should be wrapped (by `banner.start.js`) in a function that\n  // returns the AMD loader references.\n  var S2 =(function () {\n  // Restore the Select2 AMD loader so it can be used\n  // Needed mostly in the language files, where the loader is not inserted\n  if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {\n    var S2 = jQuery.fn.select2.amd;\n  }\nvar S2;(function () { if (!S2 || !S2.requirejs) {\nif (!S2) { S2 = {}; } else { require = S2; }\n/**\n * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.\n * Released under MIT license, http://github.com/requirejs/almond/LICENSE\n */\n//Going sloppy to avoid 'use strict' string cost, but strict practices should\n//be followed.\n/*global setTimeout: false */\n\nvar requirejs, require, define;\n(function (undef) {\n    var main, req, makeMap, handlers,\n        defined = {},\n        waiting = {},\n        config = {},\n        defining = {},\n        hasOwn = Object.prototype.hasOwnProperty,\n        aps = [].slice,\n        jsSuffixRegExp = /\\.js$/;\n\n    function hasProp(obj, prop) {\n        return hasOwn.call(obj, prop);\n    }\n\n    /**\n     * Given a relative module name, like ./something, normalize it to\n     * a real name that can be mapped to a path.\n     * @param {String} name the relative name\n     * @param {String} baseName a real name that the name arg is relative\n     * to.\n     * @returns {String} normalized name\n     */\n    function normalize(name, baseName) {\n        var nameParts, nameSegment, mapValue, foundMap, lastIndex,\n            foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,\n            baseParts = baseName && baseName.split(\"/\"),\n            map = config.map,\n            starMap = (map && map['*']) || {};\n\n        //Adjust any relative paths.\n        if (name) {\n            name = name.split('/');\n            lastIndex = name.length - 1;\n\n            // If wanting node ID compatibility, strip .js from end\n            // of IDs. Have to do this here, and not in nameToUrl\n            // because node allows either .js or non .js to map\n            // to same file.\n            if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {\n                name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');\n            }\n\n            // Starts with a '.' so need the baseName\n            if (name[0].charAt(0) === '.' && baseParts) {\n                //Convert baseName to array, and lop off the last part,\n                //so that . matches that 'directory' and not name of the baseName's\n                //module. For instance, baseName of 'one/two/three', maps to\n                //'one/two/three.js', but we want the directory, 'one/two' for\n                //this normalization.\n                normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);\n                name = normalizedBaseParts.concat(name);\n            }\n\n            //start trimDots\n            for (i = 0; i < name.length; i++) {\n                part = name[i];\n                if (part === '.') {\n                    name.splice(i, 1);\n                    i -= 1;\n                } else if (part === '..') {\n                    // If at the start, or previous value is still ..,\n                    // keep them so that when converted to a path it may\n                    // still work when converted to a path, even though\n                    // as an ID it is less than ideal. In larger point\n                    // releases, may be better to just kick out an error.\n                    if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {\n                        continue;\n                    } else if (i > 0) {\n                        name.splice(i - 1, 2);\n                        i -= 2;\n                    }\n                }\n            }\n            //end trimDots\n\n            name = name.join('/');\n        }\n\n        //Apply map config if available.\n        if ((baseParts || starMap) && map) {\n            nameParts = name.split('/');\n\n            for (i = nameParts.length; i > 0; i -= 1) {\n                nameSegment = nameParts.slice(0, i).join(\"/\");\n\n                if (baseParts) {\n                    //Find the longest baseName segment match in the config.\n                    //So, do joins on the biggest to smallest lengths of baseParts.\n                    for (j = baseParts.length; j > 0; j -= 1) {\n                        mapValue = map[baseParts.slice(0, j).join('/')];\n\n                        //baseName segment has  config, find if it has one for\n                        //this name.\n                        if (mapValue) {\n                            mapValue = mapValue[nameSegment];\n                            if (mapValue) {\n                                //Match, update name to the new value.\n                                foundMap = mapValue;\n                                foundI = i;\n                                break;\n                            }\n                        }\n                    }\n                }\n\n                if (foundMap) {\n                    break;\n                }\n\n                //Check for a star map match, but just hold on to it,\n                //if there is a shorter segment match later in a matching\n                //config, then favor over this star map.\n                if (!foundStarMap && starMap && starMap[nameSegment]) {\n                    foundStarMap = starMap[nameSegment];\n                    starI = i;\n                }\n            }\n\n            if (!foundMap && foundStarMap) {\n                foundMap = foundStarMap;\n                foundI = starI;\n            }\n\n            if (foundMap) {\n                nameParts.splice(0, foundI, foundMap);\n                name = nameParts.join('/');\n            }\n        }\n\n        return name;\n    }\n\n    function makeRequire(relName, forceSync) {\n        return function () {\n            //A version of a require function that passes a moduleName\n            //value for items that may need to\n            //look up paths relative to the moduleName\n            var args = aps.call(arguments, 0);\n\n            //If first arg is not require('string'), and there is only\n            //one arg, it is the array form without a callback. Insert\n            //a null so that the following concat is correct.\n            if (typeof args[0] !== 'string' && args.length === 1) {\n                args.push(null);\n            }\n            return req.apply(undef, args.concat([relName, forceSync]));\n        };\n    }\n\n    function makeNormalize(relName) {\n        return function (name) {\n            return normalize(name, relName);\n        };\n    }\n\n    function makeLoad(depName) {\n        return function (value) {\n            defined[depName] = value;\n        };\n    }\n\n    function callDep(name) {\n        if (hasProp(waiting, name)) {\n            var args = waiting[name];\n            delete waiting[name];\n            defining[name] = true;\n            main.apply(undef, args);\n        }\n\n        if (!hasProp(defined, name) && !hasProp(defining, name)) {\n            throw new Error('No ' + name);\n        }\n        return defined[name];\n    }\n\n    //Turns a plugin!resource to [plugin, resource]\n    //with the plugin being undefined if the name\n    //did not have a plugin prefix.\n    function splitPrefix(name) {\n        var prefix,\n            index = name ? name.indexOf('!') : -1;\n        if (index > -1) {\n            prefix = name.substring(0, index);\n            name = name.substring(index + 1, name.length);\n        }\n        return [prefix, name];\n    }\n\n    //Creates a parts array for a relName where first part is plugin ID,\n    //second part is resource ID. Assumes relName has already been normalized.\n    function makeRelParts(relName) {\n        return relName ? splitPrefix(relName) : [];\n    }\n\n    /**\n     * Makes a name map, normalizing the name, and using a plugin\n     * for normalization if necessary. Grabs a ref to plugin\n     * too, as an optimization.\n     */\n    makeMap = function (name, relParts) {\n        var plugin,\n            parts = splitPrefix(name),\n            prefix = parts[0],\n            relResourceName = relParts[1];\n\n        name = parts[1];\n\n        if (prefix) {\n            prefix = normalize(prefix, relResourceName);\n            plugin = callDep(prefix);\n        }\n\n        //Normalize according\n        if (prefix) {\n            if (plugin && plugin.normalize) {\n                name = plugin.normalize(name, makeNormalize(relResourceName));\n            } else {\n                name = normalize(name, relResourceName);\n            }\n        } else {\n            name = normalize(name, relResourceName);\n            parts = splitPrefix(name);\n            prefix = parts[0];\n            name = parts[1];\n            if (prefix) {\n                plugin = callDep(prefix);\n            }\n        }\n\n        //Using ridiculous property names for space reasons\n        return {\n            f: prefix ? prefix + '!' + name : name, //fullName\n            n: name,\n            pr: prefix,\n            p: plugin\n        };\n    };\n\n    function makeConfig(name) {\n        return function () {\n            return (config && config.config && config.config[name]) || {};\n        };\n    }\n\n    handlers = {\n        require: function (name) {\n            return makeRequire(name);\n        },\n        exports: function (name) {\n            var e = defined[name];\n            if (typeof e !== 'undefined') {\n                return e;\n            } else {\n                return (defined[name] = {});\n            }\n        },\n        module: function (name) {\n            return {\n                id: name,\n                uri: '',\n                exports: defined[name],\n                config: makeConfig(name)\n            };\n        }\n    };\n\n    main = function (name, deps, callback, relName) {\n        var cjsModule, depName, ret, map, i, relParts,\n            args = [],\n            callbackType = typeof callback,\n            usingExports;\n\n        //Use name if no relName\n        relName = relName || name;\n        relParts = makeRelParts(relName);\n\n        //Call the callback to define the module, if necessary.\n        if (callbackType === 'undefined' || callbackType === 'function') {\n            //Pull out the defined dependencies and pass the ordered\n            //values to the callback.\n            //Default to [require, exports, module] if no deps\n            deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;\n            for (i = 0; i < deps.length; i += 1) {\n                map = makeMap(deps[i], relParts);\n                depName = map.f;\n\n                //Fast path CommonJS standard dependencies.\n                if (depName === \"require\") {\n                    args[i] = handlers.require(name);\n                } else if (depName === \"exports\") {\n                    //CommonJS module spec 1.1\n                    args[i] = handlers.exports(name);\n                    usingExports = true;\n                } else if (depName === \"module\") {\n                    //CommonJS module spec 1.1\n                    cjsModule = args[i] = handlers.module(name);\n                } else if (hasProp(defined, depName) ||\n                           hasProp(waiting, depName) ||\n                           hasProp(defining, depName)) {\n                    args[i] = callDep(depName);\n                } else if (map.p) {\n                    map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});\n                    args[i] = defined[depName];\n                } else {\n                    throw new Error(name + ' missing ' + depName);\n                }\n            }\n\n            ret = callback ? callback.apply(defined[name], args) : undefined;\n\n            if (name) {\n                //If setting exports via \"module\" is in play,\n                //favor that over return value and exports. After that,\n                //favor a non-undefined return value over exports use.\n                if (cjsModule && cjsModule.exports !== undef &&\n                        cjsModule.exports !== defined[name]) {\n                    defined[name] = cjsModule.exports;\n                } else if (ret !== undef || !usingExports) {\n                    //Use the return value from the function.\n                    defined[name] = ret;\n                }\n            }\n        } else if (name) {\n            //May just be an object definition for the module. Only\n            //worry about defining if have a module name.\n            defined[name] = callback;\n        }\n    };\n\n    requirejs = require = req = function (deps, callback, relName, forceSync, alt) {\n        if (typeof deps === \"string\") {\n            if (handlers[deps]) {\n                //callback in this case is really relName\n                return handlers[deps](callback);\n            }\n            //Just return the module wanted. In this scenario, the\n            //deps arg is the module name, and second arg (if passed)\n            //is just the relName.\n            //Normalize module name, if it contains . or ..\n            return callDep(makeMap(deps, makeRelParts(callback)).f);\n        } else if (!deps.splice) {\n            //deps is a config object, not an array.\n            config = deps;\n            if (config.deps) {\n                req(config.deps, config.callback);\n            }\n            if (!callback) {\n                return;\n            }\n\n            if (callback.splice) {\n                //callback is an array, which means it is a dependency list.\n                //Adjust args if there are dependencies\n                deps = callback;\n                callback = relName;\n                relName = null;\n            } else {\n                deps = undef;\n            }\n        }\n\n        //Support require(['a'])\n        callback = callback || function () {};\n\n        //If relName is a function, it is an errback handler,\n        //so remove it.\n        if (typeof relName === 'function') {\n            relName = forceSync;\n            forceSync = alt;\n        }\n\n        //Simulate async callback;\n        if (forceSync) {\n            main(undef, deps, callback, relName);\n        } else {\n            //Using a non-zero value because of concern for what old browsers\n            //do, and latest browsers \"upgrade\" to 4 if lower value is used:\n            //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:\n            //If want a value immediately, use require('id') instead -- something\n            //that works in almond on the global level, but not guaranteed and\n            //unlikely to work in other AMD implementations.\n            setTimeout(function () {\n                main(undef, deps, callback, relName);\n            }, 4);\n        }\n\n        return req;\n    };\n\n    /**\n     * Just drops the config on the floor, but returns req in case\n     * the config return value is used.\n     */\n    req.config = function (cfg) {\n        return req(cfg);\n    };\n\n    /**\n     * Expose module registry for debugging and tooling\n     */\n    requirejs._defined = defined;\n\n    define = function (name, deps, callback) {\n        if (typeof name !== 'string') {\n            throw new Error('See almond README: incorrect module build, no module name');\n        }\n\n        //This module may not have dependencies\n        if (!deps.splice) {\n            //deps is not an array, so probably means\n            //an object literal or factory function for\n            //the value. Adjust args.\n            callback = deps;\n            deps = [];\n        }\n\n        if (!hasProp(defined, name) && !hasProp(waiting, name)) {\n            waiting[name] = [name, deps, callback];\n        }\n    };\n\n    define.amd = {\n        jQuery: true\n    };\n}());\n\nS2.requirejs = requirejs;S2.require = require;S2.define = define;\n}\n}());\nS2.define(\"almond\", function(){});\n\n/* global jQuery:false, $:false */\nS2.define('jquery',[],function () {\n  var _$ = jQuery || $;\n\n  if (_$ == null && console && console.error) {\n    console.error(\n      'Select2: An instance of jQuery or a jQuery-compatible library was not ' +\n      'found. Make sure that you are including jQuery before Select2 on your ' +\n      'web page.'\n    );\n  }\n\n  return _$;\n});\n\nS2.define('select2/utils',[\n  'jquery'\n], function ($) {\n  var Utils = {};\n\n  Utils.Extend = function (ChildClass, SuperClass) {\n    var __hasProp = {}.hasOwnProperty;\n\n    function BaseConstructor () {\n      this.constructor = ChildClass;\n    }\n\n    for (var key in SuperClass) {\n      if (__hasProp.call(SuperClass, key)) {\n        ChildClass[key] = SuperClass[key];\n      }\n    }\n\n    BaseConstructor.prototype = SuperClass.prototype;\n    ChildClass.prototype = new BaseConstructor();\n    ChildClass.__super__ = SuperClass.prototype;\n\n    return ChildClass;\n  };\n\n  function getMethods (theClass) {\n    var proto = theClass.prototype;\n\n    var methods = [];\n\n    for (var methodName in proto) {\n      var m = proto[methodName];\n\n      if (typeof m !== 'function') {\n        continue;\n      }\n\n      if (methodName === 'constructor') {\n        continue;\n      }\n\n      methods.push(methodName);\n    }\n\n    return methods;\n  }\n\n  Utils.Decorate = function (SuperClass, DecoratorClass) {\n    var decoratedMethods = getMethods(DecoratorClass);\n    var superMethods = getMethods(SuperClass);\n\n    function DecoratedClass () {\n      var unshift = Array.prototype.unshift;\n\n      var argCount = DecoratorClass.prototype.constructor.length;\n\n      var calledConstructor = SuperClass.prototype.constructor;\n\n      if (argCount > 0) {\n        unshift.call(arguments, SuperClass.prototype.constructor);\n\n        calledConstructor = DecoratorClass.prototype.constructor;\n      }\n\n      calledConstructor.apply(this, arguments);\n    }\n\n    DecoratorClass.displayName = SuperClass.displayName;\n\n    function ctr () {\n      this.constructor = DecoratedClass;\n    }\n\n    DecoratedClass.prototype = new ctr();\n\n    for (var m = 0; m < superMethods.length; m++) {\n      var superMethod = superMethods[m];\n\n      DecoratedClass.prototype[superMethod] =\n        SuperClass.prototype[superMethod];\n    }\n\n    var calledMethod = function (methodName) {\n      // Stub out the original method if it's not decorating an actual method\n      var originalMethod = function () {};\n\n      if (methodName in DecoratedClass.prototype) {\n        originalMethod = DecoratedClass.prototype[methodName];\n      }\n\n      var decoratedMethod = DecoratorClass.prototype[methodName];\n\n      return function () {\n        var unshift = Array.prototype.unshift;\n\n        unshift.call(arguments, originalMethod);\n\n        return decoratedMethod.apply(this, arguments);\n      };\n    };\n\n    for (var d = 0; d < decoratedMethods.length; d++) {\n      var decoratedMethod = decoratedMethods[d];\n\n      DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);\n    }\n\n    return DecoratedClass;\n  };\n\n  var Observable = function () {\n    this.listeners = {};\n  };\n\n  Observable.prototype.on = function (event, callback) {\n    this.listeners = this.listeners || {};\n\n    if (event in this.listeners) {\n      this.listeners[event].push(callback);\n    } else {\n      this.listeners[event] = [callback];\n    }\n  };\n\n  Observable.prototype.trigger = function (event) {\n    var slice = Array.prototype.slice;\n    var params = slice.call(arguments, 1);\n\n    this.listeners = this.listeners || {};\n\n    // Params should always come in as an array\n    if (params == null) {\n      params = [];\n    }\n\n    // If there are no arguments to the event, use a temporary object\n    if (params.length === 0) {\n      params.push({});\n    }\n\n    // Set the `_type` of the first object to the event\n    params[0]._type = event;\n\n    if (event in this.listeners) {\n      this.invoke(this.listeners[event], slice.call(arguments, 1));\n    }\n\n    if ('*' in this.listeners) {\n      this.invoke(this.listeners['*'], arguments);\n    }\n  };\n\n  Observable.prototype.invoke = function (listeners, params) {\n    for (var i = 0, len = listeners.length; i < len; i++) {\n      listeners[i].apply(this, params);\n    }\n  };\n\n  Utils.Observable = Observable;\n\n  Utils.generateChars = function (length) {\n    var chars = '';\n\n    for (var i = 0; i < length; i++) {\n      var randomChar = Math.floor(Math.random() * 36);\n      chars += randomChar.toString(36);\n    }\n\n    return chars;\n  };\n\n  Utils.bind = function (func, context) {\n    return function () {\n      func.apply(context, arguments);\n    };\n  };\n\n  Utils._convertData = function (data) {\n    for (var originalKey in data) {\n      var keys = originalKey.split('-');\n\n      var dataLevel = data;\n\n      if (keys.length === 1) {\n        continue;\n      }\n\n      for (var k = 0; k < keys.length; k++) {\n        var key = keys[k];\n\n        // Lowercase the first letter\n        // By default, dash-separated becomes camelCase\n        key = key.substring(0, 1).toLowerCase() + key.substring(1);\n\n        if (!(key in dataLevel)) {\n          dataLevel[key] = {};\n        }\n\n        if (k == keys.length - 1) {\n          dataLevel[key] = data[originalKey];\n        }\n\n        dataLevel = dataLevel[key];\n      }\n\n      delete data[originalKey];\n    }\n\n    return data;\n  };\n\n  Utils.hasScroll = function (index, el) {\n    // Adapted from the function created by @ShadowScripter\n    // and adapted by @BillBarry on the Stack Exchange Code Review website.\n    // The original code can be found at\n    // http://codereview.stackexchange.com/q/13338\n    // and was designed to be used with the Sizzle selector engine.\n\n    var $el = $(el);\n    var overflowX = el.style.overflowX;\n    var overflowY = el.style.overflowY;\n\n    //Check both x and y declarations\n    if (overflowX === overflowY &&\n        (overflowY === 'hidden' || overflowY === 'visible')) {\n      return false;\n    }\n\n    if (overflowX === 'scroll' || overflowY === 'scroll') {\n      return true;\n    }\n\n    return ($el.innerHeight() < el.scrollHeight ||\n      $el.innerWidth() < el.scrollWidth);\n  };\n\n  Utils.escapeMarkup = function (markup) {\n    var replaceMap = {\n      '\\\\': '&#92;',\n      '&': '&amp;',\n      '<': '&lt;',\n      '>': '&gt;',\n      '\"': '&quot;',\n      '\\'': '&#39;',\n      '/': '&#47;'\n    };\n\n    // Do not try to escape the markup if it's not a string\n    if (typeof markup !== 'string') {\n      return markup;\n    }\n\n    return String(markup).replace(/[&<>\"'\\/\\\\]/g, function (match) {\n      return replaceMap[match];\n    });\n  };\n\n  // Append an array of jQuery nodes to a given element.\n  Utils.appendMany = function ($element, $nodes) {\n    // jQuery 1.7.x does not support $.fn.append() with an array\n    // Fall back to a jQuery object collection using $.fn.add()\n    if ($.fn.jquery.substr(0, 3) === '1.7') {\n      var $jqNodes = $();\n\n      $.map($nodes, function (node) {\n        $jqNodes = $jqNodes.add(node);\n      });\n\n      $nodes = $jqNodes;\n    }\n\n    $element.append($nodes);\n  };\n\n  // Cache objects in Utils.__cache instead of $.data (see #4346)\n  Utils.__cache = {};\n\n  var id = 0;\n  Utils.GetUniqueElementId = function (element) {\n    // Get a unique element Id. If element has no id,\n    // creates a new unique number, stores it in the id\n    // attribute and returns the new id.\n    // If an id already exists, it simply returns it.\n\n    var select2Id = element.getAttribute('data-select2-id');\n    if (select2Id == null) {\n      // If element has id, use it.\n      if (element.id) {\n        select2Id = element.id;\n        element.setAttribute('data-select2-id', select2Id);\n      } else {\n        element.setAttribute('data-select2-id', ++id);\n        select2Id = id.toString();\n      }\n    }\n    return select2Id;\n  };\n\n  Utils.StoreData = function (element, name, value) {\n    // Stores an item in the cache for a specified element.\n    // name is the cache key.\n    var id = Utils.GetUniqueElementId(element);\n    if (!Utils.__cache[id]) {\n      Utils.__cache[id] = {};\n    }\n\n    Utils.__cache[id][name] = value;\n  };\n\n  Utils.GetData = function (element, name) {\n    // Retrieves a value from the cache by its key (name)\n    // name is optional. If no name specified, return\n    // all cache items for the specified element.\n    // and for a specified element.\n    var id = Utils.GetUniqueElementId(element);\n    if (name) {\n      if (Utils.__cache[id]) {\n        if (Utils.__cache[id][name] != null) {\n          return Utils.__cache[id][name];\n        }\n        return $(element).data(name); // Fallback to HTML5 data attribs.\n      }\n      return $(element).data(name); // Fallback to HTML5 data attribs.\n    } else {\n      return Utils.__cache[id];\n    }\n  };\n\n  Utils.RemoveData = function (element) {\n    // Removes all cached items for a specified element.\n    var id = Utils.GetUniqueElementId(element);\n    if (Utils.__cache[id] != null) {\n      delete Utils.__cache[id];\n    }\n\n    element.removeAttribute('data-select2-id');\n  };\n\n  return Utils;\n});\n\nS2.define('select2/results',[\n  'jquery',\n  './utils'\n], function ($, Utils) {\n  function Results ($element, options, dataAdapter) {\n    this.$element = $element;\n    this.data = dataAdapter;\n    this.options = options;\n\n    Results.__super__.constructor.call(this);\n  }\n\n  Utils.Extend(Results, Utils.Observable);\n\n  Results.prototype.render = function () {\n    var $results = $(\n      '<ul class=\"select2-results__options\" role=\"listbox\"></ul>'\n    );\n\n    if (this.options.get('multiple')) {\n      $results.attr('aria-multiselectable', 'true');\n    }\n\n    this.$results = $results;\n\n    return $results;\n  };\n\n  Results.prototype.clear = function () {\n    this.$results.empty();\n  };\n\n  Results.prototype.displayMessage = function (params) {\n    var escapeMarkup = this.options.get('escapeMarkup');\n\n    this.clear();\n    this.hideLoading();\n\n    var $message = $(\n      '<li role=\"alert\" aria-live=\"assertive\"' +\n      ' class=\"select2-results__option\"></li>'\n    );\n\n    var message = this.options.get('translations').get(params.message);\n\n    $message.append(\n      escapeMarkup(\n        message(params.args)\n      )\n    );\n\n    $message[0].className += ' select2-results__message';\n\n    this.$results.append($message);\n  };\n\n  Results.prototype.hideMessages = function () {\n    this.$results.find('.select2-results__message').remove();\n  };\n\n  Results.prototype.append = function (data) {\n    this.hideLoading();\n\n    var $options = [];\n\n    if (data.results == null || data.results.length === 0) {\n      if (this.$results.children().length === 0) {\n        this.trigger('results:message', {\n          message: 'noResults'\n        });\n      }\n\n      return;\n    }\n\n    data.results = this.sort(data.results);\n\n    for (var d = 0; d < data.results.length; d++) {\n      var item = data.results[d];\n\n      var $option = this.option(item);\n\n      $options.push($option);\n    }\n\n    this.$results.append($options);\n  };\n\n  Results.prototype.position = function ($results, $dropdown) {\n    var $resultsContainer = $dropdown.find('.select2-results');\n    $resultsContainer.append($results);\n  };\n\n  Results.prototype.sort = function (data) {\n    var sorter = this.options.get('sorter');\n\n    return sorter(data);\n  };\n\n  Results.prototype.highlightFirstItem = function () {\n    var $options = this.$results\n      .find('.select2-results__option[aria-selected]');\n\n    var $selected = $options.filter('[aria-selected=true]');\n\n    // Check if there are any selected options\n    if ($selected.length > 0) {\n      // If there are selected options, highlight the first\n      $selected.first().trigger('mouseenter');\n    } else {\n      // If there are no selected options, highlight the first option\n      // in the dropdown\n      $options.first().trigger('mouseenter');\n    }\n\n    this.ensureHighlightVisible();\n  };\n\n  Results.prototype.setClasses = function () {\n    var self = this;\n\n    this.data.current(function (selected) {\n      var selectedIds = $.map(selected, function (s) {\n        return s.id.toString();\n      });\n\n      var $options = self.$results\n        .find('.select2-results__option[aria-selected]');\n\n      $options.each(function () {\n        var $option = $(this);\n\n        var item = Utils.GetData(this, 'data');\n\n        // id needs to be converted to a string when comparing\n        var id = '' + item.id;\n\n        if ((item.element != null && item.element.selected) ||\n            (item.element == null && $.inArray(id, selectedIds) > -1)) {\n          $option.attr('aria-selected', 'true');\n        } else {\n          $option.attr('aria-selected', 'false');\n        }\n      });\n\n    });\n  };\n\n  Results.prototype.showLoading = function (params) {\n    this.hideLoading();\n\n    var loadingMore = this.options.get('translations').get('searching');\n\n    var loading = {\n      disabled: true,\n      loading: true,\n      text: loadingMore(params)\n    };\n    var $loading = this.option(loading);\n    $loading.className += ' loading-results';\n\n    this.$results.prepend($loading);\n  };\n\n  Results.prototype.hideLoading = function () {\n    this.$results.find('.loading-results').remove();\n  };\n\n  Results.prototype.option = function (data) {\n    var option = document.createElement('li');\n    option.className = 'select2-results__option';\n\n    var attrs = {\n      'role': 'option',\n      'aria-selected': 'false'\n    };\n\n    var matches = window.Element.prototype.matches ||\n      window.Element.prototype.msMatchesSelector ||\n      window.Element.prototype.webkitMatchesSelector;\n\n    if ((data.element != null && matches.call(data.element, ':disabled')) ||\n        (data.element == null && data.disabled)) {\n      delete attrs['aria-selected'];\n      attrs['aria-disabled'] = 'true';\n    }\n\n    if (data.id == null) {\n      delete attrs['aria-selected'];\n    }\n\n    if (data._resultId != null) {\n      option.id = data._resultId;\n    }\n\n    if (data.title) {\n      option.title = data.title;\n    }\n\n    if (data.children) {\n      attrs.role = 'group';\n      attrs['aria-label'] = data.text;\n      delete attrs['aria-selected'];\n    }\n\n    for (var attr in attrs) {\n      var val = attrs[attr];\n\n      option.setAttribute(attr, val);\n    }\n\n    if (data.children) {\n      var $option = $(option);\n\n      var label = document.createElement('strong');\n      label.className = 'select2-results__group';\n\n      var $label = $(label);\n      this.template(data, label);\n\n      var $children = [];\n\n      for (var c = 0; c < data.children.length; c++) {\n        var child = data.children[c];\n\n        var $child = this.option(child);\n\n        $children.push($child);\n      }\n\n      var $childrenContainer = $('<ul></ul>', {\n        'class': 'select2-results__options select2-results__options--nested'\n      });\n\n      $childrenContainer.append($children);\n\n      $option.append(label);\n      $option.append($childrenContainer);\n    } else {\n      this.template(data, option);\n    }\n\n    Utils.StoreData(option, 'data', data);\n\n    return option;\n  };\n\n  Results.prototype.bind = function (container, $container) {\n    var self = this;\n\n    var id = container.id + '-results';\n\n    this.$results.attr('id', id);\n\n    container.on('results:all', function (params) {\n      self.clear();\n      self.append(params.data);\n\n      if (container.isOpen()) {\n        self.setClasses();\n        self.highlightFirstItem();\n      }\n    });\n\n    container.on('results:append', function (params) {\n      self.append(params.data);\n\n      if (container.isOpen()) {\n        self.setClasses();\n      }\n    });\n\n    container.on('query', function (params) {\n      self.hideMessages();\n      self.showLoading(params);\n    });\n\n    container.on('select', function () {\n      if (!container.isOpen()) {\n        return;\n      }\n\n      self.setClasses();\n\n      if (self.options.get('scrollAfterSelect')) {\n        self.highlightFirstItem();\n      }\n    });\n\n    container.on('unselect', function () {\n      if (!container.isOpen()) {\n        return;\n      }\n\n      self.setClasses();\n\n      if (self.options.get('scrollAfterSelect')) {\n        self.highlightFirstItem();\n      }\n    });\n\n    container.on('open', function () {\n      // When the dropdown is open, aria-expended=\"true\"\n      self.$results.attr('aria-expanded', 'true');\n      self.$results.attr('aria-hidden', 'false');\n\n      self.setClasses();\n      self.ensureHighlightVisible();\n    });\n\n    container.on('close', function () {\n      // When the dropdown is closed, aria-expended=\"false\"\n      self.$results.attr('aria-expanded', 'false');\n      self.$results.attr('aria-hidden', 'true');\n      self.$results.removeAttr('aria-activedescendant');\n    });\n\n    container.on('results:toggle', function () {\n      var $highlighted = self.getHighlightedResults();\n\n      if ($highlighted.length === 0) {\n        return;\n      }\n\n      $highlighted.trigger('mouseup');\n    });\n\n    container.on('results:select', function () {\n      var $highlighted = self.getHighlightedResults();\n\n      if ($highlighted.length === 0) {\n        return;\n      }\n\n      var data = Utils.GetData($highlighted[0], 'data');\n\n      if ($highlighted.attr('aria-selected') == 'true') {\n        self.trigger('close', {});\n      } else {\n        self.trigger('select', {\n          data: data\n        });\n      }\n    });\n\n    container.on('results:previous', function () {\n      var $highlighted = self.getHighlightedResults();\n\n      var $options = self.$results.find('[aria-selected]');\n\n      var currentIndex = $options.index($highlighted);\n\n      // If we are already at the top, don't move further\n      // If no options, currentIndex will be -1\n      if (currentIndex <= 0) {\n        return;\n      }\n\n      var nextIndex = currentIndex - 1;\n\n      // If none are highlighted, highlight the first\n      if ($highlighted.length === 0) {\n        nextIndex = 0;\n      }\n\n      var $next = $options.eq(nextIndex);\n\n      $next.trigger('mouseenter');\n\n      var currentOffset = self.$results.offset().top;\n      var nextTop = $next.offset().top;\n      var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);\n\n      if (nextIndex === 0) {\n        self.$results.scrollTop(0);\n      } else if (nextTop - currentOffset < 0) {\n        self.$results.scrollTop(nextOffset);\n      }\n    });\n\n    container.on('results:next', function () {\n      var $highlighted = self.getHighlightedResults();\n\n      var $options = self.$results.find('[aria-selected]');\n\n      var currentIndex = $options.index($highlighted);\n\n      var nextIndex = currentIndex + 1;\n\n      // If we are at the last option, stay there\n      if (nextIndex >= $options.length) {\n        return;\n      }\n\n      var $next = $options.eq(nextIndex);\n\n      $next.trigger('mouseenter');\n\n      var currentOffset = self.$results.offset().top +\n        self.$results.outerHeight(false);\n      var nextBottom = $next.offset().top + $next.outerHeight(false);\n      var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;\n\n      if (nextIndex === 0) {\n        self.$results.scrollTop(0);\n      } else if (nextBottom > currentOffset) {\n        self.$results.scrollTop(nextOffset);\n      }\n    });\n\n    container.on('results:focus', function (params) {\n      params.element.addClass('select2-results__option--highlighted');\n    });\n\n    container.on('results:message', function (params) {\n      self.displayMessage(params);\n    });\n\n    if ($.fn.mousewheel) {\n      this.$results.on('mousewheel', function (e) {\n        var top = self.$results.scrollTop();\n\n        var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;\n\n        var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;\n        var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();\n\n        if (isAtTop) {\n          self.$results.scrollTop(0);\n\n          e.preventDefault();\n          e.stopPropagation();\n        } else if (isAtBottom) {\n          self.$results.scrollTop(\n            self.$results.get(0).scrollHeight - self.$results.height()\n          );\n\n          e.preventDefault();\n          e.stopPropagation();\n        }\n      });\n    }\n\n    this.$results.on('mouseup', '.select2-results__option[aria-selected]',\n      function (evt) {\n      var $this = $(this);\n\n      var data = Utils.GetData(this, 'data');\n\n      if ($this.attr('aria-selected') === 'true') {\n        if (self.options.get('multiple')) {\n          self.trigger('unselect', {\n            originalEvent: evt,\n            data: data\n          });\n        } else {\n          self.trigger('close', {});\n        }\n\n        return;\n      }\n\n      self.trigger('select', {\n        originalEvent: evt,\n        data: data\n      });\n    });\n\n    this.$results.on('mouseenter', '.select2-results__option[aria-selected]',\n      function (evt) {\n      var data = Utils.GetData(this, 'data');\n\n      self.getHighlightedResults()\n          .removeClass('select2-results__option--highlighted');\n\n      self.trigger('results:focus', {\n        data: data,\n        element: $(this)\n      });\n    });\n  };\n\n  Results.prototype.getHighlightedResults = function () {\n    var $highlighted = this.$results\n    .find('.select2-results__option--highlighted');\n\n    return $highlighted;\n  };\n\n  Results.prototype.destroy = function () {\n    this.$results.remove();\n  };\n\n  Results.prototype.ensureHighlightVisible = function () {\n    var $highlighted = this.getHighlightedResults();\n\n    if ($highlighted.length === 0) {\n      return;\n    }\n\n    var $options = this.$results.find('[aria-selected]');\n\n    var currentIndex = $options.index($highlighted);\n\n    var currentOffset = this.$results.offset().top;\n    var nextTop = $highlighted.offset().top;\n    var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);\n\n    var offsetDelta = nextTop - currentOffset;\n    nextOffset -= $highlighted.outerHeight(false) * 2;\n\n    if (currentIndex <= 2) {\n      this.$results.scrollTop(0);\n    } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {\n      this.$results.scrollTop(nextOffset);\n    }\n  };\n\n  Results.prototype.template = function (result, container) {\n    var template = this.options.get('templateResult');\n    var escapeMarkup = this.options.get('escapeMarkup');\n\n    var content = template(result, container);\n\n    if (content == null) {\n      container.style.display = 'none';\n    } else if (typeof content === 'string') {\n      container.innerHTML = escapeMarkup(content);\n    } else {\n      $(container).append(content);\n    }\n  };\n\n  return Results;\n});\n\nS2.define('select2/keys',[\n\n], function () {\n  var KEYS = {\n    BACKSPACE: 8,\n    TAB: 9,\n    ENTER: 13,\n    SHIFT: 16,\n    CTRL: 17,\n    ALT: 18,\n    ESC: 27,\n    SPACE: 32,\n    PAGE_UP: 33,\n    PAGE_DOWN: 34,\n    END: 35,\n    HOME: 36,\n    LEFT: 37,\n    UP: 38,\n    RIGHT: 39,\n    DOWN: 40,\n    DELETE: 46\n  };\n\n  return KEYS;\n});\n\nS2.define('select2/selection/base',[\n  'jquery',\n  '../utils',\n  '../keys'\n], function ($, Utils, KEYS) {\n  function BaseSelection ($element, options) {\n    this.$element = $element;\n    this.options = options;\n\n    BaseSelection.__super__.constructor.call(this);\n  }\n\n  Utils.Extend(BaseSelection, Utils.Observable);\n\n  BaseSelection.prototype.render = function () {\n    var $selection = $(\n      '<span class=\"select2-selection\" role=\"combobox\" ' +\n      ' aria-haspopup=\"true\" aria-expanded=\"false\">' +\n      '</span>'\n    );\n\n    this._tabindex = 0;\n\n    if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {\n      this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');\n    } else if (this.$element.attr('tabindex') != null) {\n      this._tabindex = this.$element.attr('tabindex');\n    }\n\n    $selection.attr('title', this.$element.attr('title'));\n    $selection.attr('tabindex', this._tabindex);\n    $selection.attr('aria-disabled', 'false');\n\n    this.$selection = $selection;\n\n    return $selection;\n  };\n\n  BaseSelection.prototype.bind = function (container, $container) {\n    var self = this;\n\n    var resultsId = container.id + '-results';\n\n    this.container = container;\n\n    this.$selection.on('focus', function (evt) {\n      self.trigger('focus', evt);\n    });\n\n    this.$selection.on('blur', function (evt) {\n      self._handleBlur(evt);\n    });\n\n    this.$selection.on('keydown', function (evt) {\n      self.trigger('keypress', evt);\n\n      if (evt.which === KEYS.SPACE) {\n        evt.preventDefault();\n      }\n    });\n\n    container.on('results:focus', function (params) {\n      self.$selection.attr('aria-activedescendant', params.data._resultId);\n    });\n\n    container.on('selection:update', function (params) {\n      self.update(params.data);\n    });\n\n    container.on('open', function () {\n      // When the dropdown is open, aria-expanded=\"true\"\n      self.$selection.attr('aria-expanded', 'true');\n      self.$selection.attr('aria-owns', resultsId);\n\n      self._attachCloseHandler(container);\n    });\n\n    container.on('close', function () {\n      // When the dropdown is closed, aria-expanded=\"false\"\n      self.$selection.attr('aria-expanded', 'false');\n      self.$selection.removeAttr('aria-activedescendant');\n      self.$selection.removeAttr('aria-owns');\n\n      self.$selection.trigger('focus');\n\n      self._detachCloseHandler(container);\n    });\n\n    container.on('enable', function () {\n      self.$selection.attr('tabindex', self._tabindex);\n      self.$selection.attr('aria-disabled', 'false');\n    });\n\n    container.on('disable', function () {\n      self.$selection.attr('tabindex', '-1');\n      self.$selection.attr('aria-disabled', 'true');\n    });\n  };\n\n  BaseSelection.prototype._handleBlur = function (evt) {\n    var self = this;\n\n    // This needs to be delayed as the active element is the body when the tab\n    // key is pressed, possibly along with others.\n    window.setTimeout(function () {\n      // Don't trigger `blur` if the focus is still in the selection\n      if (\n        (document.activeElement == self.$selection[0]) ||\n        ($.contains(self.$selection[0], document.activeElement))\n      ) {\n        return;\n      }\n\n      self.trigger('blur', evt);\n    }, 1);\n  };\n\n  BaseSelection.prototype._attachCloseHandler = function (container) {\n\n    $(document.body).on('mousedown.select2.' + container.id, function (e) {\n      var $target = $(e.target);\n\n      var $select = $target.closest('.select2');\n\n      var $all = $('.select2.select2-container--open');\n\n      $all.each(function () {\n        if (this == $select[0]) {\n          return;\n        }\n\n        var $element = Utils.GetData(this, 'element');\n\n        $element.select2('close');\n      });\n    });\n  };\n\n  BaseSelection.prototype._detachCloseHandler = function (container) {\n    $(document.body).off('mousedown.select2.' + container.id);\n  };\n\n  BaseSelection.prototype.position = function ($selection, $container) {\n    var $selectionContainer = $container.find('.selection');\n    $selectionContainer.append($selection);\n  };\n\n  BaseSelection.prototype.destroy = function () {\n    this._detachCloseHandler(this.container);\n  };\n\n  BaseSelection.prototype.update = function (data) {\n    throw new Error('The `update` method must be defined in child classes.');\n  };\n\n  /**\n   * Helper method to abstract the \"enabled\" (not \"disabled\") state of this\n   * object.\n   *\n   * @return {true} if the instance is not disabled.\n   * @return {false} if the instance is disabled.\n   */\n  BaseSelection.prototype.isEnabled = function () {\n    return !this.isDisabled();\n  };\n\n  /**\n   * Helper method to abstract the \"disabled\" state of this object.\n   *\n   * @return {true} if the disabled option is true.\n   * @return {false} if the disabled option is false.\n   */\n  BaseSelection.prototype.isDisabled = function () {\n    return this.options.get('disabled');\n  };\n\n  return BaseSelection;\n});\n\nS2.define('select2/selection/single',[\n  'jquery',\n  './base',\n  '../utils',\n  '../keys'\n], function ($, BaseSelection, Utils, KEYS) {\n  function SingleSelection () {\n    SingleSelection.__super__.constructor.apply(this, arguments);\n  }\n\n  Utils.Extend(SingleSelection, BaseSelection);\n\n  SingleSelection.prototype.render = function () {\n    var $selection = SingleSelection.__super__.render.call(this);\n\n    $selection.addClass('select2-selection--single');\n\n    $selection.html(\n      '<span class=\"select2-selection__rendered\"></span>' +\n      '<span class=\"select2-selection__arrow\" role=\"presentation\">' +\n        '<b role=\"presentation\"></b>' +\n      '</span>'\n    );\n\n    return $selection;\n  };\n\n  SingleSelection.prototype.bind = function (container, $container) {\n    var self = this;\n\n    SingleSelection.__super__.bind.apply(this, arguments);\n\n    var id = container.id + '-container';\n\n    this.$selection.find('.select2-selection__rendered')\n      .attr('id', id)\n      .attr('role', 'textbox')\n      .attr('aria-readonly', 'true');\n    this.$selection.attr('aria-labelledby', id);\n\n    this.$selection.on('mousedown', function (evt) {\n      // Only respond to left clicks\n      if (evt.which !== 1) {\n        return;\n      }\n\n      self.trigger('toggle', {\n        originalEvent: evt\n      });\n    });\n\n    this.$selection.on('focus', function (evt) {\n      // User focuses on the container\n    });\n\n    this.$selection.on('blur', function (evt) {\n      // User exits the container\n    });\n\n    container.on('focus', function (evt) {\n      if (!container.isOpen()) {\n        self.$selection.trigger('focus');\n      }\n    });\n  };\n\n  SingleSelection.prototype.clear = function () {\n    var $rendered = this.$selection.find('.select2-selection__rendered');\n    $rendered.empty();\n    $rendered.removeAttr('title'); // clear tooltip on empty\n  };\n\n  SingleSelection.prototype.display = function (data, container) {\n    var template = this.options.get('templateSelection');\n    var escapeMarkup = this.options.get('escapeMarkup');\n\n    return escapeMarkup(template(data, container));\n  };\n\n  SingleSelection.prototype.selectionContainer = function () {\n    return $('<span></span>');\n  };\n\n  SingleSelection.prototype.update = function (data) {\n    if (data.length === 0) {\n      this.clear();\n      return;\n    }\n\n    var selection = data[0];\n\n    var $rendered = this.$selection.find('.select2-selection__rendered');\n    var formatted = this.display(selection, $rendered);\n\n    $rendered.empty().append(formatted);\n\n    var title = selection.title || selection.text;\n\n    if (title) {\n      $rendered.attr('title', title);\n    } else {\n      $rendered.removeAttr('title');\n    }\n  };\n\n  return SingleSelection;\n});\n\nS2.define('select2/selection/multiple',[\n  'jquery',\n  './base',\n  '../utils'\n], function ($, BaseSelection, Utils) {\n  function MultipleSelection ($element, options) {\n    MultipleSelection.__super__.constructor.apply(this, arguments);\n  }\n\n  Utils.Extend(MultipleSelection, BaseSelection);\n\n  MultipleSelection.prototype.render = function () {\n    var $selection = MultipleSelection.__super__.render.call(this);\n\n    $selection.addClass('select2-selection--multiple');\n\n    $selection.html(\n      '<ul class=\"select2-selection__rendered\"></ul>'\n    );\n\n    return $selection;\n  };\n\n  MultipleSelection.prototype.bind = function (container, $container) {\n    var self = this;\n\n    MultipleSelection.__super__.bind.apply(this, arguments);\n\n    this.$selection.on('click', function (evt) {\n      self.trigger('toggle', {\n        originalEvent: evt\n      });\n    });\n\n    this.$selection.on(\n      'click',\n      '.select2-selection__choice__remove',\n      function (evt) {\n        // Ignore the event if it is disabled\n        if (self.isDisabled()) {\n          return;\n        }\n\n        var $remove = $(this);\n        var $selection = $remove.parent();\n\n        var data = Utils.GetData($selection[0], 'data');\n\n        self.trigger('unselect', {\n          originalEvent: evt,\n          data: data\n        });\n      }\n    );\n  };\n\n  MultipleSelection.prototype.clear = function () {\n    var $rendered = this.$selection.find('.select2-selection__rendered');\n    $rendered.empty();\n    $rendered.removeAttr('title');\n  };\n\n  MultipleSelection.prototype.display = function (data, container) {\n    var template = this.options.get('templateSelection');\n    var escapeMarkup = this.options.get('escapeMarkup');\n\n    return escapeMarkup(template(data, container));\n  };\n\n  MultipleSelection.prototype.selectionContainer = function () {\n    var $container = $(\n      '<li class=\"select2-selection__choice\">' +\n        '<span class=\"select2-selection__choice__remove\" role=\"presentation\">' +\n          '&times;' +\n        '</span>' +\n      '</li>'\n    );\n\n    return $container;\n  };\n\n  MultipleSelection.prototype.update = function (data) {\n    this.clear();\n\n    if (data.length === 0) {\n      return;\n    }\n\n    var $selections = [];\n\n    for (var d = 0; d < data.length; d++) {\n      var selection = data[d];\n\n      var $selection = this.selectionContainer();\n      var formatted = this.display(selection, $selection);\n\n      $selection.append(formatted);\n\n      var title = selection.title || selection.text;\n\n      if (title) {\n        $selection.attr('title', title);\n      }\n\n      Utils.StoreData($selection[0], 'data', selection);\n\n      $selections.push($selection);\n    }\n\n    var $rendered = this.$selection.find('.select2-selection__rendered');\n\n    Utils.appendMany($rendered, $selections);\n  };\n\n  return MultipleSelection;\n});\n\nS2.define('select2/selection/placeholder',[\n  '../utils'\n], function (Utils) {\n  function Placeholder (decorated, $element, options) {\n    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));\n\n    decorated.call(this, $element, options);\n  }\n\n  Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {\n    if (typeof placeholder === 'string') {\n      placeholder = {\n        id: '',\n        text: placeholder\n      };\n    }\n\n    return placeholder;\n  };\n\n  Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {\n    var $placeholder = this.selectionContainer();\n\n    $placeholder.html(this.display(placeholder));\n    $placeholder.addClass('select2-selection__placeholder')\n                .removeClass('select2-selection__choice');\n\n    return $placeholder;\n  };\n\n  Placeholder.prototype.update = function (decorated, data) {\n    var singlePlaceholder = (\n      data.length == 1 && data[0].id != this.placeholder.id\n    );\n    var multipleSelections = data.length > 1;\n\n    if (multipleSelections || singlePlaceholder) {\n      return decorated.call(this, data);\n    }\n\n    this.clear();\n\n    var $placeholder = this.createPlaceholder(this.placeholder);\n\n    this.$selection.find('.select2-selection__rendered').append($placeholder);\n  };\n\n  return Placeholder;\n});\n\nS2.define('select2/selection/allowClear',[\n  'jquery',\n  '../keys',\n  '../utils'\n], function ($, KEYS, Utils) {\n  function AllowClear () { }\n\n  AllowClear.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n\n    decorated.call(this, container, $container);\n\n    if (this.placeholder == null) {\n      if (this.options.get('debug') && window.console && console.error) {\n        console.error(\n          'Select2: The `allowClear` option should be used in combination ' +\n          'with the `placeholder` option.'\n        );\n      }\n    }\n\n    this.$selection.on('mousedown', '.select2-selection__clear',\n      function (evt) {\n        self._handleClear(evt);\n    });\n\n    container.on('keypress', function (evt) {\n      self._handleKeyboardClear(evt, container);\n    });\n  };\n\n  AllowClear.prototype._handleClear = function (_, evt) {\n    // Ignore the event if it is disabled\n    if (this.isDisabled()) {\n      return;\n    }\n\n    var $clear = this.$selection.find('.select2-selection__clear');\n\n    // Ignore the event if nothing has been selected\n    if ($clear.length === 0) {\n      return;\n    }\n\n    evt.stopPropagation();\n\n    var data = Utils.GetData($clear[0], 'data');\n\n    var previousVal = this.$element.val();\n    this.$element.val(this.placeholder.id);\n\n    var unselectData = {\n      data: data\n    };\n    this.trigger('clear', unselectData);\n    if (unselectData.prevented) {\n      this.$element.val(previousVal);\n      return;\n    }\n\n    for (var d = 0; d < data.length; d++) {\n      unselectData = {\n        data: data[d]\n      };\n\n      // Trigger the `unselect` event, so people can prevent it from being\n      // cleared.\n      this.trigger('unselect', unselectData);\n\n      // If the event was prevented, don't clear it out.\n      if (unselectData.prevented) {\n        this.$element.val(previousVal);\n        return;\n      }\n    }\n\n    this.$element.trigger('input').trigger('change');\n\n    this.trigger('toggle', {});\n  };\n\n  AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {\n    if (container.isOpen()) {\n      return;\n    }\n\n    if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {\n      this._handleClear(evt);\n    }\n  };\n\n  AllowClear.prototype.update = function (decorated, data) {\n    decorated.call(this, data);\n\n    if (this.$selection.find('.select2-selection__placeholder').length > 0 ||\n        data.length === 0) {\n      return;\n    }\n\n    var removeAll = this.options.get('translations').get('removeAllItems');\n\n    var $remove = $(\n      '<span class=\"select2-selection__clear\" title=\"' + removeAll() +'\">' +\n        '&times;' +\n      '</span>'\n    );\n    Utils.StoreData($remove[0], 'data', data);\n\n    this.$selection.find('.select2-selection__rendered').prepend($remove);\n  };\n\n  return AllowClear;\n});\n\nS2.define('select2/selection/search',[\n  'jquery',\n  '../utils',\n  '../keys'\n], function ($, Utils, KEYS) {\n  function Search (decorated, $element, options) {\n    decorated.call(this, $element, options);\n  }\n\n  Search.prototype.render = function (decorated) {\n    var $search = $(\n      '<li class=\"select2-search select2-search--inline\">' +\n        '<input class=\"select2-search__field\" type=\"search\" tabindex=\"-1\"' +\n        ' autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"none\"' +\n        ' spellcheck=\"false\" role=\"searchbox\" aria-autocomplete=\"list\" />' +\n      '</li>'\n    );\n\n    this.$searchContainer = $search;\n    this.$search = $search.find('input');\n\n    var $rendered = decorated.call(this);\n\n    this._transferTabIndex();\n\n    return $rendered;\n  };\n\n  Search.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n\n    var resultsId = container.id + '-results';\n\n    decorated.call(this, container, $container);\n\n    container.on('open', function () {\n      self.$search.attr('aria-controls', resultsId);\n      self.$search.trigger('focus');\n    });\n\n    container.on('close', function () {\n      self.$search.val('');\n      self.$search.removeAttr('aria-controls');\n      self.$search.removeAttr('aria-activedescendant');\n      self.$search.trigger('focus');\n    });\n\n    container.on('enable', function () {\n      self.$search.prop('disabled', false);\n\n      self._transferTabIndex();\n    });\n\n    container.on('disable', function () {\n      self.$search.prop('disabled', true);\n    });\n\n    container.on('focus', function (evt) {\n      self.$search.trigger('focus');\n    });\n\n    container.on('results:focus', function (params) {\n      if (params.data._resultId) {\n        self.$search.attr('aria-activedescendant', params.data._resultId);\n      } else {\n        self.$search.removeAttr('aria-activedescendant');\n      }\n    });\n\n    this.$selection.on('focusin', '.select2-search--inline', function (evt) {\n      self.trigger('focus', evt);\n    });\n\n    this.$selection.on('focusout', '.select2-search--inline', function (evt) {\n      self._handleBlur(evt);\n    });\n\n    this.$selection.on('keydown', '.select2-search--inline', function (evt) {\n      evt.stopPropagation();\n\n      self.trigger('keypress', evt);\n\n      self._keyUpPrevented = evt.isDefaultPrevented();\n\n      var key = evt.which;\n\n      if (key === KEYS.BACKSPACE && self.$search.val() === '') {\n        var $previousChoice = self.$searchContainer\n          .prev('.select2-selection__choice');\n\n        if ($previousChoice.length > 0) {\n          var item = Utils.GetData($previousChoice[0], 'data');\n\n          self.searchRemoveChoice(item);\n\n          evt.preventDefault();\n        }\n      }\n    });\n\n    this.$selection.on('click', '.select2-search--inline', function (evt) {\n      if (self.$search.val()) {\n        evt.stopPropagation();\n      }\n    });\n\n    // Try to detect the IE version should the `documentMode` property that\n    // is stored on the document. This is only implemented in IE and is\n    // slightly cleaner than doing a user agent check.\n    // This property is not available in Edge, but Edge also doesn't have\n    // this bug.\n    var msie = document.documentMode;\n    var disableInputEvents = msie && msie <= 11;\n\n    // Workaround for browsers which do not support the `input` event\n    // This will prevent double-triggering of events for browsers which support\n    // both the `keyup` and `input` events.\n    this.$selection.on(\n      'input.searchcheck',\n      '.select2-search--inline',\n      function (evt) {\n        // IE will trigger the `input` event when a placeholder is used on a\n        // search box. To get around this issue, we are forced to ignore all\n        // `input` events in IE and keep using `keyup`.\n        if (disableInputEvents) {\n          self.$selection.off('input.search input.searchcheck');\n          return;\n        }\n\n        // Unbind the duplicated `keyup` event\n        self.$selection.off('keyup.search');\n      }\n    );\n\n    this.$selection.on(\n      'keyup.search input.search',\n      '.select2-search--inline',\n      function (evt) {\n        // IE will trigger the `input` event when a placeholder is used on a\n        // search box. To get around this issue, we are forced to ignore all\n        // `input` events in IE and keep using `keyup`.\n        if (disableInputEvents && evt.type === 'input') {\n          self.$selection.off('input.search input.searchcheck');\n          return;\n        }\n\n        var key = evt.which;\n\n        // We can freely ignore events from modifier keys\n        if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {\n          return;\n        }\n\n        // Tabbing will be handled during the `keydown` phase\n        if (key == KEYS.TAB) {\n          return;\n        }\n\n        self.handleSearch(evt);\n      }\n    );\n  };\n\n  /**\n   * This method will transfer the tabindex attribute from the rendered\n   * selection to the search box. This allows for the search box to be used as\n   * the primary focus instead of the selection container.\n   *\n   * @private\n   */\n  Search.prototype._transferTabIndex = function (decorated) {\n    this.$search.attr('tabindex', this.$selection.attr('tabindex'));\n    this.$selection.attr('tabindex', '-1');\n  };\n\n  Search.prototype.createPlaceholder = function (decorated, placeholder) {\n    this.$search.attr('placeholder', placeholder.text);\n  };\n\n  Search.prototype.update = function (decorated, data) {\n    var searchHadFocus = this.$search[0] == document.activeElement;\n\n    this.$search.attr('placeholder', '');\n\n    decorated.call(this, data);\n\n    this.$selection.find('.select2-selection__rendered')\n                   .append(this.$searchContainer);\n\n    this.resizeSearch();\n    if (searchHadFocus) {\n      this.$search.trigger('focus');\n    }\n  };\n\n  Search.prototype.handleSearch = function () {\n    this.resizeSearch();\n\n    if (!this._keyUpPrevented) {\n      var input = this.$search.val();\n\n      this.trigger('query', {\n        term: input\n      });\n    }\n\n    this._keyUpPrevented = false;\n  };\n\n  Search.prototype.searchRemoveChoice = function (decorated, item) {\n    this.trigger('unselect', {\n      data: item\n    });\n\n    this.$search.val(item.text);\n    this.handleSearch();\n  };\n\n  Search.prototype.resizeSearch = function () {\n    this.$search.css('width', '25px');\n\n    var width = '';\n\n    if (this.$search.attr('placeholder') !== '') {\n      width = this.$selection.find('.select2-selection__rendered').width();\n    } else {\n      var minimumWidth = this.$search.val().length + 1;\n\n      width = (minimumWidth * 0.75) + 'em';\n    }\n\n    this.$search.css('width', width);\n  };\n\n  return Search;\n});\n\nS2.define('select2/selection/eventRelay',[\n  'jquery'\n], function ($) {\n  function EventRelay () { }\n\n  EventRelay.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n    var relayEvents = [\n      'open', 'opening',\n      'close', 'closing',\n      'select', 'selecting',\n      'unselect', 'unselecting',\n      'clear', 'clearing'\n    ];\n\n    var preventableEvents = [\n      'opening', 'closing', 'selecting', 'unselecting', 'clearing'\n    ];\n\n    decorated.call(this, container, $container);\n\n    container.on('*', function (name, params) {\n      // Ignore events that should not be relayed\n      if ($.inArray(name, relayEvents) === -1) {\n        return;\n      }\n\n      // The parameters should always be an object\n      params = params || {};\n\n      // Generate the jQuery event for the Select2 event\n      var evt = $.Event('select2:' + name, {\n        params: params\n      });\n\n      self.$element.trigger(evt);\n\n      // Only handle preventable events if it was one\n      if ($.inArray(name, preventableEvents) === -1) {\n        return;\n      }\n\n      params.prevented = evt.isDefaultPrevented();\n    });\n  };\n\n  return EventRelay;\n});\n\nS2.define('select2/translation',[\n  'jquery',\n  'require'\n], function ($, require) {\n  function Translation (dict) {\n    this.dict = dict || {};\n  }\n\n  Translation.prototype.all = function () {\n    return this.dict;\n  };\n\n  Translation.prototype.get = function (key) {\n    return this.dict[key];\n  };\n\n  Translation.prototype.extend = function (translation) {\n    this.dict = $.extend({}, translation.all(), this.dict);\n  };\n\n  // Static functions\n\n  Translation._cache = {};\n\n  Translation.loadPath = function (path) {\n    if (!(path in Translation._cache)) {\n      var translations = require(path);\n\n      Translation._cache[path] = translations;\n    }\n\n    return new Translation(Translation._cache[path]);\n  };\n\n  return Translation;\n});\n\nS2.define('select2/diacritics',[\n\n], function () {\n  var diacritics = {\n    '\\u24B6': 'A',\n    '\\uFF21': 'A',\n    '\\u00C0': 'A',\n    '\\u00C1': 'A',\n    '\\u00C2': 'A',\n    '\\u1EA6': 'A',\n    '\\u1EA4': 'A',\n    '\\u1EAA': 'A',\n    '\\u1EA8': 'A',\n    '\\u00C3': 'A',\n    '\\u0100': 'A',\n    '\\u0102': 'A',\n    '\\u1EB0': 'A',\n    '\\u1EAE': 'A',\n    '\\u1EB4': 'A',\n    '\\u1EB2': 'A',\n    '\\u0226': 'A',\n    '\\u01E0': 'A',\n    '\\u00C4': 'A',\n    '\\u01DE': 'A',\n    '\\u1EA2': 'A',\n    '\\u00C5': 'A',\n    '\\u01FA': 'A',\n    '\\u01CD': 'A',\n    '\\u0200': 'A',\n    '\\u0202': 'A',\n    '\\u1EA0': 'A',\n    '\\u1EAC': 'A',\n    '\\u1EB6': 'A',\n    '\\u1E00': 'A',\n    '\\u0104': 'A',\n    '\\u023A': 'A',\n    '\\u2C6F': 'A',\n    '\\uA732': 'AA',\n    '\\u00C6': 'AE',\n    '\\u01FC': 'AE',\n    '\\u01E2': 'AE',\n    '\\uA734': 'AO',\n    '\\uA736': 'AU',\n    '\\uA738': 'AV',\n    '\\uA73A': 'AV',\n    '\\uA73C': 'AY',\n    '\\u24B7': 'B',\n    '\\uFF22': 'B',\n    '\\u1E02': 'B',\n    '\\u1E04': 'B',\n    '\\u1E06': 'B',\n    '\\u0243': 'B',\n    '\\u0182': 'B',\n    '\\u0181': 'B',\n    '\\u24B8': 'C',\n    '\\uFF23': 'C',\n    '\\u0106': 'C',\n    '\\u0108': 'C',\n    '\\u010A': 'C',\n    '\\u010C': 'C',\n    '\\u00C7': 'C',\n    '\\u1E08': 'C',\n    '\\u0187': 'C',\n    '\\u023B': 'C',\n    '\\uA73E': 'C',\n    '\\u24B9': 'D',\n    '\\uFF24': 'D',\n    '\\u1E0A': 'D',\n    '\\u010E': 'D',\n    '\\u1E0C': 'D',\n    '\\u1E10': 'D',\n    '\\u1E12': 'D',\n    '\\u1E0E': 'D',\n    '\\u0110': 'D',\n    '\\u018B': 'D',\n    '\\u018A': 'D',\n    '\\u0189': 'D',\n    '\\uA779': 'D',\n    '\\u01F1': 'DZ',\n    '\\u01C4': 'DZ',\n    '\\u01F2': 'Dz',\n    '\\u01C5': 'Dz',\n    '\\u24BA': 'E',\n    '\\uFF25': 'E',\n    '\\u00C8': 'E',\n    '\\u00C9': 'E',\n    '\\u00CA': 'E',\n    '\\u1EC0': 'E',\n    '\\u1EBE': 'E',\n    '\\u1EC4': 'E',\n    '\\u1EC2': 'E',\n    '\\u1EBC': 'E',\n    '\\u0112': 'E',\n    '\\u1E14': 'E',\n    '\\u1E16': 'E',\n    '\\u0114': 'E',\n    '\\u0116': 'E',\n    '\\u00CB': 'E',\n    '\\u1EBA': 'E',\n    '\\u011A': 'E',\n    '\\u0204': 'E',\n    '\\u0206': 'E',\n    '\\u1EB8': 'E',\n    '\\u1EC6': 'E',\n    '\\u0228': 'E',\n    '\\u1E1C': 'E',\n    '\\u0118': 'E',\n    '\\u1E18': 'E',\n    '\\u1E1A': 'E',\n    '\\u0190': 'E',\n    '\\u018E': 'E',\n    '\\u24BB': 'F',\n    '\\uFF26': 'F',\n    '\\u1E1E': 'F',\n    '\\u0191': 'F',\n    '\\uA77B': 'F',\n    '\\u24BC': 'G',\n    '\\uFF27': 'G',\n    '\\u01F4': 'G',\n    '\\u011C': 'G',\n    '\\u1E20': 'G',\n    '\\u011E': 'G',\n    '\\u0120': 'G',\n    '\\u01E6': 'G',\n    '\\u0122': 'G',\n    '\\u01E4': 'G',\n    '\\u0193': 'G',\n    '\\uA7A0': 'G',\n    '\\uA77D': 'G',\n    '\\uA77E': 'G',\n    '\\u24BD': 'H',\n    '\\uFF28': 'H',\n    '\\u0124': 'H',\n    '\\u1E22': 'H',\n    '\\u1E26': 'H',\n    '\\u021E': 'H',\n    '\\u1E24': 'H',\n    '\\u1E28': 'H',\n    '\\u1E2A': 'H',\n    '\\u0126': 'H',\n    '\\u2C67': 'H',\n    '\\u2C75': 'H',\n    '\\uA78D': 'H',\n    '\\u24BE': 'I',\n    '\\uFF29': 'I',\n    '\\u00CC': 'I',\n    '\\u00CD': 'I',\n    '\\u00CE': 'I',\n    '\\u0128': 'I',\n    '\\u012A': 'I',\n    '\\u012C': 'I',\n    '\\u0130': 'I',\n    '\\u00CF': 'I',\n    '\\u1E2E': 'I',\n    '\\u1EC8': 'I',\n    '\\u01CF': 'I',\n    '\\u0208': 'I',\n    '\\u020A': 'I',\n    '\\u1ECA': 'I',\n    '\\u012E': 'I',\n    '\\u1E2C': 'I',\n    '\\u0197': 'I',\n    '\\u24BF': 'J',\n    '\\uFF2A': 'J',\n    '\\u0134': 'J',\n    '\\u0248': 'J',\n    '\\u24C0': 'K',\n    '\\uFF2B': 'K',\n    '\\u1E30': 'K',\n    '\\u01E8': 'K',\n    '\\u1E32': 'K',\n    '\\u0136': 'K',\n    '\\u1E34': 'K',\n    '\\u0198': 'K',\n    '\\u2C69': 'K',\n    '\\uA740': 'K',\n    '\\uA742': 'K',\n    '\\uA744': 'K',\n    '\\uA7A2': 'K',\n    '\\u24C1': 'L',\n    '\\uFF2C': 'L',\n    '\\u013F': 'L',\n    '\\u0139': 'L',\n    '\\u013D': 'L',\n    '\\u1E36': 'L',\n    '\\u1E38': 'L',\n    '\\u013B': 'L',\n    '\\u1E3C': 'L',\n    '\\u1E3A': 'L',\n    '\\u0141': 'L',\n    '\\u023D': 'L',\n    '\\u2C62': 'L',\n    '\\u2C60': 'L',\n    '\\uA748': 'L',\n    '\\uA746': 'L',\n    '\\uA780': 'L',\n    '\\u01C7': 'LJ',\n    '\\u01C8': 'Lj',\n    '\\u24C2': 'M',\n    '\\uFF2D': 'M',\n    '\\u1E3E': 'M',\n    '\\u1E40': 'M',\n    '\\u1E42': 'M',\n    '\\u2C6E': 'M',\n    '\\u019C': 'M',\n    '\\u24C3': 'N',\n    '\\uFF2E': 'N',\n    '\\u01F8': 'N',\n    '\\u0143': 'N',\n    '\\u00D1': 'N',\n    '\\u1E44': 'N',\n    '\\u0147': 'N',\n    '\\u1E46': 'N',\n    '\\u0145': 'N',\n    '\\u1E4A': 'N',\n    '\\u1E48': 'N',\n    '\\u0220': 'N',\n    '\\u019D': 'N',\n    '\\uA790': 'N',\n    '\\uA7A4': 'N',\n    '\\u01CA': 'NJ',\n    '\\u01CB': 'Nj',\n    '\\u24C4': 'O',\n    '\\uFF2F': 'O',\n    '\\u00D2': 'O',\n    '\\u00D3': 'O',\n    '\\u00D4': 'O',\n    '\\u1ED2': 'O',\n    '\\u1ED0': 'O',\n    '\\u1ED6': 'O',\n    '\\u1ED4': 'O',\n    '\\u00D5': 'O',\n    '\\u1E4C': 'O',\n    '\\u022C': 'O',\n    '\\u1E4E': 'O',\n    '\\u014C': 'O',\n    '\\u1E50': 'O',\n    '\\u1E52': 'O',\n    '\\u014E': 'O',\n    '\\u022E': 'O',\n    '\\u0230': 'O',\n    '\\u00D6': 'O',\n    '\\u022A': 'O',\n    '\\u1ECE': 'O',\n    '\\u0150': 'O',\n    '\\u01D1': 'O',\n    '\\u020C': 'O',\n    '\\u020E': 'O',\n    '\\u01A0': 'O',\n    '\\u1EDC': 'O',\n    '\\u1EDA': 'O',\n    '\\u1EE0': 'O',\n    '\\u1EDE': 'O',\n    '\\u1EE2': 'O',\n    '\\u1ECC': 'O',\n    '\\u1ED8': 'O',\n    '\\u01EA': 'O',\n    '\\u01EC': 'O',\n    '\\u00D8': 'O',\n    '\\u01FE': 'O',\n    '\\u0186': 'O',\n    '\\u019F': 'O',\n    '\\uA74A': 'O',\n    '\\uA74C': 'O',\n    '\\u0152': 'OE',\n    '\\u01A2': 'OI',\n    '\\uA74E': 'OO',\n    '\\u0222': 'OU',\n    '\\u24C5': 'P',\n    '\\uFF30': 'P',\n    '\\u1E54': 'P',\n    '\\u1E56': 'P',\n    '\\u01A4': 'P',\n    '\\u2C63': 'P',\n    '\\uA750': 'P',\n    '\\uA752': 'P',\n    '\\uA754': 'P',\n    '\\u24C6': 'Q',\n    '\\uFF31': 'Q',\n    '\\uA756': 'Q',\n    '\\uA758': 'Q',\n    '\\u024A': 'Q',\n    '\\u24C7': 'R',\n    '\\uFF32': 'R',\n    '\\u0154': 'R',\n    '\\u1E58': 'R',\n    '\\u0158': 'R',\n    '\\u0210': 'R',\n    '\\u0212': 'R',\n    '\\u1E5A': 'R',\n    '\\u1E5C': 'R',\n    '\\u0156': 'R',\n    '\\u1E5E': 'R',\n    '\\u024C': 'R',\n    '\\u2C64': 'R',\n    '\\uA75A': 'R',\n    '\\uA7A6': 'R',\n    '\\uA782': 'R',\n    '\\u24C8': 'S',\n    '\\uFF33': 'S',\n    '\\u1E9E': 'S',\n    '\\u015A': 'S',\n    '\\u1E64': 'S',\n    '\\u015C': 'S',\n    '\\u1E60': 'S',\n    '\\u0160': 'S',\n    '\\u1E66': 'S',\n    '\\u1E62': 'S',\n    '\\u1E68': 'S',\n    '\\u0218': 'S',\n    '\\u015E': 'S',\n    '\\u2C7E': 'S',\n    '\\uA7A8': 'S',\n    '\\uA784': 'S',\n    '\\u24C9': 'T',\n    '\\uFF34': 'T',\n    '\\u1E6A': 'T',\n    '\\u0164': 'T',\n    '\\u1E6C': 'T',\n    '\\u021A': 'T',\n    '\\u0162': 'T',\n    '\\u1E70': 'T',\n    '\\u1E6E': 'T',\n    '\\u0166': 'T',\n    '\\u01AC': 'T',\n    '\\u01AE': 'T',\n    '\\u023E': 'T',\n    '\\uA786': 'T',\n    '\\uA728': 'TZ',\n    '\\u24CA': 'U',\n    '\\uFF35': 'U',\n    '\\u00D9': 'U',\n    '\\u00DA': 'U',\n    '\\u00DB': 'U',\n    '\\u0168': 'U',\n    '\\u1E78': 'U',\n    '\\u016A': 'U',\n    '\\u1E7A': 'U',\n    '\\u016C': 'U',\n    '\\u00DC': 'U',\n    '\\u01DB': 'U',\n    '\\u01D7': 'U',\n    '\\u01D5': 'U',\n    '\\u01D9': 'U',\n    '\\u1EE6': 'U',\n    '\\u016E': 'U',\n    '\\u0170': 'U',\n    '\\u01D3': 'U',\n    '\\u0214': 'U',\n    '\\u0216': 'U',\n    '\\u01AF': 'U',\n    '\\u1EEA': 'U',\n    '\\u1EE8': 'U',\n    '\\u1EEE': 'U',\n    '\\u1EEC': 'U',\n    '\\u1EF0': 'U',\n    '\\u1EE4': 'U',\n    '\\u1E72': 'U',\n    '\\u0172': 'U',\n    '\\u1E76': 'U',\n    '\\u1E74': 'U',\n    '\\u0244': 'U',\n    '\\u24CB': 'V',\n    '\\uFF36': 'V',\n    '\\u1E7C': 'V',\n    '\\u1E7E': 'V',\n    '\\u01B2': 'V',\n    '\\uA75E': 'V',\n    '\\u0245': 'V',\n    '\\uA760': 'VY',\n    '\\u24CC': 'W',\n    '\\uFF37': 'W',\n    '\\u1E80': 'W',\n    '\\u1E82': 'W',\n    '\\u0174': 'W',\n    '\\u1E86': 'W',\n    '\\u1E84': 'W',\n    '\\u1E88': 'W',\n    '\\u2C72': 'W',\n    '\\u24CD': 'X',\n    '\\uFF38': 'X',\n    '\\u1E8A': 'X',\n    '\\u1E8C': 'X',\n    '\\u24CE': 'Y',\n    '\\uFF39': 'Y',\n    '\\u1EF2': 'Y',\n    '\\u00DD': 'Y',\n    '\\u0176': 'Y',\n    '\\u1EF8': 'Y',\n    '\\u0232': 'Y',\n    '\\u1E8E': 'Y',\n    '\\u0178': 'Y',\n    '\\u1EF6': 'Y',\n    '\\u1EF4': 'Y',\n    '\\u01B3': 'Y',\n    '\\u024E': 'Y',\n    '\\u1EFE': 'Y',\n    '\\u24CF': 'Z',\n    '\\uFF3A': 'Z',\n    '\\u0179': 'Z',\n    '\\u1E90': 'Z',\n    '\\u017B': 'Z',\n    '\\u017D': 'Z',\n    '\\u1E92': 'Z',\n    '\\u1E94': 'Z',\n    '\\u01B5': 'Z',\n    '\\u0224': 'Z',\n    '\\u2C7F': 'Z',\n    '\\u2C6B': 'Z',\n    '\\uA762': 'Z',\n    '\\u24D0': 'a',\n    '\\uFF41': 'a',\n    '\\u1E9A': 'a',\n    '\\u00E0': 'a',\n    '\\u00E1': 'a',\n    '\\u00E2': 'a',\n    '\\u1EA7': 'a',\n    '\\u1EA5': 'a',\n    '\\u1EAB': 'a',\n    '\\u1EA9': 'a',\n    '\\u00E3': 'a',\n    '\\u0101': 'a',\n    '\\u0103': 'a',\n    '\\u1EB1': 'a',\n    '\\u1EAF': 'a',\n    '\\u1EB5': 'a',\n    '\\u1EB3': 'a',\n    '\\u0227': 'a',\n    '\\u01E1': 'a',\n    '\\u00E4': 'a',\n    '\\u01DF': 'a',\n    '\\u1EA3': 'a',\n    '\\u00E5': 'a',\n    '\\u01FB': 'a',\n    '\\u01CE': 'a',\n    '\\u0201': 'a',\n    '\\u0203': 'a',\n    '\\u1EA1': 'a',\n    '\\u1EAD': 'a',\n    '\\u1EB7': 'a',\n    '\\u1E01': 'a',\n    '\\u0105': 'a',\n    '\\u2C65': 'a',\n    '\\u0250': 'a',\n    '\\uA733': 'aa',\n    '\\u00E6': 'ae',\n    '\\u01FD': 'ae',\n    '\\u01E3': 'ae',\n    '\\uA735': 'ao',\n    '\\uA737': 'au',\n    '\\uA739': 'av',\n    '\\uA73B': 'av',\n    '\\uA73D': 'ay',\n    '\\u24D1': 'b',\n    '\\uFF42': 'b',\n    '\\u1E03': 'b',\n    '\\u1E05': 'b',\n    '\\u1E07': 'b',\n    '\\u0180': 'b',\n    '\\u0183': 'b',\n    '\\u0253': 'b',\n    '\\u24D2': 'c',\n    '\\uFF43': 'c',\n    '\\u0107': 'c',\n    '\\u0109': 'c',\n    '\\u010B': 'c',\n    '\\u010D': 'c',\n    '\\u00E7': 'c',\n    '\\u1E09': 'c',\n    '\\u0188': 'c',\n    '\\u023C': 'c',\n    '\\uA73F': 'c',\n    '\\u2184': 'c',\n    '\\u24D3': 'd',\n    '\\uFF44': 'd',\n    '\\u1E0B': 'd',\n    '\\u010F': 'd',\n    '\\u1E0D': 'd',\n    '\\u1E11': 'd',\n    '\\u1E13': 'd',\n    '\\u1E0F': 'd',\n    '\\u0111': 'd',\n    '\\u018C': 'd',\n    '\\u0256': 'd',\n    '\\u0257': 'd',\n    '\\uA77A': 'd',\n    '\\u01F3': 'dz',\n    '\\u01C6': 'dz',\n    '\\u24D4': 'e',\n    '\\uFF45': 'e',\n    '\\u00E8': 'e',\n    '\\u00E9': 'e',\n    '\\u00EA': 'e',\n    '\\u1EC1': 'e',\n    '\\u1EBF': 'e',\n    '\\u1EC5': 'e',\n    '\\u1EC3': 'e',\n    '\\u1EBD': 'e',\n    '\\u0113': 'e',\n    '\\u1E15': 'e',\n    '\\u1E17': 'e',\n    '\\u0115': 'e',\n    '\\u0117': 'e',\n    '\\u00EB': 'e',\n    '\\u1EBB': 'e',\n    '\\u011B': 'e',\n    '\\u0205': 'e',\n    '\\u0207': 'e',\n    '\\u1EB9': 'e',\n    '\\u1EC7': 'e',\n    '\\u0229': 'e',\n    '\\u1E1D': 'e',\n    '\\u0119': 'e',\n    '\\u1E19': 'e',\n    '\\u1E1B': 'e',\n    '\\u0247': 'e',\n    '\\u025B': 'e',\n    '\\u01DD': 'e',\n    '\\u24D5': 'f',\n    '\\uFF46': 'f',\n    '\\u1E1F': 'f',\n    '\\u0192': 'f',\n    '\\uA77C': 'f',\n    '\\u24D6': 'g',\n    '\\uFF47': 'g',\n    '\\u01F5': 'g',\n    '\\u011D': 'g',\n    '\\u1E21': 'g',\n    '\\u011F': 'g',\n    '\\u0121': 'g',\n    '\\u01E7': 'g',\n    '\\u0123': 'g',\n    '\\u01E5': 'g',\n    '\\u0260': 'g',\n    '\\uA7A1': 'g',\n    '\\u1D79': 'g',\n    '\\uA77F': 'g',\n    '\\u24D7': 'h',\n    '\\uFF48': 'h',\n    '\\u0125': 'h',\n    '\\u1E23': 'h',\n    '\\u1E27': 'h',\n    '\\u021F': 'h',\n    '\\u1E25': 'h',\n    '\\u1E29': 'h',\n    '\\u1E2B': 'h',\n    '\\u1E96': 'h',\n    '\\u0127': 'h',\n    '\\u2C68': 'h',\n    '\\u2C76': 'h',\n    '\\u0265': 'h',\n    '\\u0195': 'hv',\n    '\\u24D8': 'i',\n    '\\uFF49': 'i',\n    '\\u00EC': 'i',\n    '\\u00ED': 'i',\n    '\\u00EE': 'i',\n    '\\u0129': 'i',\n    '\\u012B': 'i',\n    '\\u012D': 'i',\n    '\\u00EF': 'i',\n    '\\u1E2F': 'i',\n    '\\u1EC9': 'i',\n    '\\u01D0': 'i',\n    '\\u0209': 'i',\n    '\\u020B': 'i',\n    '\\u1ECB': 'i',\n    '\\u012F': 'i',\n    '\\u1E2D': 'i',\n    '\\u0268': 'i',\n    '\\u0131': 'i',\n    '\\u24D9': 'j',\n    '\\uFF4A': 'j',\n    '\\u0135': 'j',\n    '\\u01F0': 'j',\n    '\\u0249': 'j',\n    '\\u24DA': 'k',\n    '\\uFF4B': 'k',\n    '\\u1E31': 'k',\n    '\\u01E9': 'k',\n    '\\u1E33': 'k',\n    '\\u0137': 'k',\n    '\\u1E35': 'k',\n    '\\u0199': 'k',\n    '\\u2C6A': 'k',\n    '\\uA741': 'k',\n    '\\uA743': 'k',\n    '\\uA745': 'k',\n    '\\uA7A3': 'k',\n    '\\u24DB': 'l',\n    '\\uFF4C': 'l',\n    '\\u0140': 'l',\n    '\\u013A': 'l',\n    '\\u013E': 'l',\n    '\\u1E37': 'l',\n    '\\u1E39': 'l',\n    '\\u013C': 'l',\n    '\\u1E3D': 'l',\n    '\\u1E3B': 'l',\n    '\\u017F': 'l',\n    '\\u0142': 'l',\n    '\\u019A': 'l',\n    '\\u026B': 'l',\n    '\\u2C61': 'l',\n    '\\uA749': 'l',\n    '\\uA781': 'l',\n    '\\uA747': 'l',\n    '\\u01C9': 'lj',\n    '\\u24DC': 'm',\n    '\\uFF4D': 'm',\n    '\\u1E3F': 'm',\n    '\\u1E41': 'm',\n    '\\u1E43': 'm',\n    '\\u0271': 'm',\n    '\\u026F': 'm',\n    '\\u24DD': 'n',\n    '\\uFF4E': 'n',\n    '\\u01F9': 'n',\n    '\\u0144': 'n',\n    '\\u00F1': 'n',\n    '\\u1E45': 'n',\n    '\\u0148': 'n',\n    '\\u1E47': 'n',\n    '\\u0146': 'n',\n    '\\u1E4B': 'n',\n    '\\u1E49': 'n',\n    '\\u019E': 'n',\n    '\\u0272': 'n',\n    '\\u0149': 'n',\n    '\\uA791': 'n',\n    '\\uA7A5': 'n',\n    '\\u01CC': 'nj',\n    '\\u24DE': 'o',\n    '\\uFF4F': 'o',\n    '\\u00F2': 'o',\n    '\\u00F3': 'o',\n    '\\u00F4': 'o',\n    '\\u1ED3': 'o',\n    '\\u1ED1': 'o',\n    '\\u1ED7': 'o',\n    '\\u1ED5': 'o',\n    '\\u00F5': 'o',\n    '\\u1E4D': 'o',\n    '\\u022D': 'o',\n    '\\u1E4F': 'o',\n    '\\u014D': 'o',\n    '\\u1E51': 'o',\n    '\\u1E53': 'o',\n    '\\u014F': 'o',\n    '\\u022F': 'o',\n    '\\u0231': 'o',\n    '\\u00F6': 'o',\n    '\\u022B': 'o',\n    '\\u1ECF': 'o',\n    '\\u0151': 'o',\n    '\\u01D2': 'o',\n    '\\u020D': 'o',\n    '\\u020F': 'o',\n    '\\u01A1': 'o',\n    '\\u1EDD': 'o',\n    '\\u1EDB': 'o',\n    '\\u1EE1': 'o',\n    '\\u1EDF': 'o',\n    '\\u1EE3': 'o',\n    '\\u1ECD': 'o',\n    '\\u1ED9': 'o',\n    '\\u01EB': 'o',\n    '\\u01ED': 'o',\n    '\\u00F8': 'o',\n    '\\u01FF': 'o',\n    '\\u0254': 'o',\n    '\\uA74B': 'o',\n    '\\uA74D': 'o',\n    '\\u0275': 'o',\n    '\\u0153': 'oe',\n    '\\u01A3': 'oi',\n    '\\u0223': 'ou',\n    '\\uA74F': 'oo',\n    '\\u24DF': 'p',\n    '\\uFF50': 'p',\n    '\\u1E55': 'p',\n    '\\u1E57': 'p',\n    '\\u01A5': 'p',\n    '\\u1D7D': 'p',\n    '\\uA751': 'p',\n    '\\uA753': 'p',\n    '\\uA755': 'p',\n    '\\u24E0': 'q',\n    '\\uFF51': 'q',\n    '\\u024B': 'q',\n    '\\uA757': 'q',\n    '\\uA759': 'q',\n    '\\u24E1': 'r',\n    '\\uFF52': 'r',\n    '\\u0155': 'r',\n    '\\u1E59': 'r',\n    '\\u0159': 'r',\n    '\\u0211': 'r',\n    '\\u0213': 'r',\n    '\\u1E5B': 'r',\n    '\\u1E5D': 'r',\n    '\\u0157': 'r',\n    '\\u1E5F': 'r',\n    '\\u024D': 'r',\n    '\\u027D': 'r',\n    '\\uA75B': 'r',\n    '\\uA7A7': 'r',\n    '\\uA783': 'r',\n    '\\u24E2': 's',\n    '\\uFF53': 's',\n    '\\u00DF': 's',\n    '\\u015B': 's',\n    '\\u1E65': 's',\n    '\\u015D': 's',\n    '\\u1E61': 's',\n    '\\u0161': 's',\n    '\\u1E67': 's',\n    '\\u1E63': 's',\n    '\\u1E69': 's',\n    '\\u0219': 's',\n    '\\u015F': 's',\n    '\\u023F': 's',\n    '\\uA7A9': 's',\n    '\\uA785': 's',\n    '\\u1E9B': 's',\n    '\\u24E3': 't',\n    '\\uFF54': 't',\n    '\\u1E6B': 't',\n    '\\u1E97': 't',\n    '\\u0165': 't',\n    '\\u1E6D': 't',\n    '\\u021B': 't',\n    '\\u0163': 't',\n    '\\u1E71': 't',\n    '\\u1E6F': 't',\n    '\\u0167': 't',\n    '\\u01AD': 't',\n    '\\u0288': 't',\n    '\\u2C66': 't',\n    '\\uA787': 't',\n    '\\uA729': 'tz',\n    '\\u24E4': 'u',\n    '\\uFF55': 'u',\n    '\\u00F9': 'u',\n    '\\u00FA': 'u',\n    '\\u00FB': 'u',\n    '\\u0169': 'u',\n    '\\u1E79': 'u',\n    '\\u016B': 'u',\n    '\\u1E7B': 'u',\n    '\\u016D': 'u',\n    '\\u00FC': 'u',\n    '\\u01DC': 'u',\n    '\\u01D8': 'u',\n    '\\u01D6': 'u',\n    '\\u01DA': 'u',\n    '\\u1EE7': 'u',\n    '\\u016F': 'u',\n    '\\u0171': 'u',\n    '\\u01D4': 'u',\n    '\\u0215': 'u',\n    '\\u0217': 'u',\n    '\\u01B0': 'u',\n    '\\u1EEB': 'u',\n    '\\u1EE9': 'u',\n    '\\u1EEF': 'u',\n    '\\u1EED': 'u',\n    '\\u1EF1': 'u',\n    '\\u1EE5': 'u',\n    '\\u1E73': 'u',\n    '\\u0173': 'u',\n    '\\u1E77': 'u',\n    '\\u1E75': 'u',\n    '\\u0289': 'u',\n    '\\u24E5': 'v',\n    '\\uFF56': 'v',\n    '\\u1E7D': 'v',\n    '\\u1E7F': 'v',\n    '\\u028B': 'v',\n    '\\uA75F': 'v',\n    '\\u028C': 'v',\n    '\\uA761': 'vy',\n    '\\u24E6': 'w',\n    '\\uFF57': 'w',\n    '\\u1E81': 'w',\n    '\\u1E83': 'w',\n    '\\u0175': 'w',\n    '\\u1E87': 'w',\n    '\\u1E85': 'w',\n    '\\u1E98': 'w',\n    '\\u1E89': 'w',\n    '\\u2C73': 'w',\n    '\\u24E7': 'x',\n    '\\uFF58': 'x',\n    '\\u1E8B': 'x',\n    '\\u1E8D': 'x',\n    '\\u24E8': 'y',\n    '\\uFF59': 'y',\n    '\\u1EF3': 'y',\n    '\\u00FD': 'y',\n    '\\u0177': 'y',\n    '\\u1EF9': 'y',\n    '\\u0233': 'y',\n    '\\u1E8F': 'y',\n    '\\u00FF': 'y',\n    '\\u1EF7': 'y',\n    '\\u1E99': 'y',\n    '\\u1EF5': 'y',\n    '\\u01B4': 'y',\n    '\\u024F': 'y',\n    '\\u1EFF': 'y',\n    '\\u24E9': 'z',\n    '\\uFF5A': 'z',\n    '\\u017A': 'z',\n    '\\u1E91': 'z',\n    '\\u017C': 'z',\n    '\\u017E': 'z',\n    '\\u1E93': 'z',\n    '\\u1E95': 'z',\n    '\\u01B6': 'z',\n    '\\u0225': 'z',\n    '\\u0240': 'z',\n    '\\u2C6C': 'z',\n    '\\uA763': 'z',\n    '\\u0386': '\\u0391',\n    '\\u0388': '\\u0395',\n    '\\u0389': '\\u0397',\n    '\\u038A': '\\u0399',\n    '\\u03AA': '\\u0399',\n    '\\u038C': '\\u039F',\n    '\\u038E': '\\u03A5',\n    '\\u03AB': '\\u03A5',\n    '\\u038F': '\\u03A9',\n    '\\u03AC': '\\u03B1',\n    '\\u03AD': '\\u03B5',\n    '\\u03AE': '\\u03B7',\n    '\\u03AF': '\\u03B9',\n    '\\u03CA': '\\u03B9',\n    '\\u0390': '\\u03B9',\n    '\\u03CC': '\\u03BF',\n    '\\u03CD': '\\u03C5',\n    '\\u03CB': '\\u03C5',\n    '\\u03B0': '\\u03C5',\n    '\\u03CE': '\\u03C9',\n    '\\u03C2': '\\u03C3',\n    '\\u2019': '\\''\n  };\n\n  return diacritics;\n});\n\nS2.define('select2/data/base',[\n  '../utils'\n], function (Utils) {\n  function BaseAdapter ($element, options) {\n    BaseAdapter.__super__.constructor.call(this);\n  }\n\n  Utils.Extend(BaseAdapter, Utils.Observable);\n\n  BaseAdapter.prototype.current = function (callback) {\n    throw new Error('The `current` method must be defined in child classes.');\n  };\n\n  BaseAdapter.prototype.query = function (params, callback) {\n    throw new Error('The `query` method must be defined in child classes.');\n  };\n\n  BaseAdapter.prototype.bind = function (container, $container) {\n    // Can be implemented in subclasses\n  };\n\n  BaseAdapter.prototype.destroy = function () {\n    // Can be implemented in subclasses\n  };\n\n  BaseAdapter.prototype.generateResultId = function (container, data) {\n    var id = container.id + '-result-';\n\n    id += Utils.generateChars(4);\n\n    if (data.id != null) {\n      id += '-' + data.id.toString();\n    } else {\n      id += '-' + Utils.generateChars(4);\n    }\n    return id;\n  };\n\n  return BaseAdapter;\n});\n\nS2.define('select2/data/select',[\n  './base',\n  '../utils',\n  'jquery'\n], function (BaseAdapter, Utils, $) {\n  function SelectAdapter ($element, options) {\n    this.$element = $element;\n    this.options = options;\n\n    SelectAdapter.__super__.constructor.call(this);\n  }\n\n  Utils.Extend(SelectAdapter, BaseAdapter);\n\n  SelectAdapter.prototype.current = function (callback) {\n    var data = [];\n    var self = this;\n\n    this.$element.find(':selected').each(function () {\n      var $option = $(this);\n\n      var option = self.item($option);\n\n      data.push(option);\n    });\n\n    callback(data);\n  };\n\n  SelectAdapter.prototype.select = function (data) {\n    var self = this;\n\n    data.selected = true;\n\n    // If data.element is a DOM node, use it instead\n    if ($(data.element).is('option')) {\n      data.element.selected = true;\n\n      this.$element.trigger('input').trigger('change');\n\n      return;\n    }\n\n    if (this.$element.prop('multiple')) {\n      this.current(function (currentData) {\n        var val = [];\n\n        data = [data];\n        data.push.apply(data, currentData);\n\n        for (var d = 0; d < data.length; d++) {\n          var id = data[d].id;\n\n          if ($.inArray(id, val) === -1) {\n            val.push(id);\n          }\n        }\n\n        self.$element.val(val);\n        self.$element.trigger('input').trigger('change');\n      });\n    } else {\n      var val = data.id;\n\n      this.$element.val(val);\n      this.$element.trigger('input').trigger('change');\n    }\n  };\n\n  SelectAdapter.prototype.unselect = function (data) {\n    var self = this;\n\n    if (!this.$element.prop('multiple')) {\n      return;\n    }\n\n    data.selected = false;\n\n    if ($(data.element).is('option')) {\n      data.element.selected = false;\n\n      this.$element.trigger('input').trigger('change');\n\n      return;\n    }\n\n    this.current(function (currentData) {\n      var val = [];\n\n      for (var d = 0; d < currentData.length; d++) {\n        var id = currentData[d].id;\n\n        if (id !== data.id && $.inArray(id, val) === -1) {\n          val.push(id);\n        }\n      }\n\n      self.$element.val(val);\n\n      self.$element.trigger('input').trigger('change');\n    });\n  };\n\n  SelectAdapter.prototype.bind = function (container, $container) {\n    var self = this;\n\n    this.container = container;\n\n    container.on('select', function (params) {\n      self.select(params.data);\n    });\n\n    container.on('unselect', function (params) {\n      self.unselect(params.data);\n    });\n  };\n\n  SelectAdapter.prototype.destroy = function () {\n    // Remove anything added to child elements\n    this.$element.find('*').each(function () {\n      // Remove any custom data set by Select2\n      Utils.RemoveData(this);\n    });\n  };\n\n  SelectAdapter.prototype.query = function (params, callback) {\n    var data = [];\n    var self = this;\n\n    var $options = this.$element.children();\n\n    $options.each(function () {\n      var $option = $(this);\n\n      if (!$option.is('option') && !$option.is('optgroup')) {\n        return;\n      }\n\n      var option = self.item($option);\n\n      var matches = self.matches(params, option);\n\n      if (matches !== null) {\n        data.push(matches);\n      }\n    });\n\n    callback({\n      results: data\n    });\n  };\n\n  SelectAdapter.prototype.addOptions = function ($options) {\n    Utils.appendMany(this.$element, $options);\n  };\n\n  SelectAdapter.prototype.option = function (data) {\n    var option;\n\n    if (data.children) {\n      option = document.createElement('optgroup');\n      option.label = data.text;\n    } else {\n      option = document.createElement('option');\n\n      if (option.textContent !== undefined) {\n        option.textContent = data.text;\n      } else {\n        option.innerText = data.text;\n      }\n    }\n\n    if (data.id !== undefined) {\n      option.value = data.id;\n    }\n\n    if (data.disabled) {\n      option.disabled = true;\n    }\n\n    if (data.selected) {\n      option.selected = true;\n    }\n\n    if (data.title) {\n      option.title = data.title;\n    }\n\n    var $option = $(option);\n\n    var normalizedData = this._normalizeItem(data);\n    normalizedData.element = option;\n\n    // Override the option's data with the combined data\n    Utils.StoreData(option, 'data', normalizedData);\n\n    return $option;\n  };\n\n  SelectAdapter.prototype.item = function ($option) {\n    var data = {};\n\n    data = Utils.GetData($option[0], 'data');\n\n    if (data != null) {\n      return data;\n    }\n\n    if ($option.is('option')) {\n      data = {\n        id: $option.val(),\n        text: $option.text(),\n        disabled: $option.prop('disabled'),\n        selected: $option.prop('selected'),\n        title: $option.prop('title')\n      };\n    } else if ($option.is('optgroup')) {\n      data = {\n        text: $option.prop('label'),\n        children: [],\n        title: $option.prop('title')\n      };\n\n      var $children = $option.children('option');\n      var children = [];\n\n      for (var c = 0; c < $children.length; c++) {\n        var $child = $($children[c]);\n\n        var child = this.item($child);\n\n        children.push(child);\n      }\n\n      data.children = children;\n    }\n\n    data = this._normalizeItem(data);\n    data.element = $option[0];\n\n    Utils.StoreData($option[0], 'data', data);\n\n    return data;\n  };\n\n  SelectAdapter.prototype._normalizeItem = function (item) {\n    if (item !== Object(item)) {\n      item = {\n        id: item,\n        text: item\n      };\n    }\n\n    item = $.extend({}, {\n      text: ''\n    }, item);\n\n    var defaults = {\n      selected: false,\n      disabled: false\n    };\n\n    if (item.id != null) {\n      item.id = item.id.toString();\n    }\n\n    if (item.text != null) {\n      item.text = item.text.toString();\n    }\n\n    if (item._resultId == null && item.id && this.container != null) {\n      item._resultId = this.generateResultId(this.container, item);\n    }\n\n    return $.extend({}, defaults, item);\n  };\n\n  SelectAdapter.prototype.matches = function (params, data) {\n    var matcher = this.options.get('matcher');\n\n    return matcher(params, data);\n  };\n\n  return SelectAdapter;\n});\n\nS2.define('select2/data/array',[\n  './select',\n  '../utils',\n  'jquery'\n], function (SelectAdapter, Utils, $) {\n  function ArrayAdapter ($element, options) {\n    this._dataToConvert = options.get('data') || [];\n\n    ArrayAdapter.__super__.constructor.call(this, $element, options);\n  }\n\n  Utils.Extend(ArrayAdapter, SelectAdapter);\n\n  ArrayAdapter.prototype.bind = function (container, $container) {\n    ArrayAdapter.__super__.bind.call(this, container, $container);\n\n    this.addOptions(this.convertToOptions(this._dataToConvert));\n  };\n\n  ArrayAdapter.prototype.select = function (data) {\n    var $option = this.$element.find('option').filter(function (i, elm) {\n      return elm.value == data.id.toString();\n    });\n\n    if ($option.length === 0) {\n      $option = this.option(data);\n\n      this.addOptions($option);\n    }\n\n    ArrayAdapter.__super__.select.call(this, data);\n  };\n\n  ArrayAdapter.prototype.convertToOptions = function (data) {\n    var self = this;\n\n    var $existing = this.$element.find('option');\n    var existingIds = $existing.map(function () {\n      return self.item($(this)).id;\n    }).get();\n\n    var $options = [];\n\n    // Filter out all items except for the one passed in the argument\n    function onlyItem (item) {\n      return function () {\n        return $(this).val() == item.id;\n      };\n    }\n\n    for (var d = 0; d < data.length; d++) {\n      var item = this._normalizeItem(data[d]);\n\n      // Skip items which were pre-loaded, only merge the data\n      if ($.inArray(item.id, existingIds) >= 0) {\n        var $existingOption = $existing.filter(onlyItem(item));\n\n        var existingData = this.item($existingOption);\n        var newData = $.extend(true, {}, item, existingData);\n\n        var $newOption = this.option(newData);\n\n        $existingOption.replaceWith($newOption);\n\n        continue;\n      }\n\n      var $option = this.option(item);\n\n      if (item.children) {\n        var $children = this.convertToOptions(item.children);\n\n        Utils.appendMany($option, $children);\n      }\n\n      $options.push($option);\n    }\n\n    return $options;\n  };\n\n  return ArrayAdapter;\n});\n\nS2.define('select2/data/ajax',[\n  './array',\n  '../utils',\n  'jquery'\n], function (ArrayAdapter, Utils, $) {\n  function AjaxAdapter ($element, options) {\n    this.ajaxOptions = this._applyDefaults(options.get('ajax'));\n\n    if (this.ajaxOptions.processResults != null) {\n      this.processResults = this.ajaxOptions.processResults;\n    }\n\n    AjaxAdapter.__super__.constructor.call(this, $element, options);\n  }\n\n  Utils.Extend(AjaxAdapter, ArrayAdapter);\n\n  AjaxAdapter.prototype._applyDefaults = function (options) {\n    var defaults = {\n      data: function (params) {\n        return $.extend({}, params, {\n          q: params.term\n        });\n      },\n      transport: function (params, success, failure) {\n        var $request = $.ajax(params);\n\n        $request.then(success);\n        $request.fail(failure);\n\n        return $request;\n      }\n    };\n\n    return $.extend({}, defaults, options, true);\n  };\n\n  AjaxAdapter.prototype.processResults = function (results) {\n    return results;\n  };\n\n  AjaxAdapter.prototype.query = function (params, callback) {\n    var matches = [];\n    var self = this;\n\n    if (this._request != null) {\n      // JSONP requests cannot always be aborted\n      if ($.isFunction(this._request.abort)) {\n        this._request.abort();\n      }\n\n      this._request = null;\n    }\n\n    var options = $.extend({\n      type: 'GET'\n    }, this.ajaxOptions);\n\n    if (typeof options.url === 'function') {\n      options.url = options.url.call(this.$element, params);\n    }\n\n    if (typeof options.data === 'function') {\n      options.data = options.data.call(this.$element, params);\n    }\n\n    function request () {\n      var $request = options.transport(options, function (data) {\n        var results = self.processResults(data, params);\n\n        if (self.options.get('debug') && window.console && console.error) {\n          // Check to make sure that the response included a `results` key.\n          if (!results || !results.results || !$.isArray(results.results)) {\n            console.error(\n              'Select2: The AJAX results did not return an array in the ' +\n              '`results` key of the response.'\n            );\n          }\n        }\n\n        callback(results);\n      }, function () {\n        // Attempt to detect if a request was aborted\n        // Only works if the transport exposes a status property\n        if ('status' in $request &&\n            ($request.status === 0 || $request.status === '0')) {\n          return;\n        }\n\n        self.trigger('results:message', {\n          message: 'errorLoading'\n        });\n      });\n\n      self._request = $request;\n    }\n\n    if (this.ajaxOptions.delay && params.term != null) {\n      if (this._queryTimeout) {\n        window.clearTimeout(this._queryTimeout);\n      }\n\n      this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);\n    } else {\n      request();\n    }\n  };\n\n  return AjaxAdapter;\n});\n\nS2.define('select2/data/tags',[\n  'jquery'\n], function ($) {\n  function Tags (decorated, $element, options) {\n    var tags = options.get('tags');\n\n    var createTag = options.get('createTag');\n\n    if (createTag !== undefined) {\n      this.createTag = createTag;\n    }\n\n    var insertTag = options.get('insertTag');\n\n    if (insertTag !== undefined) {\n        this.insertTag = insertTag;\n    }\n\n    decorated.call(this, $element, options);\n\n    if ($.isArray(tags)) {\n      for (var t = 0; t < tags.length; t++) {\n        var tag = tags[t];\n        var item = this._normalizeItem(tag);\n\n        var $option = this.option(item);\n\n        this.$element.append($option);\n      }\n    }\n  }\n\n  Tags.prototype.query = function (decorated, params, callback) {\n    var self = this;\n\n    this._removeOldTags();\n\n    if (params.term == null || params.page != null) {\n      decorated.call(this, params, callback);\n      return;\n    }\n\n    function wrapper (obj, child) {\n      var data = obj.results;\n\n      for (var i = 0; i < data.length; i++) {\n        var option = data[i];\n\n        var checkChildren = (\n          option.children != null &&\n          !wrapper({\n            results: option.children\n          }, true)\n        );\n\n        var optionText = (option.text || '').toUpperCase();\n        var paramsTerm = (params.term || '').toUpperCase();\n\n        var checkText = optionText === paramsTerm;\n\n        if (checkText || checkChildren) {\n          if (child) {\n            return false;\n          }\n\n          obj.data = data;\n          callback(obj);\n\n          return;\n        }\n      }\n\n      if (child) {\n        return true;\n      }\n\n      var tag = self.createTag(params);\n\n      if (tag != null) {\n        var $option = self.option(tag);\n        $option.attr('data-select2-tag', true);\n\n        self.addOptions([$option]);\n\n        self.insertTag(data, tag);\n      }\n\n      obj.results = data;\n\n      callback(obj);\n    }\n\n    decorated.call(this, params, wrapper);\n  };\n\n  Tags.prototype.createTag = function (decorated, params) {\n    var term = $.trim(params.term);\n\n    if (term === '') {\n      return null;\n    }\n\n    return {\n      id: term,\n      text: term\n    };\n  };\n\n  Tags.prototype.insertTag = function (_, data, tag) {\n    data.unshift(tag);\n  };\n\n  Tags.prototype._removeOldTags = function (_) {\n    var $options = this.$element.find('option[data-select2-tag]');\n\n    $options.each(function () {\n      if (this.selected) {\n        return;\n      }\n\n      $(this).remove();\n    });\n  };\n\n  return Tags;\n});\n\nS2.define('select2/data/tokenizer',[\n  'jquery'\n], function ($) {\n  function Tokenizer (decorated, $element, options) {\n    var tokenizer = options.get('tokenizer');\n\n    if (tokenizer !== undefined) {\n      this.tokenizer = tokenizer;\n    }\n\n    decorated.call(this, $element, options);\n  }\n\n  Tokenizer.prototype.bind = function (decorated, container, $container) {\n    decorated.call(this, container, $container);\n\n    this.$search =  container.dropdown.$search || container.selection.$search ||\n      $container.find('.select2-search__field');\n  };\n\n  Tokenizer.prototype.query = function (decorated, params, callback) {\n    var self = this;\n\n    function createAndSelect (data) {\n      // Normalize the data object so we can use it for checks\n      var item = self._normalizeItem(data);\n\n      // Check if the data object already exists as a tag\n      // Select it if it doesn't\n      var $existingOptions = self.$element.find('option').filter(function () {\n        return $(this).val() === item.id;\n      });\n\n      // If an existing option wasn't found for it, create the option\n      if (!$existingOptions.length) {\n        var $option = self.option(item);\n        $option.attr('data-select2-tag', true);\n\n        self._removeOldTags();\n        self.addOptions([$option]);\n      }\n\n      // Select the item, now that we know there is an option for it\n      select(item);\n    }\n\n    function select (data) {\n      self.trigger('select', {\n        data: data\n      });\n    }\n\n    params.term = params.term || '';\n\n    var tokenData = this.tokenizer(params, this.options, createAndSelect);\n\n    if (tokenData.term !== params.term) {\n      // Replace the search term if we have the search box\n      if (this.$search.length) {\n        this.$search.val(tokenData.term);\n        this.$search.trigger('focus');\n      }\n\n      params.term = tokenData.term;\n    }\n\n    decorated.call(this, params, callback);\n  };\n\n  Tokenizer.prototype.tokenizer = function (_, params, options, callback) {\n    var separators = options.get('tokenSeparators') || [];\n    var term = params.term;\n    var i = 0;\n\n    var createTag = this.createTag || function (params) {\n      return {\n        id: params.term,\n        text: params.term\n      };\n    };\n\n    while (i < term.length) {\n      var termChar = term[i];\n\n      if ($.inArray(termChar, separators) === -1) {\n        i++;\n\n        continue;\n      }\n\n      var part = term.substr(0, i);\n      var partParams = $.extend({}, params, {\n        term: part\n      });\n\n      var data = createTag(partParams);\n\n      if (data == null) {\n        i++;\n        continue;\n      }\n\n      callback(data);\n\n      // Reset the term to not include the tokenized portion\n      term = term.substr(i + 1) || '';\n      i = 0;\n    }\n\n    return {\n      term: term\n    };\n  };\n\n  return Tokenizer;\n});\n\nS2.define('select2/data/minimumInputLength',[\n\n], function () {\n  function MinimumInputLength (decorated, $e, options) {\n    this.minimumInputLength = options.get('minimumInputLength');\n\n    decorated.call(this, $e, options);\n  }\n\n  MinimumInputLength.prototype.query = function (decorated, params, callback) {\n    params.term = params.term || '';\n\n    if (params.term.length < this.minimumInputLength) {\n      this.trigger('results:message', {\n        message: 'inputTooShort',\n        args: {\n          minimum: this.minimumInputLength,\n          input: params.term,\n          params: params\n        }\n      });\n\n      return;\n    }\n\n    decorated.call(this, params, callback);\n  };\n\n  return MinimumInputLength;\n});\n\nS2.define('select2/data/maximumInputLength',[\n\n], function () {\n  function MaximumInputLength (decorated, $e, options) {\n    this.maximumInputLength = options.get('maximumInputLength');\n\n    decorated.call(this, $e, options);\n  }\n\n  MaximumInputLength.prototype.query = function (decorated, params, callback) {\n    params.term = params.term || '';\n\n    if (this.maximumInputLength > 0 &&\n        params.term.length > this.maximumInputLength) {\n      this.trigger('results:message', {\n        message: 'inputTooLong',\n        args: {\n          maximum: this.maximumInputLength,\n          input: params.term,\n          params: params\n        }\n      });\n\n      return;\n    }\n\n    decorated.call(this, params, callback);\n  };\n\n  return MaximumInputLength;\n});\n\nS2.define('select2/data/maximumSelectionLength',[\n\n], function (){\n  function MaximumSelectionLength (decorated, $e, options) {\n    this.maximumSelectionLength = options.get('maximumSelectionLength');\n\n    decorated.call(this, $e, options);\n  }\n\n  MaximumSelectionLength.prototype.bind =\n    function (decorated, container, $container) {\n      var self = this;\n\n      decorated.call(this, container, $container);\n\n      container.on('select', function () {\n        self._checkIfMaximumSelected();\n      });\n  };\n\n  MaximumSelectionLength.prototype.query =\n    function (decorated, params, callback) {\n      var self = this;\n\n      this._checkIfMaximumSelected(function () {\n        decorated.call(self, params, callback);\n      });\n  };\n\n  MaximumSelectionLength.prototype._checkIfMaximumSelected =\n    function (_, successCallback) {\n      var self = this;\n\n      this.current(function (currentData) {\n        var count = currentData != null ? currentData.length : 0;\n        if (self.maximumSelectionLength > 0 &&\n          count >= self.maximumSelectionLength) {\n          self.trigger('results:message', {\n            message: 'maximumSelected',\n            args: {\n              maximum: self.maximumSelectionLength\n            }\n          });\n          return;\n        }\n\n        if (successCallback) {\n          successCallback();\n        }\n      });\n  };\n\n  return MaximumSelectionLength;\n});\n\nS2.define('select2/dropdown',[\n  'jquery',\n  './utils'\n], function ($, Utils) {\n  function Dropdown ($element, options) {\n    this.$element = $element;\n    this.options = options;\n\n    Dropdown.__super__.constructor.call(this);\n  }\n\n  Utils.Extend(Dropdown, Utils.Observable);\n\n  Dropdown.prototype.render = function () {\n    var $dropdown = $(\n      '<span class=\"select2-dropdown\">' +\n        '<span class=\"select2-results\"></span>' +\n      '</span>'\n    );\n\n    $dropdown.attr('dir', this.options.get('dir'));\n\n    this.$dropdown = $dropdown;\n\n    return $dropdown;\n  };\n\n  Dropdown.prototype.bind = function () {\n    // Should be implemented in subclasses\n  };\n\n  Dropdown.prototype.position = function ($dropdown, $container) {\n    // Should be implemented in subclasses\n  };\n\n  Dropdown.prototype.destroy = function () {\n    // Remove the dropdown from the DOM\n    this.$dropdown.remove();\n  };\n\n  return Dropdown;\n});\n\nS2.define('select2/dropdown/search',[\n  'jquery',\n  '../utils'\n], function ($, Utils) {\n  function Search () { }\n\n  Search.prototype.render = function (decorated) {\n    var $rendered = decorated.call(this);\n\n    var $search = $(\n      '<span class=\"select2-search select2-search--dropdown\">' +\n        '<input class=\"select2-search__field\" type=\"search\" tabindex=\"-1\"' +\n        ' autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"none\"' +\n        ' spellcheck=\"false\" role=\"searchbox\" aria-autocomplete=\"list\" />' +\n      '</span>'\n    );\n\n    this.$searchContainer = $search;\n    this.$search = $search.find('input');\n\n    $rendered.prepend($search);\n\n    return $rendered;\n  };\n\n  Search.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n\n    var resultsId = container.id + '-results';\n\n    decorated.call(this, container, $container);\n\n    this.$search.on('keydown', function (evt) {\n      self.trigger('keypress', evt);\n\n      self._keyUpPrevented = evt.isDefaultPrevented();\n    });\n\n    // Workaround for browsers which do not support the `input` event\n    // This will prevent double-triggering of events for browsers which support\n    // both the `keyup` and `input` events.\n    this.$search.on('input', function (evt) {\n      // Unbind the duplicated `keyup` event\n      $(this).off('keyup');\n    });\n\n    this.$search.on('keyup input', function (evt) {\n      self.handleSearch(evt);\n    });\n\n    container.on('open', function () {\n      self.$search.attr('tabindex', 0);\n      self.$search.attr('aria-controls', resultsId);\n\n      self.$search.trigger('focus');\n\n      window.setTimeout(function () {\n        self.$search.trigger('focus');\n      }, 0);\n    });\n\n    container.on('close', function () {\n      self.$search.attr('tabindex', -1);\n      self.$search.removeAttr('aria-controls');\n      self.$search.removeAttr('aria-activedescendant');\n\n      self.$search.val('');\n      self.$search.trigger('blur');\n    });\n\n    container.on('focus', function () {\n      if (!container.isOpen()) {\n        self.$search.trigger('focus');\n      }\n    });\n\n    container.on('results:all', function (params) {\n      if (params.query.term == null || params.query.term === '') {\n        var showSearch = self.showSearch(params);\n\n        if (showSearch) {\n          self.$searchContainer.removeClass('select2-search--hide');\n        } else {\n          self.$searchContainer.addClass('select2-search--hide');\n        }\n      }\n    });\n\n    container.on('results:focus', function (params) {\n      if (params.data._resultId) {\n        self.$search.attr('aria-activedescendant', params.data._resultId);\n      } else {\n        self.$search.removeAttr('aria-activedescendant');\n      }\n    });\n  };\n\n  Search.prototype.handleSearch = function (evt) {\n    if (!this._keyUpPrevented) {\n      var input = this.$search.val();\n\n      this.trigger('query', {\n        term: input\n      });\n    }\n\n    this._keyUpPrevented = false;\n  };\n\n  Search.prototype.showSearch = function (_, params) {\n    return true;\n  };\n\n  return Search;\n});\n\nS2.define('select2/dropdown/hidePlaceholder',[\n\n], function () {\n  function HidePlaceholder (decorated, $element, options, dataAdapter) {\n    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));\n\n    decorated.call(this, $element, options, dataAdapter);\n  }\n\n  HidePlaceholder.prototype.append = function (decorated, data) {\n    data.results = this.removePlaceholder(data.results);\n\n    decorated.call(this, data);\n  };\n\n  HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {\n    if (typeof placeholder === 'string') {\n      placeholder = {\n        id: '',\n        text: placeholder\n      };\n    }\n\n    return placeholder;\n  };\n\n  HidePlaceholder.prototype.removePlaceholder = function (_, data) {\n    var modifiedData = data.slice(0);\n\n    for (var d = data.length - 1; d >= 0; d--) {\n      var item = data[d];\n\n      if (this.placeholder.id === item.id) {\n        modifiedData.splice(d, 1);\n      }\n    }\n\n    return modifiedData;\n  };\n\n  return HidePlaceholder;\n});\n\nS2.define('select2/dropdown/infiniteScroll',[\n  'jquery'\n], function ($) {\n  function InfiniteScroll (decorated, $element, options, dataAdapter) {\n    this.lastParams = {};\n\n    decorated.call(this, $element, options, dataAdapter);\n\n    this.$loadingMore = this.createLoadingMore();\n    this.loading = false;\n  }\n\n  InfiniteScroll.prototype.append = function (decorated, data) {\n    this.$loadingMore.remove();\n    this.loading = false;\n\n    decorated.call(this, data);\n\n    if (this.showLoadingMore(data)) {\n      this.$results.append(this.$loadingMore);\n      this.loadMoreIfNeeded();\n    }\n  };\n\n  InfiniteScroll.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n\n    decorated.call(this, container, $container);\n\n    container.on('query', function (params) {\n      self.lastParams = params;\n      self.loading = true;\n    });\n\n    container.on('query:append', function (params) {\n      self.lastParams = params;\n      self.loading = true;\n    });\n\n    this.$results.on('scroll', this.loadMoreIfNeeded.bind(this));\n  };\n\n  InfiniteScroll.prototype.loadMoreIfNeeded = function () {\n    var isLoadMoreVisible = $.contains(\n      document.documentElement,\n      this.$loadingMore[0]\n    );\n\n    if (this.loading || !isLoadMoreVisible) {\n      return;\n    }\n\n    var currentOffset = this.$results.offset().top +\n      this.$results.outerHeight(false);\n    var loadingMoreOffset = this.$loadingMore.offset().top +\n      this.$loadingMore.outerHeight(false);\n\n    if (currentOffset + 50 >= loadingMoreOffset) {\n      this.loadMore();\n    }\n  };\n\n  InfiniteScroll.prototype.loadMore = function () {\n    this.loading = true;\n\n    var params = $.extend({}, {page: 1}, this.lastParams);\n\n    params.page++;\n\n    this.trigger('query:append', params);\n  };\n\n  InfiniteScroll.prototype.showLoadingMore = function (_, data) {\n    return data.pagination && data.pagination.more;\n  };\n\n  InfiniteScroll.prototype.createLoadingMore = function () {\n    var $option = $(\n      '<li ' +\n      'class=\"select2-results__option select2-results__option--load-more\"' +\n      'role=\"option\" aria-disabled=\"true\"></li>'\n    );\n\n    var message = this.options.get('translations').get('loadingMore');\n\n    $option.html(message(this.lastParams));\n\n    return $option;\n  };\n\n  return InfiniteScroll;\n});\n\nS2.define('select2/dropdown/attachBody',[\n  'jquery',\n  '../utils'\n], function ($, Utils) {\n  function AttachBody (decorated, $element, options) {\n    this.$dropdownParent = $(options.get('dropdownParent') || document.body);\n\n    decorated.call(this, $element, options);\n  }\n\n  AttachBody.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n\n    decorated.call(this, container, $container);\n\n    container.on('open', function () {\n      self._showDropdown();\n      self._attachPositioningHandler(container);\n\n      // Must bind after the results handlers to ensure correct sizing\n      self._bindContainerResultHandlers(container);\n    });\n\n    container.on('close', function () {\n      self._hideDropdown();\n      self._detachPositioningHandler(container);\n    });\n\n    this.$dropdownContainer.on('mousedown', function (evt) {\n      evt.stopPropagation();\n    });\n  };\n\n  AttachBody.prototype.destroy = function (decorated) {\n    decorated.call(this);\n\n    this.$dropdownContainer.remove();\n  };\n\n  AttachBody.prototype.position = function (decorated, $dropdown, $container) {\n    // Clone all of the container classes\n    $dropdown.attr('class', $container.attr('class'));\n\n    $dropdown.removeClass('select2');\n    $dropdown.addClass('select2-container--open');\n\n    $dropdown.css({\n      position: 'absolute',\n      top: -999999\n    });\n\n    this.$container = $container;\n  };\n\n  AttachBody.prototype.render = function (decorated) {\n    var $container = $('<span></span>');\n\n    var $dropdown = decorated.call(this);\n    $container.append($dropdown);\n\n    this.$dropdownContainer = $container;\n\n    return $container;\n  };\n\n  AttachBody.prototype._hideDropdown = function (decorated) {\n    this.$dropdownContainer.detach();\n  };\n\n  AttachBody.prototype._bindContainerResultHandlers =\n      function (decorated, container) {\n\n    // These should only be bound once\n    if (this._containerResultsHandlersBound) {\n      return;\n    }\n\n    var self = this;\n\n    container.on('results:all', function () {\n      self._positionDropdown();\n      self._resizeDropdown();\n    });\n\n    container.on('results:append', function () {\n      self._positionDropdown();\n      self._resizeDropdown();\n    });\n\n    container.on('results:message', function () {\n      self._positionDropdown();\n      self._resizeDropdown();\n    });\n\n    container.on('select', function () {\n      self._positionDropdown();\n      self._resizeDropdown();\n    });\n\n    container.on('unselect', function () {\n      self._positionDropdown();\n      self._resizeDropdown();\n    });\n\n    this._containerResultsHandlersBound = true;\n  };\n\n  AttachBody.prototype._attachPositioningHandler =\n      function (decorated, container) {\n    var self = this;\n\n    var scrollEvent = 'scroll.select2.' + container.id;\n    var resizeEvent = 'resize.select2.' + container.id;\n    var orientationEvent = 'orientationchange.select2.' + container.id;\n\n    var $watchers = this.$container.parents().filter(Utils.hasScroll);\n    $watchers.each(function () {\n      Utils.StoreData(this, 'select2-scroll-position', {\n        x: $(this).scrollLeft(),\n        y: $(this).scrollTop()\n      });\n    });\n\n    $watchers.on(scrollEvent, function (ev) {\n      var position = Utils.GetData(this, 'select2-scroll-position');\n      $(this).scrollTop(position.y);\n    });\n\n    $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,\n      function (e) {\n      self._positionDropdown();\n      self._resizeDropdown();\n    });\n  };\n\n  AttachBody.prototype._detachPositioningHandler =\n      function (decorated, container) {\n    var scrollEvent = 'scroll.select2.' + container.id;\n    var resizeEvent = 'resize.select2.' + container.id;\n    var orientationEvent = 'orientationchange.select2.' + container.id;\n\n    var $watchers = this.$container.parents().filter(Utils.hasScroll);\n    $watchers.off(scrollEvent);\n\n    $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);\n  };\n\n  AttachBody.prototype._positionDropdown = function () {\n    var $window = $(window);\n\n    var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');\n    var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');\n\n    var newDirection = null;\n\n    var offset = this.$container.offset();\n\n    offset.bottom = offset.top + this.$container.outerHeight(false);\n\n    var container = {\n      height: this.$container.outerHeight(false)\n    };\n\n    container.top = offset.top;\n    container.bottom = offset.top + container.height;\n\n    var dropdown = {\n      height: this.$dropdown.outerHeight(false)\n    };\n\n    var viewport = {\n      top: $window.scrollTop(),\n      bottom: $window.scrollTop() + $window.height()\n    };\n\n    var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);\n    var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);\n\n    var css = {\n      left: offset.left,\n      top: container.bottom\n    };\n\n    // Determine what the parent element is to use for calculating the offset\n    var $offsetParent = this.$dropdownParent;\n\n    // For statically positioned elements, we need to get the element\n    // that is determining the offset\n    if ($offsetParent.css('position') === 'static') {\n      $offsetParent = $offsetParent.offsetParent();\n    }\n\n    var parentOffset = {\n      top: 0,\n      left: 0\n    };\n\n    if (\n      $.contains(document.body, $offsetParent[0]) ||\n      $offsetParent[0].isConnected\n      ) {\n      parentOffset = $offsetParent.offset();\n    }\n\n    css.top -= parentOffset.top;\n    css.left -= parentOffset.left;\n\n    if (!isCurrentlyAbove && !isCurrentlyBelow) {\n      newDirection = 'below';\n    }\n\n    if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {\n      newDirection = 'above';\n    } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {\n      newDirection = 'below';\n    }\n\n    if (newDirection == 'above' ||\n      (isCurrentlyAbove && newDirection !== 'below')) {\n      css.top = container.top - parentOffset.top - dropdown.height;\n    }\n\n    if (newDirection != null) {\n      this.$dropdown\n        .removeClass('select2-dropdown--below select2-dropdown--above')\n        .addClass('select2-dropdown--' + newDirection);\n      this.$container\n        .removeClass('select2-container--below select2-container--above')\n        .addClass('select2-container--' + newDirection);\n    }\n\n    this.$dropdownContainer.css(css);\n  };\n\n  AttachBody.prototype._resizeDropdown = function () {\n    var css = {\n      width: this.$container.outerWidth(false) + 'px'\n    };\n\n    if (this.options.get('dropdownAutoWidth')) {\n      css.minWidth = css.width;\n      css.position = 'relative';\n      css.width = 'auto';\n    }\n\n    this.$dropdown.css(css);\n  };\n\n  AttachBody.prototype._showDropdown = function (decorated) {\n    this.$dropdownContainer.appendTo(this.$dropdownParent);\n\n    this._positionDropdown();\n    this._resizeDropdown();\n  };\n\n  return AttachBody;\n});\n\nS2.define('select2/dropdown/minimumResultsForSearch',[\n\n], function () {\n  function countResults (data) {\n    var count = 0;\n\n    for (var d = 0; d < data.length; d++) {\n      var item = data[d];\n\n      if (item.children) {\n        count += countResults(item.children);\n      } else {\n        count++;\n      }\n    }\n\n    return count;\n  }\n\n  function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {\n    this.minimumResultsForSearch = options.get('minimumResultsForSearch');\n\n    if (this.minimumResultsForSearch < 0) {\n      this.minimumResultsForSearch = Infinity;\n    }\n\n    decorated.call(this, $element, options, dataAdapter);\n  }\n\n  MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {\n    if (countResults(params.data.results) < this.minimumResultsForSearch) {\n      return false;\n    }\n\n    return decorated.call(this, params);\n  };\n\n  return MinimumResultsForSearch;\n});\n\nS2.define('select2/dropdown/selectOnClose',[\n  '../utils'\n], function (Utils) {\n  function SelectOnClose () { }\n\n  SelectOnClose.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n\n    decorated.call(this, container, $container);\n\n    container.on('close', function (params) {\n      self._handleSelectOnClose(params);\n    });\n  };\n\n  SelectOnClose.prototype._handleSelectOnClose = function (_, params) {\n    if (params && params.originalSelect2Event != null) {\n      var event = params.originalSelect2Event;\n\n      // Don't select an item if the close event was triggered from a select or\n      // unselect event\n      if (event._type === 'select' || event._type === 'unselect') {\n        return;\n      }\n    }\n\n    var $highlightedResults = this.getHighlightedResults();\n\n    // Only select highlighted results\n    if ($highlightedResults.length < 1) {\n      return;\n    }\n\n    var data = Utils.GetData($highlightedResults[0], 'data');\n\n    // Don't re-select already selected resulte\n    if (\n      (data.element != null && data.element.selected) ||\n      (data.element == null && data.selected)\n    ) {\n      return;\n    }\n\n    this.trigger('select', {\n        data: data\n    });\n  };\n\n  return SelectOnClose;\n});\n\nS2.define('select2/dropdown/closeOnSelect',[\n\n], function () {\n  function CloseOnSelect () { }\n\n  CloseOnSelect.prototype.bind = function (decorated, container, $container) {\n    var self = this;\n\n    decorated.call(this, container, $container);\n\n    container.on('select', function (evt) {\n      self._selectTriggered(evt);\n    });\n\n    container.on('unselect', function (evt) {\n      self._selectTriggered(evt);\n    });\n  };\n\n  CloseOnSelect.prototype._selectTriggered = function (_, evt) {\n    var originalEvent = evt.originalEvent;\n\n    // Don't close if the control key is being held\n    if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) {\n      return;\n    }\n\n    this.trigger('close', {\n      originalEvent: originalEvent,\n      originalSelect2Event: evt\n    });\n  };\n\n  return CloseOnSelect;\n});\n\nS2.define('select2/i18n/en',[],function () {\n  // English\n  return {\n    errorLoading: function () {\n      return '无法载入结果。';\n    },\n    inputTooLong: function (args) {\n      var overChars = args.input.length - args.maximum;\n\n      var message = '请删除' + overChars + '个字符';\n\n      if (overChars != 1) {\n        message += 's';\n      }\n\n      return message;\n    },\n    inputTooShort: function (args) {\n      var remainingChars = args.minimum - args.input.length;\n\n      var message = '请再输入至少' + remainingChars + '个字符';\n\n      return message;\n    },\n    loadingMore: function () {\n      return '载入更多结果…';\n    },\n    maximumSelected: function (args) {\n      var message = '最多只能' + args.maximum + '个选项';\n\n      if (args.maximum != 1) {\n        message += 's';\n      }\n\n      return message;\n    },\n    noResults: function () {\n      return '未找到结果';\n    },\n    searching: function () {\n      return '搜索中…';\n    },\n    removeAllItems: function () {\n      return '删除所有项目';\n    }\n  };\n});\n\nS2.define('select2/defaults',[\n  'jquery',\n  'require',\n\n  './results',\n\n  './selection/single',\n  './selection/multiple',\n  './selection/placeholder',\n  './selection/allowClear',\n  './selection/search',\n  './selection/eventRelay',\n\n  './utils',\n  './translation',\n  './diacritics',\n\n  './data/select',\n  './data/array',\n  './data/ajax',\n  './data/tags',\n  './data/tokenizer',\n  './data/minimumInputLength',\n  './data/maximumInputLength',\n  './data/maximumSelectionLength',\n\n  './dropdown',\n  './dropdown/search',\n  './dropdown/hidePlaceholder',\n  './dropdown/infiniteScroll',\n  './dropdown/attachBody',\n  './dropdown/minimumResultsForSearch',\n  './dropdown/selectOnClose',\n  './dropdown/closeOnSelect',\n\n  './i18n/en'\n], function ($, require,\n\n             ResultsList,\n\n             SingleSelection, MultipleSelection, Placeholder, AllowClear,\n             SelectionSearch, EventRelay,\n\n             Utils, Translation, DIACRITICS,\n\n             SelectData, ArrayData, AjaxData, Tags, Tokenizer,\n             MinimumInputLength, MaximumInputLength, MaximumSelectionLength,\n\n             Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,\n             AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,\n\n             EnglishTranslation) {\n  function Defaults () {\n    this.reset();\n  }\n\n  Defaults.prototype.apply = function (options) {\n    options = $.extend(true, {}, this.defaults, options);\n\n    if (options.dataAdapter == null) {\n      if (options.ajax != null) {\n        options.dataAdapter = AjaxData;\n      } else if (options.data != null) {\n        options.dataAdapter = ArrayData;\n      } else {\n        options.dataAdapter = SelectData;\n      }\n\n      if (options.minimumInputLength > 0) {\n        options.dataAdapter = Utils.Decorate(\n          options.dataAdapter,\n          MinimumInputLength\n        );\n      }\n\n      if (options.maximumInputLength > 0) {\n        options.dataAdapter = Utils.Decorate(\n          options.dataAdapter,\n          MaximumInputLength\n        );\n      }\n\n      if (options.maximumSelectionLength > 0) {\n        options.dataAdapter = Utils.Decorate(\n          options.dataAdapter,\n          MaximumSelectionLength\n        );\n      }\n\n      if (options.tags) {\n        options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);\n      }\n\n      if (options.tokenSeparators != null || options.tokenizer != null) {\n        options.dataAdapter = Utils.Decorate(\n          options.dataAdapter,\n          Tokenizer\n        );\n      }\n\n      if (options.query != null) {\n        var Query = require(options.amdBase + 'compat/query');\n\n        options.dataAdapter = Utils.Decorate(\n          options.dataAdapter,\n          Query\n        );\n      }\n\n      if (options.initSelection != null) {\n        var InitSelection = require(options.amdBase + 'compat/initSelection');\n\n        options.dataAdapter = Utils.Decorate(\n          options.dataAdapter,\n          InitSelection\n        );\n      }\n    }\n\n    if (options.resultsAdapter == null) {\n      options.resultsAdapter = ResultsList;\n\n      if (options.ajax != null) {\n        options.resultsAdapter = Utils.Decorate(\n          options.resultsAdapter,\n          InfiniteScroll\n        );\n      }\n\n      if (options.placeholder != null) {\n        options.resultsAdapter = Utils.Decorate(\n          options.resultsAdapter,\n          HidePlaceholder\n        );\n      }\n\n      if (options.selectOnClose) {\n        options.resultsAdapter = Utils.Decorate(\n          options.resultsAdapter,\n          SelectOnClose\n        );\n      }\n    }\n\n    if (options.dropdownAdapter == null) {\n      if (options.multiple) {\n        options.dropdownAdapter = Dropdown;\n      } else {\n        var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);\n\n        options.dropdownAdapter = SearchableDropdown;\n      }\n\n      if (options.minimumResultsForSearch !== 0) {\n        options.dropdownAdapter = Utils.Decorate(\n          options.dropdownAdapter,\n          MinimumResultsForSearch\n        );\n      }\n\n      if (options.closeOnSelect) {\n        options.dropdownAdapter = Utils.Decorate(\n          options.dropdownAdapter,\n          CloseOnSelect\n        );\n      }\n\n      if (\n        options.dropdownCssClass != null ||\n        options.dropdownCss != null ||\n        options.adaptDropdownCssClass != null\n      ) {\n        var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');\n\n        options.dropdownAdapter = Utils.Decorate(\n          options.dropdownAdapter,\n          DropdownCSS\n        );\n      }\n\n      options.dropdownAdapter = Utils.Decorate(\n        options.dropdownAdapter,\n        AttachBody\n      );\n    }\n\n    if (options.selectionAdapter == null) {\n      if (options.multiple) {\n        options.selectionAdapter = MultipleSelection;\n      } else {\n        options.selectionAdapter = SingleSelection;\n      }\n\n      // Add the placeholder mixin if a placeholder was specified\n      if (options.placeholder != null) {\n        options.selectionAdapter = Utils.Decorate(\n          options.selectionAdapter,\n          Placeholder\n        );\n      }\n\n      if (options.allowClear) {\n        options.selectionAdapter = Utils.Decorate(\n          options.selectionAdapter,\n          AllowClear\n        );\n      }\n\n      if (options.multiple) {\n        options.selectionAdapter = Utils.Decorate(\n          options.selectionAdapter,\n          SelectionSearch\n        );\n      }\n\n      if (\n        options.containerCssClass != null ||\n        options.containerCss != null ||\n        options.adaptContainerCssClass != null\n      ) {\n        var ContainerCSS = require(options.amdBase + 'compat/containerCss');\n\n        options.selectionAdapter = Utils.Decorate(\n          options.selectionAdapter,\n          ContainerCSS\n        );\n      }\n\n      options.selectionAdapter = Utils.Decorate(\n        options.selectionAdapter,\n        EventRelay\n      );\n    }\n\n    // If the defaults were not previously applied from an element, it is\n    // possible for the language option to have not been resolved\n    options.language = this._resolveLanguage(options.language);\n\n    // Always fall back to English since it will always be complete\n    options.language.push('en');\n\n    var uniqueLanguages = [];\n\n    for (var l = 0; l < options.language.length; l++) {\n      var language = options.language[l];\n\n      if (uniqueLanguages.indexOf(language) === -1) {\n        uniqueLanguages.push(language);\n      }\n    }\n\n    options.language = uniqueLanguages;\n\n    options.translations = this._processTranslations(\n      options.language,\n      options.debug\n    );\n\n    return options;\n  };\n\n  Defaults.prototype.reset = function () {\n    function stripDiacritics (text) {\n      // Used 'uni range + named function' from http://jsperf.com/diacritics/18\n      function match(a) {\n        return DIACRITICS[a] || a;\n      }\n\n      return text.replace(/[^\\u0000-\\u007E]/g, match);\n    }\n\n    function matcher (params, data) {\n      // Always return the object if there is nothing to compare\n      if ($.trim(params.term) === '') {\n        return data;\n      }\n\n      // Do a recursive check for options with children\n      if (data.children && data.children.length > 0) {\n        // Clone the data object if there are children\n        // This is required as we modify the object to remove any non-matches\n        var match = $.extend(true, {}, data);\n\n        // Check each child of the option\n        for (var c = data.children.length - 1; c >= 0; c--) {\n          var child = data.children[c];\n\n          var matches = matcher(params, child);\n\n          // If there wasn't a match, remove the object in the array\n          if (matches == null) {\n            match.children.splice(c, 1);\n          }\n        }\n\n        // If any children matched, return the new object\n        if (match.children.length > 0) {\n          return match;\n        }\n\n        // If there were no matching children, check just the plain object\n        return matcher(params, match);\n      }\n\n      var original = stripDiacritics(data.text).toUpperCase();\n      var term = stripDiacritics(params.term).toUpperCase();\n\n      // Check if the text contains the term\n      if (original.indexOf(term) > -1) {\n        return data;\n      }\n\n      // If it doesn't contain the term, don't return anything\n      return null;\n    }\n\n    this.defaults = {\n      amdBase: './',\n      amdLanguageBase: './i18n/',\n      closeOnSelect: true,\n      debug: false,\n      dropdownAutoWidth: false,\n      escapeMarkup: Utils.escapeMarkup,\n      language: {},\n      matcher: matcher,\n      minimumInputLength: 0,\n      maximumInputLength: 0,\n      maximumSelectionLength: 0,\n      minimumResultsForSearch: 0,\n      selectOnClose: false,\n      scrollAfterSelect: false,\n      sorter: function (data) {\n        return data;\n      },\n      templateResult: function (result) {\n        return result.text;\n      },\n      templateSelection: function (selection) {\n        return selection.text;\n      },\n      theme: 'default',\n      width: 'resolve'\n    };\n  };\n\n  Defaults.prototype.applyFromElement = function (options, $element) {\n    var optionLanguage = options.language;\n    var defaultLanguage = this.defaults.language;\n    var elementLanguage = $element.prop('lang');\n    var parentLanguage = $element.closest('[lang]').prop('lang');\n\n    var languages = Array.prototype.concat.call(\n      this._resolveLanguage(elementLanguage),\n      this._resolveLanguage(optionLanguage),\n      this._resolveLanguage(defaultLanguage),\n      this._resolveLanguage(parentLanguage)\n    );\n\n    options.language = languages;\n\n    return options;\n  };\n\n  Defaults.prototype._resolveLanguage = function (language) {\n    if (!language) {\n      return [];\n    }\n\n    if ($.isEmptyObject(language)) {\n      return [];\n    }\n\n    if ($.isPlainObject(language)) {\n      return [language];\n    }\n\n    var languages;\n\n    if (!$.isArray(language)) {\n      languages = [language];\n    } else {\n      languages = language;\n    }\n\n    var resolvedLanguages = [];\n\n    for (var l = 0; l < languages.length; l++) {\n      resolvedLanguages.push(languages[l]);\n\n      if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {\n        // Extract the region information if it is included\n        var languageParts = languages[l].split('-');\n        var baseLanguage = languageParts[0];\n\n        resolvedLanguages.push(baseLanguage);\n      }\n    }\n\n    return resolvedLanguages;\n  };\n\n  Defaults.prototype._processTranslations = function (languages, debug) {\n    var translations = new Translation();\n\n    for (var l = 0; l < languages.length; l++) {\n      var languageData = new Translation();\n\n      var language = languages[l];\n\n      if (typeof language === 'string') {\n        try {\n          // Try to load it with the original name\n          languageData = Translation.loadPath(language);\n        } catch (e) {\n          try {\n            // If we couldn't load it, check if it wasn't the full path\n            language = this.defaults.amdLanguageBase + language;\n            languageData = Translation.loadPath(language);\n          } catch (ex) {\n            // The translation could not be loaded at all. Sometimes this is\n            // because of a configuration problem, other times this can be\n            // because of how Select2 helps load all possible translation files\n            if (debug && window.console && console.warn) {\n              console.warn(\n                'Select2: The language file for \"' + language + '\" could ' +\n                'not be automatically loaded. A fallback will be used instead.'\n              );\n            }\n          }\n        }\n      } else if ($.isPlainObject(language)) {\n        languageData = new Translation(language);\n      } else {\n        languageData = language;\n      }\n\n      translations.extend(languageData);\n    }\n\n    return translations;\n  };\n\n  Defaults.prototype.set = function (key, value) {\n    var camelKey = $.camelCase(key);\n\n    var data = {};\n    data[camelKey] = value;\n\n    var convertedData = Utils._convertData(data);\n\n    $.extend(true, this.defaults, convertedData);\n  };\n\n  var defaults = new Defaults();\n\n  return defaults;\n});\n\nS2.define('select2/options',[\n  'require',\n  'jquery',\n  './defaults',\n  './utils'\n], function (require, $, Defaults, Utils) {\n  function Options (options, $element) {\n    this.options = options;\n\n    if ($element != null) {\n      this.fromElement($element);\n    }\n\n    if ($element != null) {\n      this.options = Defaults.applyFromElement(this.options, $element);\n    }\n\n    this.options = Defaults.apply(this.options);\n\n    if ($element && $element.is('input')) {\n      var InputCompat = require(this.get('amdBase') + 'compat/inputData');\n\n      this.options.dataAdapter = Utils.Decorate(\n        this.options.dataAdapter,\n        InputCompat\n      );\n    }\n  }\n\n  Options.prototype.fromElement = function ($e) {\n    var excludedData = ['select2'];\n\n    if (this.options.multiple == null) {\n      this.options.multiple = $e.prop('multiple');\n    }\n\n    if (this.options.disabled == null) {\n      this.options.disabled = $e.prop('disabled');\n    }\n\n    if (this.options.dir == null) {\n      if ($e.prop('dir')) {\n        this.options.dir = $e.prop('dir');\n      } else if ($e.closest('[dir]').prop('dir')) {\n        this.options.dir = $e.closest('[dir]').prop('dir');\n      } else {\n        this.options.dir = 'ltr';\n      }\n    }\n\n    $e.prop('disabled', this.options.disabled);\n    $e.prop('multiple', this.options.multiple);\n\n    if (Utils.GetData($e[0], 'select2Tags')) {\n      if (this.options.debug && window.console && console.warn) {\n        console.warn(\n          'Select2: The `data-select2-tags` attribute has been changed to ' +\n          'use the `data-data` and `data-tags=\"true\"` attributes and will be ' +\n          'removed in future versions of Select2.'\n        );\n      }\n\n      Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));\n      Utils.StoreData($e[0], 'tags', true);\n    }\n\n    if (Utils.GetData($e[0], 'ajaxUrl')) {\n      if (this.options.debug && window.console && console.warn) {\n        console.warn(\n          'Select2: The `data-ajax-url` attribute has been changed to ' +\n          '`data-ajax--url` and support for the old attribute will be removed' +\n          ' in future versions of Select2.'\n        );\n      }\n\n      $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));\n      Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));\n    }\n\n    var dataset = {};\n\n    function upperCaseLetter(_, letter) {\n      return letter.toUpperCase();\n    }\n\n    // Pre-load all of the attributes which are prefixed with `data-`\n    for (var attr = 0; attr < $e[0].attributes.length; attr++) {\n      var attributeName = $e[0].attributes[attr].name;\n      var prefix = 'data-';\n\n      if (attributeName.substr(0, prefix.length) == prefix) {\n        // Get the contents of the attribute after `data-`\n        var dataName = attributeName.substring(prefix.length);\n\n        // Get the data contents from the consistent source\n        // This is more than likely the jQuery data helper\n        var dataValue = Utils.GetData($e[0], dataName);\n\n        // camelCase the attribute name to match the spec\n        var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter);\n\n        // Store the data attribute contents into the dataset since\n        dataset[camelDataName] = dataValue;\n      }\n    }\n\n    // Prefer the element's `dataset` attribute if it exists\n    // jQuery 1.x does not correctly handle data attributes with multiple dashes\n    if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {\n      dataset = $.extend(true, {}, $e[0].dataset, dataset);\n    }\n\n    // Prefer our internal data cache if it exists\n    var data = $.extend(true, {}, Utils.GetData($e[0]), dataset);\n\n    data = Utils._convertData(data);\n\n    for (var key in data) {\n      if ($.inArray(key, excludedData) > -1) {\n        continue;\n      }\n\n      if ($.isPlainObject(this.options[key])) {\n        $.extend(this.options[key], data[key]);\n      } else {\n        this.options[key] = data[key];\n      }\n    }\n\n    return this;\n  };\n\n  Options.prototype.get = function (key) {\n    return this.options[key];\n  };\n\n  Options.prototype.set = function (key, val) {\n    this.options[key] = val;\n  };\n\n  return Options;\n});\n\nS2.define('select2/core',[\n  'jquery',\n  './options',\n  './utils',\n  './keys'\n], function ($, Options, Utils, KEYS) {\n  var Select2 = function ($element, options) {\n    if (Utils.GetData($element[0], 'select2') != null) {\n      Utils.GetData($element[0], 'select2').destroy();\n    }\n\n    this.$element = $element;\n\n    this.id = this._generateId($element);\n\n    options = options || {};\n\n    this.options = new Options(options, $element);\n\n    Select2.__super__.constructor.call(this);\n\n    // Set up the tabindex\n\n    var tabindex = $element.attr('tabindex') || 0;\n    Utils.StoreData($element[0], 'old-tabindex', tabindex);\n    $element.attr('tabindex', '-1');\n\n    // Set up containers and adapters\n\n    var DataAdapter = this.options.get('dataAdapter');\n    this.dataAdapter = new DataAdapter($element, this.options);\n\n    var $container = this.render();\n\n    this._placeContainer($container);\n\n    var SelectionAdapter = this.options.get('selectionAdapter');\n    this.selection = new SelectionAdapter($element, this.options);\n    this.$selection = this.selection.render();\n\n    this.selection.position(this.$selection, $container);\n\n    var DropdownAdapter = this.options.get('dropdownAdapter');\n    this.dropdown = new DropdownAdapter($element, this.options);\n    this.$dropdown = this.dropdown.render();\n\n    this.dropdown.position(this.$dropdown, $container);\n\n    var ResultsAdapter = this.options.get('resultsAdapter');\n    this.results = new ResultsAdapter($element, this.options, this.dataAdapter);\n    this.$results = this.results.render();\n\n    this.results.position(this.$results, this.$dropdown);\n\n    // Bind events\n\n    var self = this;\n\n    // Bind the container to all of the adapters\n    this._bindAdapters();\n\n    // Register any DOM event handlers\n    this._registerDomEvents();\n\n    // Register any internal event handlers\n    this._registerDataEvents();\n    this._registerSelectionEvents();\n    this._registerDropdownEvents();\n    this._registerResultsEvents();\n    this._registerEvents();\n\n    // Set the initial state\n    this.dataAdapter.current(function (initialData) {\n      self.trigger('selection:update', {\n        data: initialData\n      });\n    });\n\n    // Hide the original select\n    $element.addClass('select2-hidden-accessible');\n    $element.attr('aria-hidden', 'true');\n\n    // Synchronize any monitored attributes\n    this._syncAttributes();\n\n    Utils.StoreData($element[0], 'select2', this);\n\n    // Ensure backwards compatibility with $element.data('select2').\n    $element.data('select2', this);\n  };\n\n  Utils.Extend(Select2, Utils.Observable);\n\n  Select2.prototype._generateId = function ($element) {\n    var id = '';\n\n    if ($element.attr('id') != null) {\n      id = $element.attr('id');\n    } else if ($element.attr('name') != null) {\n      id = $element.attr('name') + '-' + Utils.generateChars(2);\n    } else {\n      id = Utils.generateChars(4);\n    }\n\n    id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n    id = 'select2-' + id;\n\n    return id;\n  };\n\n  Select2.prototype._placeContainer = function ($container) {\n    $container.insertAfter(this.$element);\n\n    var width = this._resolveWidth(this.$element, this.options.get('width'));\n\n    if (width != null) {\n      $container.css('width', width);\n    }\n  };\n\n  Select2.prototype._resolveWidth = function ($element, method) {\n    var WIDTH = /^width:(([-+]?([0-9]*\\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;\n\n    if (method == 'resolve') {\n      var styleWidth = this._resolveWidth($element, 'style');\n\n      if (styleWidth != null) {\n        return styleWidth;\n      }\n\n      return this._resolveWidth($element, 'element');\n    }\n\n    if (method == 'element') {\n      var elementWidth = $element.outerWidth(false);\n\n      if (elementWidth <= 0) {\n        return 'auto';\n      }\n\n      return elementWidth + 'px';\n    }\n\n    if (method == 'style') {\n      var style = $element.attr('style');\n\n      if (typeof(style) !== 'string') {\n        return null;\n      }\n\n      var attrs = style.split(';');\n\n      for (var i = 0, l = attrs.length; i < l; i = i + 1) {\n        var attr = attrs[i].replace(/\\s/g, '');\n        var matches = attr.match(WIDTH);\n\n        if (matches !== null && matches.length >= 1) {\n          return matches[1];\n        }\n      }\n\n      return null;\n    }\n\n    if (method == 'computedstyle') {\n      var computedStyle = window.getComputedStyle($element[0]);\n\n      return computedStyle.width;\n    }\n\n    return method;\n  };\n\n  Select2.prototype._bindAdapters = function () {\n    this.dataAdapter.bind(this, this.$container);\n    this.selection.bind(this, this.$container);\n\n    this.dropdown.bind(this, this.$container);\n    this.results.bind(this, this.$container);\n  };\n\n  Select2.prototype._registerDomEvents = function () {\n    var self = this;\n\n    this.$element.on('change.select2', function () {\n      self.dataAdapter.current(function (data) {\n        self.trigger('selection:update', {\n          data: data\n        });\n      });\n    });\n\n    this.$element.on('focus.select2', function (evt) {\n      self.trigger('focus', evt);\n    });\n\n    this._syncA = Utils.bind(this._syncAttributes, this);\n    this._syncS = Utils.bind(this._syncSubtree, this);\n\n    if (this.$element[0].attachEvent) {\n      this.$element[0].attachEvent('onpropertychange', this._syncA);\n    }\n\n    var observer = window.MutationObserver ||\n      window.WebKitMutationObserver ||\n      window.MozMutationObserver\n    ;\n\n    if (observer != null) {\n      this._observer = new observer(function (mutations) {\n        self._syncA();\n        self._syncS(null, mutations);\n      });\n      this._observer.observe(this.$element[0], {\n        attributes: true,\n        childList: true,\n        subtree: false\n      });\n    } else if (this.$element[0].addEventListener) {\n      this.$element[0].addEventListener(\n        'DOMAttrModified',\n        self._syncA,\n        false\n      );\n      this.$element[0].addEventListener(\n        'DOMNodeInserted',\n        self._syncS,\n        false\n      );\n      this.$element[0].addEventListener(\n        'DOMNodeRemoved',\n        self._syncS,\n        false\n      );\n    }\n  };\n\n  Select2.prototype._registerDataEvents = function () {\n    var self = this;\n\n    this.dataAdapter.on('*', function (name, params) {\n      self.trigger(name, params);\n    });\n  };\n\n  Select2.prototype._registerSelectionEvents = function () {\n    var self = this;\n    var nonRelayEvents = ['toggle', 'focus'];\n\n    this.selection.on('toggle', function () {\n      self.toggleDropdown();\n    });\n\n    this.selection.on('focus', function (params) {\n      self.focus(params);\n    });\n\n    this.selection.on('*', function (name, params) {\n      if ($.inArray(name, nonRelayEvents) !== -1) {\n        return;\n      }\n\n      self.trigger(name, params);\n    });\n  };\n\n  Select2.prototype._registerDropdownEvents = function () {\n    var self = this;\n\n    this.dropdown.on('*', function (name, params) {\n      self.trigger(name, params);\n    });\n  };\n\n  Select2.prototype._registerResultsEvents = function () {\n    var self = this;\n\n    this.results.on('*', function (name, params) {\n      self.trigger(name, params);\n    });\n  };\n\n  Select2.prototype._registerEvents = function () {\n    var self = this;\n\n    this.on('open', function () {\n      self.$container.addClass('select2-container--open');\n    });\n\n    this.on('close', function () {\n      self.$container.removeClass('select2-container--open');\n    });\n\n    this.on('enable', function () {\n      self.$container.removeClass('select2-container--disabled');\n    });\n\n    this.on('disable', function () {\n      self.$container.addClass('select2-container--disabled');\n    });\n\n    this.on('blur', function () {\n      self.$container.removeClass('select2-container--focus');\n    });\n\n    this.on('query', function (params) {\n      if (!self.isOpen()) {\n        self.trigger('open', {});\n      }\n\n      this.dataAdapter.query(params, function (data) {\n        self.trigger('results:all', {\n          data: data,\n          query: params\n        });\n      });\n    });\n\n    this.on('query:append', function (params) {\n      this.dataAdapter.query(params, function (data) {\n        self.trigger('results:append', {\n          data: data,\n          query: params\n        });\n      });\n    });\n\n    this.on('keypress', function (evt) {\n      var key = evt.which;\n\n      if (self.isOpen()) {\n        if (key === KEYS.ESC || key === KEYS.TAB ||\n            (key === KEYS.UP && evt.altKey)) {\n          self.close(evt);\n\n          evt.preventDefault();\n        } else if (key === KEYS.ENTER) {\n          self.trigger('results:select', {});\n\n          evt.preventDefault();\n        } else if ((key === KEYS.SPACE && evt.ctrlKey)) {\n          self.trigger('results:toggle', {});\n\n          evt.preventDefault();\n        } else if (key === KEYS.UP) {\n          self.trigger('results:previous', {});\n\n          evt.preventDefault();\n        } else if (key === KEYS.DOWN) {\n          self.trigger('results:next', {});\n\n          evt.preventDefault();\n        }\n      } else {\n        if (key === KEYS.ENTER || key === KEYS.SPACE ||\n            (key === KEYS.DOWN && evt.altKey)) {\n          self.open();\n\n          evt.preventDefault();\n        }\n      }\n    });\n  };\n\n  Select2.prototype._syncAttributes = function () {\n    this.options.set('disabled', this.$element.prop('disabled'));\n\n    if (this.isDisabled()) {\n      if (this.isOpen()) {\n        this.close();\n      }\n\n      this.trigger('disable', {});\n    } else {\n      this.trigger('enable', {});\n    }\n  };\n\n  Select2.prototype._isChangeMutation = function (evt, mutations) {\n    var changed = false;\n    var self = this;\n\n    // Ignore any mutation events raised for elements that aren't options or\n    // optgroups. This handles the case when the select element is destroyed\n    if (\n      evt && evt.target && (\n        evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'\n      )\n    ) {\n      return;\n    }\n\n    if (!mutations) {\n      // If mutation events aren't supported, then we can only assume that the\n      // change affected the selections\n      changed = true;\n    } else if (mutations.addedNodes && mutations.addedNodes.length > 0) {\n      for (var n = 0; n < mutations.addedNodes.length; n++) {\n        var node = mutations.addedNodes[n];\n\n        if (node.selected) {\n          changed = true;\n        }\n      }\n    } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {\n      changed = true;\n    } else if ($.isArray(mutations)) {\n      $.each(mutations, function(evt, mutation) {\n        if (self._isChangeMutation(evt, mutation)) {\n          // We've found a change mutation.\n          // Let's escape from the loop and continue\n          changed = true;\n          return false;\n        }\n      });\n    }\n    return changed;\n  };\n\n  Select2.prototype._syncSubtree = function (evt, mutations) {\n    var changed = this._isChangeMutation(evt, mutations);\n    var self = this;\n\n    // Only re-pull the data if we think there is a change\n    if (changed) {\n      this.dataAdapter.current(function (currentData) {\n        self.trigger('selection:update', {\n          data: currentData\n        });\n      });\n    }\n  };\n\n  /**\n   * Override the trigger method to automatically trigger pre-events when\n   * there are events that can be prevented.\n   */\n  Select2.prototype.trigger = function (name, args) {\n    var actualTrigger = Select2.__super__.trigger;\n    var preTriggerMap = {\n      'open': 'opening',\n      'close': 'closing',\n      'select': 'selecting',\n      'unselect': 'unselecting',\n      'clear': 'clearing'\n    };\n\n    if (args === undefined) {\n      args = {};\n    }\n\n    if (name in preTriggerMap) {\n      var preTriggerName = preTriggerMap[name];\n      var preTriggerArgs = {\n        prevented: false,\n        name: name,\n        args: args\n      };\n\n      actualTrigger.call(this, preTriggerName, preTriggerArgs);\n\n      if (preTriggerArgs.prevented) {\n        args.prevented = true;\n\n        return;\n      }\n    }\n\n    actualTrigger.call(this, name, args);\n  };\n\n  Select2.prototype.toggleDropdown = function () {\n    if (this.isDisabled()) {\n      return;\n    }\n\n    if (this.isOpen()) {\n      this.close();\n    } else {\n      this.open();\n    }\n  };\n\n  Select2.prototype.open = function () {\n    if (this.isOpen()) {\n      return;\n    }\n\n    if (this.isDisabled()) {\n      return;\n    }\n\n    this.trigger('query', {});\n  };\n\n  Select2.prototype.close = function (evt) {\n    if (!this.isOpen()) {\n      return;\n    }\n\n    this.trigger('close', { originalEvent : evt });\n  };\n\n  /**\n   * Helper method to abstract the \"enabled\" (not \"disabled\") state of this\n   * object.\n   *\n   * @return {true} if the instance is not disabled.\n   * @return {false} if the instance is disabled.\n   */\n  Select2.prototype.isEnabled = function () {\n    return !this.isDisabled();\n  };\n\n  /**\n   * Helper method to abstract the \"disabled\" state of this object.\n   *\n   * @return {true} if the disabled option is true.\n   * @return {false} if the disabled option is false.\n   */\n  Select2.prototype.isDisabled = function () {\n    return this.options.get('disabled');\n  };\n\n  Select2.prototype.isOpen = function () {\n    return this.$container.hasClass('select2-container--open');\n  };\n\n  Select2.prototype.hasFocus = function () {\n    return this.$container.hasClass('select2-container--focus');\n  };\n\n  Select2.prototype.focus = function (data) {\n    // No need to re-trigger focus events if we are already focused\n    if (this.hasFocus()) {\n      return;\n    }\n\n    this.$container.addClass('select2-container--focus');\n    this.trigger('focus', {});\n  };\n\n  Select2.prototype.enable = function (args) {\n    if (this.options.get('debug') && window.console && console.warn) {\n      console.warn(\n        'Select2: The `select2(\"enable\")` method has been deprecated and will' +\n        ' be removed in later Select2 versions. Use $element.prop(\"disabled\")' +\n        ' instead.'\n      );\n    }\n\n    if (args == null || args.length === 0) {\n      args = [true];\n    }\n\n    var disabled = !args[0];\n\n    this.$element.prop('disabled', disabled);\n  };\n\n  Select2.prototype.data = function () {\n    if (this.options.get('debug') &&\n        arguments.length > 0 && window.console && console.warn) {\n      console.warn(\n        'Select2: Data can no longer be set using `select2(\"data\")`. You ' +\n        'should consider setting the value instead using `$element.val()`.'\n      );\n    }\n\n    var data = [];\n\n    this.dataAdapter.current(function (currentData) {\n      data = currentData;\n    });\n\n    return data;\n  };\n\n  Select2.prototype.val = function (args) {\n    if (this.options.get('debug') && window.console && console.warn) {\n      console.warn(\n        'Select2: The `select2(\"val\")` method has been deprecated and will be' +\n        ' removed in later Select2 versions. Use $element.val() instead.'\n      );\n    }\n\n    if (args == null || args.length === 0) {\n      return this.$element.val();\n    }\n\n    var newVal = args[0];\n\n    if ($.isArray(newVal)) {\n      newVal = $.map(newVal, function (obj) {\n        return obj.toString();\n      });\n    }\n\n    this.$element.val(newVal).trigger('input').trigger('change');\n  };\n\n  Select2.prototype.destroy = function () {\n    this.$container.remove();\n\n    if (this.$element[0].detachEvent) {\n      this.$element[0].detachEvent('onpropertychange', this._syncA);\n    }\n\n    if (this._observer != null) {\n      this._observer.disconnect();\n      this._observer = null;\n    } else if (this.$element[0].removeEventListener) {\n      this.$element[0]\n        .removeEventListener('DOMAttrModified', this._syncA, false);\n      this.$element[0]\n        .removeEventListener('DOMNodeInserted', this._syncS, false);\n      this.$element[0]\n        .removeEventListener('DOMNodeRemoved', this._syncS, false);\n    }\n\n    this._syncA = null;\n    this._syncS = null;\n\n    this.$element.off('.select2');\n    this.$element.attr('tabindex',\n    Utils.GetData(this.$element[0], 'old-tabindex'));\n\n    this.$element.removeClass('select2-hidden-accessible');\n    this.$element.attr('aria-hidden', 'false');\n    Utils.RemoveData(this.$element[0]);\n    this.$element.removeData('select2');\n\n    this.dataAdapter.destroy();\n    this.selection.destroy();\n    this.dropdown.destroy();\n    this.results.destroy();\n\n    this.dataAdapter = null;\n    this.selection = null;\n    this.dropdown = null;\n    this.results = null;\n  };\n\n  Select2.prototype.render = function () {\n    var $container = $(\n      '<span class=\"select2 select2-container\">' +\n        '<span class=\"selection\"></span>' +\n        '<span class=\"dropdown-wrapper\" aria-hidden=\"true\"></span>' +\n      '</span>'\n    );\n\n    $container.attr('dir', this.options.get('dir'));\n\n    this.$container = $container;\n\n    this.$container.addClass('select2-container--' + this.options.get('theme'));\n\n    Utils.StoreData($container[0], 'element', this.$element);\n\n    return $container;\n  };\n\n  return Select2;\n});\n\nS2.define('jquery-mousewheel',[\n  'jquery'\n], function ($) {\n  // Used to shim jQuery.mousewheel for non-full builds.\n  return $;\n});\n\nS2.define('jquery.select2',[\n  'jquery',\n  'jquery-mousewheel',\n\n  './select2/core',\n  './select2/defaults',\n  './select2/utils'\n], function ($, _, Select2, Defaults, Utils) {\n  if ($.fn.select2 == null) {\n    // All methods that should return the element\n    var thisMethods = ['open', 'close', 'destroy'];\n\n    $.fn.select2 = function (options) {\n      options = options || {};\n\n      if (typeof options === 'object') {\n        this.each(function () {\n          var instanceOptions = $.extend(true, {}, options);\n\n          var instance = new Select2($(this), instanceOptions);\n        });\n\n        return this;\n      } else if (typeof options === 'string') {\n        var ret;\n        var args = Array.prototype.slice.call(arguments, 1);\n\n        this.each(function () {\n          var instance = Utils.GetData(this, 'select2');\n\n          if (instance == null && window.console && console.error) {\n            console.error(\n              'The select2(\\'' + options + '\\') method was called on an ' +\n              'element that is not using Select2.'\n            );\n          }\n\n          ret = instance[options].apply(instance, args);\n        });\n\n        // Check if we should be returning `this`\n        if ($.inArray(options, thisMethods) > -1) {\n          return this;\n        }\n\n        return ret;\n      } else {\n        throw new Error('Invalid arguments for Select2: ' + options);\n      }\n    };\n  }\n\n  if ($.fn.select2.defaults == null) {\n    $.fn.select2.defaults = Defaults;\n  }\n\n  return Select2;\n});\n\n  // Return the AMD loader configuration so it can be used outside of this file\n  return {\n    define: S2.define,\n    require: S2.require\n  };\n}());\n\n  // Autoload the jQuery bindings\n  // We know that all of the modules exist above this, so we're safe\n  var select2 = S2.require('jquery.select2');\n\n  // Hold the AMD module references on the jQuery function that was just loaded\n  // This allows Select2 to use the internal loader outside of this file, such\n  // as in the language files.\n  jQuery.fn.select2.amd = S2;\n\n  // Return the Select2 instance for anyone who is importing it.\n  return select2;\n}));\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/suggest/bootstrap-suggest.js",
    "content": "/**\r\n * bootstrap-suggest-plugin - v0.1.29\r\n * @description 这是一个基于 bootstrap 按钮式下拉菜单组件的搜索建议插件，必须使用于按钮式下拉菜单组件上。\r\n * @author lzwme - https://lzw.me\r\n * @GitHub https://github.com/lzwme/bootstrap-suggest-plugin.git\r\n * @since 2019-11-18 09:30:06\r\n */\r\n(function(factory) {\r\n  if (typeof define === \"function\" && define.amd) {\r\n    define([\"jquery\"], factory);\r\n  } else if (typeof exports === \"object\" && typeof module === \"object\") {\r\n    factory(require(\"jquery\"));\r\n  } else if (window.jQuery) {\r\n    factory(window.jQuery);\r\n  } else {\r\n    throw new Error(\"Not found jQuery.\");\r\n  }\r\n})(function($) {\r\n  var VERSION = \"VERSION_PLACEHOLDER\";\r\n  var $window = $(window);\r\n  var isIe = \"ActiveXObject\" in window; // 用于对 IE 的兼容判断\r\n  var inputLock; // 用于中文输入法输入时锁定搜索\r\n\r\n  // ie 下和 chrome 51 以上浏览器版本，出现滚动条时不计算 padding\r\n  var chromeVer = navigator.userAgent.match(/Chrome\\/(\\d+)/);\r\n  if (chromeVer) {\r\n    chromeVer = +chromeVer[1];\r\n  }\r\n  var notNeedCalcPadding = isIe || chromeVer > 51;\r\n\r\n  // 一些常量\r\n  var BSSUGGEST = \"bsSuggest\";\r\n  var onDataRequestSuccess = \"onDataRequestSuccess\";\r\n  var DISABLED = \"disabled\";\r\n  var TRUE = true;\r\n  var FALSE = false;\r\n\r\n  function isUndefined(val) {\r\n    return val === void 0;\r\n  }\r\n\r\n  /**\r\n   * 错误处理\r\n   */\r\n  function handleError(e1, e2) {\r\n    if (!window.console || !window.console.trace) {\r\n      return;\r\n    }\r\n    console.trace(e1);\r\n    if (e2) {\r\n      console.trace(e2);\r\n    }\r\n  }\r\n  /**\r\n   * 获取当前 tr 列的关键字数据\r\n   */\r\n  function getPointKeyword($list) {\r\n    return $list.data();\r\n  }\r\n  /**\r\n   * 设置或获取输入框的 alt 值\r\n   */\r\n  function setOrGetAlt($input, val) {\r\n    return isUndefined(val) ? $input.attr(\"alt\") : $input.attr(\"alt\", val);\r\n  }\r\n  /**\r\n   * 设置或获取输入框的 data-id 值\r\n   */\r\n  function setOrGetDataId($input, val) {\r\n    return val !== void 0\r\n      ? $input.attr(\"data-id\", val)\r\n      : $input.attr(\"data-id\");\r\n  }\r\n  /**\r\n   * 设置选中的值\r\n   */\r\n  function setValue($input, keywords, options) {\r\n    if (!keywords || !keywords.key) {\r\n      return;\r\n    }\r\n\r\n    var separator = options.separator || \",\",\r\n      inputValList,\r\n      inputIdList,\r\n      dataId = setOrGetDataId($input);\r\n\r\n    if (options && options.multiWord) {\r\n      inputValList = $input.val().split(separator);\r\n      inputValList[inputValList.length - 1] = keywords.key;\r\n\r\n      //多关键字检索支持设置id --- 存在 bug，不建议使用\r\n      if (!dataId) {\r\n        inputIdList = [keywords.id];\r\n      } else {\r\n        inputIdList = dataId.split(separator);\r\n        inputIdList.push(keywords.id);\r\n      }\r\n\r\n      setOrGetDataId($input, inputIdList.join(separator))\r\n        .val(inputValList.join(separator))\r\n        .focus();\r\n    } else {\r\n      setOrGetDataId($input, keywords.id || \"\")\r\n        .val(keywords.key)\r\n        .focus();\r\n    }\r\n\r\n    $input\r\n      .data(\"pre-val\", $input.val())\r\n      .trigger(\"onSetSelectValue\", [\r\n        keywords,\r\n        (options.data.value || options._lastData.value)[keywords.index]\r\n      ]);\r\n  }\r\n  /**\r\n   * 调整选择菜单位置\r\n   * @param {Object} $input\r\n   * @param {Object} $dropdownMenu\r\n   * @param {Object} options\r\n   */\r\n  function adjustDropMenuPos($input, $dropdownMenu, options) {\r\n    if (!$dropdownMenu.is(\":visible\")) {\r\n      return;\r\n    }\r\n\r\n    var $parent = $input.parent();\r\n    var parentHeight = $parent.height();\r\n    var parentWidth = $parent.width();\r\n\r\n    if (options.autoDropup) {\r\n      setTimeout(function() {\r\n        var offsetTop = $input.offset().top;\r\n        var winScrollTop = $window.scrollTop();\r\n        var menuHeight = $dropdownMenu.height();\r\n\r\n        if (\r\n          // 自动判断菜单向上展开\r\n          $window.height() + winScrollTop - offsetTop < menuHeight && // 假如向下会撑长页面\r\n          offsetTop > menuHeight + winScrollTop // 而且向上不会撑到顶部\r\n        ) {\r\n          $parent.addClass(\"dropup\");\r\n        } else {\r\n          $parent.removeClass(\"dropup\");\r\n        }\r\n      }, 10);\r\n    }\r\n\r\n    // 列表对齐方式\r\n    var dmcss = {};\r\n    if (options.listAlign === \"left\") {\r\n      dmcss = {\r\n        left: $input.siblings(\"div\").width() - parentWidth,\r\n        right: \"auto\"\r\n      };\r\n    } else if (options.listAlign === \"right\") {\r\n      dmcss = {\r\n        left: \"auto\",\r\n        right: 0\r\n      };\r\n    }\r\n\r\n    // ie 下，不显示按钮时的 top/bottom\r\n    if (isIe && !options.showBtn) {\r\n      if (!$parent.hasClass(\"dropup\")) {\r\n        dmcss.top = parentHeight;\r\n        dmcss.bottom = \"auto\";\r\n      } else {\r\n        dmcss.top = \"auto\";\r\n        dmcss.bottom = parentHeight;\r\n      }\r\n    }\r\n\r\n    // 是否自动最小宽度\r\n    if (!options.autoMinWidth) {\r\n      dmcss.minWidth = parentWidth;\r\n    }\r\n    /* else {\r\n            dmcss['width'] = 'auto';\r\n        }*/\r\n\r\n    $dropdownMenu.css(dmcss);\r\n\r\n    return $input;\r\n  }\r\n  /**\r\n   * 设置输入框背景色\r\n   * 当设置了 indexId，而输入框的 data-id 为空时，输入框加载警告色\r\n   */\r\n  function setBackground($input, options) {\r\n    var inputbg, bg, warnbg;\r\n    if ((options.indexId === -1 && !options.idField) || options.multiWord) {\r\n      return $input;\r\n    }\r\n\r\n    bg = options.inputBgColor;\r\n    warnbg = options.inputWarnColor;\r\n\r\n    var curVal = $input.val();\r\n    var preVal = $input.data(\"pre-val\");\r\n\r\n    if (setOrGetDataId($input) || !curVal) {\r\n      $input.css(\"background\", bg || \"\");\r\n\r\n      if (!curVal && preVal) {\r\n        $input.trigger(\"onUnsetSelectValue\").data(\"pre-val\", \"\");\r\n      }\r\n\r\n      return $input;\r\n    }\r\n\r\n    inputbg = $input\r\n      .css(\"backgroundColor\")\r\n      .replace(/ /g, \"\")\r\n      .split(\",\", 3)\r\n      .join(\",\");\r\n    // 自由输入的内容，设置背景色\r\n    if (!~warnbg.indexOf(inputbg)) {\r\n      $input\r\n        .trigger(\"onUnsetSelectValue\") // 触发取消data-id事件\r\n        .data(\"pre-val\", \"\")\r\n        .css(\"background\", warnbg);\r\n    }\r\n\r\n    return $input;\r\n  }\r\n  /**\r\n   * 调整滑动条\r\n   */\r\n  function adjustScroll($input, $dropdownMenu, options) {\r\n    // 控制滑动条\r\n    var $hover = $input.parent().find(\"tbody tr.\" + options.listHoverCSS),\r\n      pos,\r\n      maxHeight;\r\n\r\n    if ($hover.length) {\r\n      pos = ($hover.index() + 3) * $hover.height();\r\n      maxHeight = +$dropdownMenu.css(\"maxHeight\").replace(\"px\", \"\");\r\n\r\n      if (pos > maxHeight || $dropdownMenu.scrollTop() > maxHeight) {\r\n        pos = pos - maxHeight;\r\n      } else {\r\n        pos = 0;\r\n      }\r\n\r\n      $dropdownMenu.scrollTop(pos);\r\n    }\r\n  }\r\n  /**\r\n   * 解除所有列表 hover 样式\r\n   */\r\n  function unHoverAll($dropdownMenu, options) {\r\n    $dropdownMenu\r\n      .find(\"tr.\" + options.listHoverCSS)\r\n      .removeClass(options.listHoverCSS);\r\n  }\r\n  /**\r\n   * 验证 $input 对象是否符合条件\r\n   *   1. 必须为 bootstrap 下拉式菜单\r\n   *   2. 必须未初始化过\r\n   */\r\n  function checkInput($input, $dropdownMenu, options) {\r\n    if (\r\n      !$dropdownMenu.length || // 过滤非 bootstrap 下拉式菜单对象\r\n      $input.data(BSSUGGEST) // 是否已经初始化的检测\r\n    ) {\r\n      return FALSE;\r\n    }\r\n\r\n    $input.data(BSSUGGEST, {\r\n      options: options\r\n    });\r\n\r\n    return TRUE;\r\n  }\r\n  /**\r\n   * 数据格式检测\r\n   * 检测 ajax 返回成功数据或 data 参数数据是否有效\r\n   * data 格式：{\"value\": [{}, {}...]}\r\n   */\r\n  function checkData(data) {\r\n    var isEmpty = TRUE,\r\n      o;\r\n\r\n    for (o in data) {\r\n      if (o === \"value\") {\r\n        isEmpty = FALSE;\r\n        break;\r\n      }\r\n    }\r\n    if (isEmpty) {\r\n      handleError(\"返回数据格式错误!\");\r\n      return FALSE;\r\n    }\r\n    if (!data.value.length) {\r\n      // handleError('返回数据为空!');\r\n      return FALSE;\r\n    }\r\n\r\n    return data;\r\n  }\r\n  /**\r\n   * 判断字段名是否在 options.effectiveFields 配置项中\r\n   * @param  {String} field   要判断的字段名\r\n   * @param  {Object} options\r\n   * @return {Boolean}        effectiveFields 为空时始终返回 true\r\n   */\r\n  function inEffectiveFields(field, options) {\r\n    var effectiveFields = options.effectiveFields;\r\n\r\n    return !(\r\n      field === \"__index\" ||\r\n      (effectiveFields.length && !~$.inArray(field, effectiveFields))\r\n    );\r\n  }\r\n  /**\r\n   * 判断字段名是否在 options.searchFields 搜索字段配置中\r\n   */\r\n  function inSearchFields(field, options) {\r\n    return ~$.inArray(field, options.searchFields);\r\n  }\r\n  /**\r\n   * 通过下拉菜单显示提示文案\r\n   */\r\n  function showTip(tip, $input, $dropdownMenu, options) {\r\n    $dropdownMenu\r\n      .html('<div style=\"padding:10px 5px 5px\">' + tip + \"</div>\")\r\n      .show();\r\n    adjustDropMenuPos($input, $dropdownMenu, options);\r\n  }\r\n  /**\r\n   * 显示下拉列表\r\n   */\r\n  function showDropMenu($input, options) {\r\n    var $dropdownMenu = $input.parent().find(\"ul:eq(0)\");\r\n    if (!$dropdownMenu.is(\":visible\")) {\r\n      // $dropdownMenu.css('display', 'block');\r\n      $dropdownMenu.show();\r\n      $input.trigger(\"onShowDropdown\", [options ? options.data.value : []]);\r\n    }\r\n  }\r\n  /**\r\n   * 隐藏下拉列表\r\n   */\r\n  function hideDropMenu($input, options) {\r\n    var $dropdownMenu = $input.parent().find(\"ul:eq(0)\");\r\n    if ($dropdownMenu.is(\":visible\")) {\r\n      // $dropdownMenu.css('display', '');\r\n      $dropdownMenu.hide();\r\n      $input.trigger(\"onHideDropdown\", [options ? options.data.value : []]);\r\n    }\r\n  }\r\n  /**\r\n   * 下拉列表刷新\r\n   * 作为 fnGetData 的 callback 函数调用\r\n   */\r\n  function refreshDropMenu($input, data, options) {\r\n    var $dropdownMenu = $input.parent().find(\"ul:eq(0)\"),\r\n      len,\r\n      i,\r\n      field,\r\n      index = 0,\r\n      tds,\r\n      html = [\r\n        '<table class=\"table table-condensed table-sm\" style=\"margin:0\">'\r\n      ],\r\n      idValue,\r\n      keyValue; // 作为输入框 data-id 和内容的字段值\r\n    var dataList = data.value;\r\n\r\n    if (!data || !(len = dataList.length)) {\r\n      if (options.emptyTip) {\r\n        showTip(options.emptyTip, $input, $dropdownMenu, options);\r\n      } else {\r\n        $dropdownMenu.empty();\r\n        hideDropMenu($input, options);\r\n      }\r\n      return $input;\r\n    }\r\n\r\n    // 相同数据，不用继续渲染了\r\n    if (\r\n      options._lastData &&\r\n      JSON.stringify(options._lastData) === JSON.stringify(data) &&\r\n      $dropdownMenu.find(\"tr\").length === len\r\n    ) {\r\n      showDropMenu($input, options);\r\n      return adjustDropMenuPos($input, $dropdownMenu, options);\r\n    }\r\n    options._lastData = data;\r\n\r\n    /** 显示于列表中的字段 */\r\n    var columns = options.effectiveFields.length\r\n      ? options.effectiveFields\r\n      : $.map(dataList[0], function(val, key) {\r\n          return key;\r\n        });\r\n\r\n    // 生成表头\r\n    if (options.showHeader) {\r\n      html.push(\"<thead><tr>\");\r\n      $.each(columns, function(index, field) {\r\n        if (!inEffectiveFields(field, options)) return;\r\n\r\n        html.push(\r\n          \"<th>\",\r\n          options.effectiveFieldsAlias[field] || field,\r\n          index === 0 ? \"(\" + len + \")\" : \"\", // 表头第一列记录总数\r\n          \"</th>\"\r\n        );\r\n\r\n        index++;\r\n      });\r\n      html.push(\"</tr></thead>\");\r\n    }\r\n    html.push(\"<tbody>\");\r\n\r\n    // console.log(data, len);\r\n    // 按列加数据\r\n    var dataI;\r\n    var maxOptionCount = Math.min(options.maxOptionCount, len);\r\n    for (i = 0; i < maxOptionCount; i++) {\r\n      index = 0;\r\n      tds = [];\r\n      dataI = dataList[i];\r\n      idValue = dataI[options.idField];\r\n      keyValue = dataI[options.keyField];\r\n\r\n      for (field in dataI) {\r\n        // 标记作为 value 和 作为 id 的值\r\n        if (isUndefined(keyValue) && options.indexKey === index) {\r\n          keyValue = dataI[field];\r\n        }\r\n        if (isUndefined(idValue) && options.indexId === index) {\r\n          idValue = dataI[field];\r\n        }\r\n        index++;\r\n      }\r\n\r\n      $.each(columns, function(index, field) {\r\n        // 列表中只显示有效的字段\r\n        if (inEffectiveFields(field, options)) {\r\n          tds.push('<td data-name=\"', field, '\">', dataI[field], \"</td>\");\r\n        }\r\n      });\r\n\r\n      html.push(\r\n        '<tr data-index=\"',\r\n        dataI.__index || i,\r\n        '\" data-id=\"',\r\n        idValue,\r\n        '\" data-key=\"',\r\n        keyValue,\r\n        '\">',\r\n        tds.join(\"\"),\r\n        \"</tr>\"\r\n      );\r\n    }\r\n    html.push(\"</tbody></table>\");\r\n\r\n    $dropdownMenu.html(html.join(\"\"));\r\n    showDropMenu($input, options);\r\n    //.show();\r\n\r\n    // scrollbar 存在时，延时到动画结束时调整 padding\r\n    setTimeout(function() {\r\n      if (notNeedCalcPadding) {\r\n        return;\r\n      }\r\n\r\n      var $table = $dropdownMenu.find(\"table:eq(0)\"),\r\n        pdr = 0,\r\n        mgb = 0;\r\n\r\n      if (\r\n        $dropdownMenu.height() < $table.height() &&\r\n        +$dropdownMenu.css(\"minWidth\").replace(\"px\", \"\") < $dropdownMenu.width()\r\n      ) {\r\n        pdr = 18;\r\n        mgb = 20;\r\n      }\r\n\r\n      $dropdownMenu.css(\"paddingRight\", pdr);\r\n      $table.css(\"marginBottom\", mgb);\r\n    }, 301);\r\n\r\n    adjustDropMenuPos($input, $dropdownMenu, options);\r\n\r\n    return $input;\r\n  }\r\n  /**\r\n   * ajax 获取数据\r\n   * @param  {Object} options\r\n   * @return {Object}         $.Deferred\r\n   */\r\n  function ajax(options, keyword) {\r\n    keyword = keyword || \"\";\r\n\r\n    var preAjax = options._preAjax;\r\n\r\n    if (preAjax && preAjax.abort && preAjax.readyState !== 4) {\r\n      // console.log('abort pre ajax');\r\n      preAjax.abort();\r\n    }\r\n\r\n    var ajaxParam = {\r\n      type: \"GET\",\r\n      dataType: options.jsonp ? \"jsonp\" : \"json\",\r\n      timeout: 5000\r\n    };\r\n\r\n    // jsonp\r\n    if (options.jsonp) {\r\n      ajaxParam.jsonp = options.jsonp;\r\n    }\r\n\r\n    // 自定义 ajax 请求参数生成方法\r\n    var adjustAjaxParam,\r\n      fnAdjustAjaxParam = options.fnAdjustAjaxParam;\r\n\r\n    if ($.isFunction(fnAdjustAjaxParam)) {\r\n      adjustAjaxParam = fnAdjustAjaxParam(keyword, options);\r\n\r\n      // options.fnAdjustAjaxParam 返回false，则终止 ajax 请求\r\n      if (FALSE === adjustAjaxParam) {\r\n        return;\r\n      }\r\n\r\n      $.extend(ajaxParam, adjustAjaxParam);\r\n    }\r\n\r\n    // url 调整\r\n    ajaxParam.url = (function() {\r\n      if (!keyword || ajaxParam.data) {\r\n        return ajaxParam.url || options.url;\r\n      }\r\n\r\n      var type = \"?\";\r\n      if (/=$/.test(options.url)) {\r\n        type = \"\";\r\n      } else if (/\\?/.test(options.url)) {\r\n        type = \"&\";\r\n      }\r\n\r\n      return options.url + type + encodeURIComponent(keyword);\r\n    })();\r\n\r\n    return (options._preAjax = $.ajax(ajaxParam)\r\n      .done(function(result) {\r\n        options.data = options.fnProcessData(result);\r\n      })\r\n      .fail(function(err) {\r\n        if (options.fnAjaxFail) {\r\n          options.fnAjaxFail(err, options);\r\n        }\r\n      }));\r\n  }\r\n  /**\r\n   * 检测 keyword 与 value 是否存在互相包含\r\n   * @param  {String}  keyword 用户输入的关键字\r\n   * @param  {String}  key     匹配字段的 key\r\n   * @param  {String}  value   key 字段对应的值\r\n   * @param  {Object}  options\r\n   * @return {Boolean}         包含/不包含\r\n   */\r\n  function isInWord(keyword, key, value, options) {\r\n    value = $.trim(value);\r\n\r\n    if (options.ignorecase) {\r\n      keyword = keyword.toLocaleLowerCase();\r\n      value = value.toLocaleLowerCase();\r\n    }\r\n\r\n    return (\r\n      value &&\r\n      (inEffectiveFields(key, options) || inSearchFields(key, options)) && // 必须在有效的搜索字段中\r\n      (~value.indexOf(keyword) || // 匹配值包含关键字\r\n        (options.twoWayMatch && ~keyword.indexOf(value))) // 关键字包含匹配值\r\n    );\r\n  }\r\n  /**\r\n   * 通过 ajax 或 json 参数获取数据\r\n   */\r\n  function getData(keyword, $input, callback, options) {\r\n    var data,\r\n      validData,\r\n      filterData = {\r\n        value: []\r\n      },\r\n      i,\r\n      key,\r\n      len,\r\n      fnPreprocessKeyword = options.fnPreprocessKeyword;\r\n\r\n    keyword = keyword || \"\";\r\n    // 获取数据前对关键字预处理方法\r\n    if ($.isFunction(fnPreprocessKeyword)) {\r\n      keyword = fnPreprocessKeyword(keyword, options);\r\n    }\r\n\r\n    // 给了url参数，则从服务器 ajax 请求\r\n    // console.log(options.url + keyword);\r\n    if (options.url) {\r\n      var timer;\r\n      if (options.searchingTip) {\r\n        timer = setTimeout(function() {\r\n          showTip(\r\n            options.searchingTip,\r\n            $input,\r\n            $input.parent().find(\"ul\"),\r\n            options\r\n          );\r\n        }, 600);\r\n      }\r\n\r\n      ajax(options, keyword)\r\n        .done(function(result) {\r\n          callback($input, options.data, options); // 为 refreshDropMenu\r\n          $input.trigger(onDataRequestSuccess, result);\r\n          if (options.getDataMethod === \"firstByUrl\") {\r\n            options.url = null;\r\n          }\r\n        })\r\n        .always(function() {\r\n          timer && clearTimeout(timer);\r\n        });\r\n    } else {\r\n      // 没有给出 url 参数，则从 data 参数获取\r\n      data = options.data;\r\n      validData = checkData(data);\r\n      // 本地的 data 数据，则在本地过滤\r\n      if (validData) {\r\n        if (keyword) {\r\n          // 输入不为空时则进行匹配\r\n          len = data.value.length;\r\n          for (i = 0; i < len; i++) {\r\n            for (key in data.value[i]) {\r\n              if (\r\n                data.value[i][key] &&\r\n                isInWord(keyword, key, data.value[i][key] + \"\", options)\r\n              ) {\r\n                filterData.value.push(data.value[i]);\r\n                filterData.value[filterData.value.length - 1].__index = i;\r\n                break;\r\n              }\r\n            }\r\n          }\r\n        } else {\r\n          filterData = data;\r\n        }\r\n      }\r\n\r\n      callback($input, filterData, options);\r\n    } // else\r\n  }\r\n  /**\r\n   * 数据处理\r\n   * url 获取数据时，对数据的处理，作为 fnGetData 之后的回调处理\r\n   */\r\n  function processData(data) {\r\n    return checkData(data);\r\n  }\r\n  /**\r\n   * 取得 clearable 清除按钮\r\n   */\r\n  function getIClear($input, options) {\r\n    var $iClear = $input.prev(\"i.clearable\");\r\n\r\n    // 是否可清除已输入的内容(添加清除按钮)\r\n    if (options.clearable && !$iClear.length) {\r\n      $iClear = $(\r\n        '<i class=\"clearable glyphicon glyphicon-remove fa fa-plus\"></i>'\r\n      ).prependTo($input.parent());\r\n    }\r\n\r\n    return $iClear\r\n      .css({\r\n        position: \"absolute\",\r\n        top: \"calc(50% - 6px)\",\r\n        transform: \"rotate(45deg)\",\r\n        // right: options.showBtn ? Math.max($input.next('.input-group-btn').width(), 33) + 2 : 12,\r\n        zIndex: 4,\r\n        cursor: \"pointer\",\r\n        width: \"14px\",\r\n        lineHeight: \"14px\",\r\n        textAlign: \"center\",\r\n        fontSize: 12\r\n      })\r\n      .hide();\r\n  }\r\n  /**\r\n   * 默认的配置选项\r\n   * @type {Object}\r\n   */\r\n  var defaultOptions = {\r\n    url: null, // 请求数据的 URL 地址\r\n    jsonp: null, // 设置此参数名，将开启jsonp功能，否则使用json数据结构\r\n    data: {\r\n      value: []\r\n    }, // 提示所用的数据，注意格式\r\n    indexId: 0, // 每组数据的第几个数据，作为input输入框的 data-id，设为 -1 且 idField 为空则不设置此值\r\n    indexKey: 0, // 每组数据的第几个数据，作为input输入框的内容\r\n    idField: \"\", // 每组数据的哪个字段作为 data-id，优先级高于 indexId 设置（推荐）\r\n    keyField: \"\", // 每组数据的哪个字段作为输入框内容，优先级高于 indexKey 设置（推荐）\r\n\r\n    /* 搜索相关 */\r\n    autoSelect: TRUE, // 键盘向上/下方向键时，是否自动选择值\r\n    allowNoKeyword: TRUE, // 是否允许无关键字时请求数据\r\n    getDataMethod: \"firstByUrl\", // 获取数据的方式，url：一直从url请求；data：从 options.data 获取；firstByUrl：第一次从Url获取全部数据，之后从options.data获取\r\n    delayUntilKeyup: FALSE, // 获取数据的方式 为 firstByUrl 时，是否延迟到有输入时才请求数据\r\n    ignorecase: FALSE, // 前端搜索匹配时，是否忽略大小写\r\n    effectiveFields: [], // 有效显示于列表中的字段，非有效字段都会过滤，默认全部有效。\r\n    effectiveFieldsAlias: {}, // 有效字段的别名对象，用于 header 的显示\r\n    searchFields: [], // 有效搜索字段，从前端搜索过滤数据时使用，但不一定显示在列表中。effectiveFields 配置字段也会用于搜索过滤\r\n    twoWayMatch: TRUE, // 是否双向匹配搜索。为 true 即输入关键字包含或包含于匹配字段均认为匹配成功，为 false 则输入关键字包含于匹配字段认为匹配成功\r\n    multiWord: FALSE, // 以分隔符号分割的多关键字支持\r\n    separator: \",\", // 多关键字支持时的分隔符，默认为半角逗号\r\n    delay: 300, // 搜索触发的延时时间间隔，单位毫秒\r\n    emptyTip: \"\", // 查询为空时显示的内容，可为 html\r\n    searchingTip: \"搜索中...\", // ajax 搜索时显示的提示内容，当搜索时间较长时给出正在搜索的提示\r\n    hideOnSelect: FALSE, // 鼠标从列表单击选择了值时，是否隐藏选择列表\r\n    maxOptionCount: 200, // 选择列表最多显示的可选项数量，默认为 200\r\n\r\n    /* UI */\r\n    autoDropup: FALSE, // 选择菜单是否自动判断向上展开。设为 true，则当下拉菜单高度超过窗体，且向上方向不会被窗体覆盖，则选择菜单向上弹出\r\n    autoMinWidth: FALSE, // 是否自动最小宽度，设为 false 则最小宽度不小于输入框宽度\r\n    showHeader: FALSE, // 是否显示选择列表的 header。为 true 时，有效字段大于一列则显示表头\r\n    showBtn: TRUE, // 是否显示下拉按钮\r\n    inputBgColor: \"\", // 输入框背景色，当与容器背景色不同时，可能需要该项的配置\r\n    inputWarnColor: \"rgba(255,0,0,.1)\", // 输入框内容不是下拉列表选择时的警告色\r\n    listStyle: {\r\n      \"padding-top\": 0,\r\n      \"max-height\": \"375px\",\r\n      \"max-width\": \"800px\",\r\n      overflow: \"auto\",\r\n      width: \"auto\",\r\n      transition: \"0.3s\",\r\n      \"-webkit-transition\": \"0.3s\",\r\n      \"-moz-transition\": \"0.3s\",\r\n      \"-o-transition\": \"0.3s\",\r\n      \"word-break\": \"keep-all\",\r\n      \"white-space\": \"nowrap\"\r\n    }, // 列表的样式控制\r\n    listAlign: \"left\", // 提示列表对齐位置，left/right/auto\r\n    listHoverStyle: \"background: #07d; color:#fff\", // 提示框列表鼠标悬浮的样式\r\n    listHoverCSS: \"jhover\", // 提示框列表鼠标悬浮的样式名称\r\n    clearable: FALSE, // 是否可清除已输入的内容\r\n\r\n    /* key */\r\n    keyLeft: 37, // 向左方向键，不同的操作系统可能会有差别，则自行定义\r\n    keyUp: 38, // 向上方向键\r\n    keyRight: 39, // 向右方向键\r\n    keyDown: 40, // 向下方向键\r\n    keyEnter: 13, // 回车键\r\n\r\n    /* methods */\r\n    fnProcessData: processData, // 格式化数据的方法，返回数据格式参考 data 参数\r\n    fnGetData: getData, // 获取数据的方法，无特殊需求一般不作设置\r\n    fnAdjustAjaxParam: null, // 调整 ajax 请求参数方法，用于更多的请求配置需求。如对请求关键字作进一步处理、修改超时时间等\r\n    fnPreprocessKeyword: null, // 搜索过滤数据前，对输入关键字作进一步处理方法。注意，应返回字符串\r\n    fnAjaxFail: null // ajax 失败时回调方法\r\n  };\r\n\r\n  var methods = {\r\n    init: function(options) {\r\n      // 参数设置\r\n      var self = this;\r\n      options = options || {};\r\n\r\n      // 默认配置有效显示字段多于一个，则显示列表表头，否则不显示\r\n      if (\r\n        isUndefined(options.showHeader) &&\r\n        options.effectiveFields &&\r\n        options.effectiveFields.length > 1\r\n      ) {\r\n        options.showHeader = TRUE;\r\n      }\r\n\r\n      options = $.extend(TRUE, {}, defaultOptions, options);\r\n\r\n      // 旧的方法兼容\r\n      if (options.processData) {\r\n        options.fnProcessData = options.processData;\r\n      }\r\n\r\n      if (options.getData) {\r\n        options.fnGetData = options.getData;\r\n      }\r\n\r\n      if (\r\n        options.getDataMethod === \"firstByUrl\" &&\r\n        options.url &&\r\n        !options.delayUntilKeyup\r\n      ) {\r\n        ajax(options).done(function(result) {\r\n          options.url = null;\r\n          self.trigger(onDataRequestSuccess, result);\r\n        });\r\n      }\r\n\r\n      // 鼠标滑动到条目样式\r\n      if (!$(\"#\" + BSSUGGEST).length) {\r\n        $(\"head:eq(0)\").append(\r\n          '<style id=\"' +\r\n            BSSUGGEST +\r\n            '\">.' +\r\n            options.listHoverCSS +\r\n            \"{\" +\r\n            options.listHoverStyle +\r\n            \"}</style>\"\r\n        );\r\n      }\r\n\r\n      return self.each(function() {\r\n        var $input = $(this),\r\n          $parent = $input.parent(),\r\n          $iClear = getIClear($input, options),\r\n          isMouseenterMenu,\r\n          keyupTimer, // keyup 与 input 事件延时定时器\r\n          $dropdownMenu = $parent.find(\"ul:eq(0)\");\r\n\r\n        // 兼容 bs4\r\n        $dropdownMenu.parent().css(\"position\", \"relative\");\r\n\r\n        // 验证输入框对象是否符合条件\r\n        if (!checkInput($input, $dropdownMenu, options)) {\r\n          console.warn(\r\n            \"不是一个标准的 bootstrap 下拉式菜单或已初始化:\",\r\n            $input\r\n          );\r\n          return;\r\n        }\r\n\r\n        // 是否显示 button 按钮\r\n        if (!options.showBtn) {\r\n          $input.css(\"borderRadius\", 4);\r\n          $parent\r\n            .css(\"width\", \"100%\")\r\n            .find(\".btn:eq(0)\")\r\n            .hide();\r\n        }\r\n\r\n        // 移除 disabled 类，并禁用自动完成\r\n        $input\r\n          .removeClass(DISABLED)\r\n          .prop(DISABLED, FALSE)\r\n          .attr(\"autocomplete\", \"off\");\r\n        // dropdown-menu 增加修饰\r\n        $dropdownMenu.css(options.listStyle);\r\n\r\n        // 默认背景色\r\n        if (!options.inputBgColor) {\r\n          options.inputBgColor = $input.css(\"backgroundColor\");\r\n        }\r\n\r\n        // 开始事件处理\r\n        $input\r\n          .on(\"keydown.bs\", function(event) {\r\n            var currentList, tipsKeyword; // 提示列表上被选中的关键字\r\n\r\n            // 当提示层显示时才对键盘事件处理\r\n            if (!$dropdownMenu.is(\":visible\")) {\r\n              setOrGetDataId($input, \"\");\r\n              return;\r\n            }\r\n\r\n            currentList = $dropdownMenu.find(\".\" + options.listHoverCSS);\r\n            tipsKeyword = \"\"; // 提示列表上被选中的关键字\r\n\r\n            unHoverAll($dropdownMenu, options);\r\n\r\n            if (event.keyCode === options.keyDown) {\r\n              // 如果按的是向下方向键\r\n              if (!currentList.length) {\r\n                // 如果提示列表没有一个被选中,则将列表第一个选中\r\n                tipsKeyword = getPointKeyword(\r\n                  $dropdownMenu.find(\"tbody tr:first\").mouseover()\r\n                );\r\n              } else if (!currentList.next().length) {\r\n                // 如果是最后一个被选中,则取消选中,即可认为是输入框被选中，并恢复输入的值\r\n                if (options.autoSelect) {\r\n                  setOrGetDataId($input, \"\").val(setOrGetAlt($input));\r\n                }\r\n              } else {\r\n                // 选中下一行\r\n                tipsKeyword = getPointKeyword(currentList.next().mouseover());\r\n              }\r\n              // 控制滑动条\r\n              adjustScroll($input, $dropdownMenu, options);\r\n\r\n              if (!options.autoSelect) {\r\n                return;\r\n              }\r\n            } else if (event.keyCode === options.keyUp) {\r\n              // 如果按的是向上方向键\r\n              if (!currentList.length) {\r\n                tipsKeyword = getPointKeyword(\r\n                  $dropdownMenu.find(\"tbody tr:last\").mouseover()\r\n                );\r\n              } else if (!currentList.prev().length) {\r\n                if (options.autoSelect) {\r\n                  setOrGetDataId($input, \"\").val(setOrGetAlt($input));\r\n                }\r\n              } else {\r\n                // 选中前一行\r\n                tipsKeyword = getPointKeyword(currentList.prev().mouseover());\r\n              }\r\n\r\n              // 控制滑动条\r\n              adjustScroll($input, $dropdownMenu, options);\r\n\r\n              if (!options.autoSelect) {\r\n                return;\r\n              }\r\n            } else if (event.keyCode === options.keyEnter) {\r\n              tipsKeyword = getPointKeyword(currentList);\r\n              hideDropMenu($input, options);\r\n            } else {\r\n              setOrGetDataId($input, \"\");\r\n            }\r\n\r\n            // 设置值 tipsKeyword\r\n            // console.log(tipsKeyword);\r\n            setValue($input, tipsKeyword, options);\r\n          })\r\n          .on(\"compositionstart.bs\", function(event) {\r\n            // 中文输入开始，锁定\r\n            // console.log('compositionstart');\r\n            inputLock = TRUE;\r\n          })\r\n          .on(\"compositionend.bs\", function(event) {\r\n            // 中文输入结束，解除锁定\r\n            // console.log('compositionend');\r\n            inputLock = FALSE;\r\n          })\r\n          .on(\"keyup.bs input.bs paste.bs\", function(event) {\r\n            var word;\r\n\r\n            if (event.keyCode) {\r\n              setBackground($input, options);\r\n            }\r\n\r\n            // 如果弹起的键是回车、向上或向下方向键则返回\r\n            if (\r\n              ~$.inArray(event.keyCode, [\r\n                options.keyDown,\r\n                options.keyUp,\r\n                options.keyEnter\r\n              ])\r\n            ) {\r\n              $input.val($input.val()); // 让鼠标输入跳到最后\r\n              return;\r\n            }\r\n\r\n            clearTimeout(keyupTimer);\r\n            keyupTimer = setTimeout(function() {\r\n              // console.log('input keyup', event);\r\n\r\n              // 锁定状态，返回\r\n              if (inputLock) {\r\n                return;\r\n              }\r\n\r\n              word = $input.val();\r\n\r\n              // 若输入框值没有改变则返回\r\n              if ($.trim(word) && word === setOrGetAlt($input)) {\r\n                return;\r\n              }\r\n\r\n              // 当按下键之前记录输入框值,以方便查看键弹起时值有没有变\r\n              setOrGetAlt($input, word);\r\n\r\n              if (options.multiWord) {\r\n                word = word.split(options.separator).reverse()[0];\r\n              }\r\n\r\n              // 是否允许空数据查询\r\n              if (!word.length && !options.allowNoKeyword) {\r\n                return;\r\n              }\r\n\r\n              options.fnGetData($.trim(word), $input, refreshDropMenu, options);\r\n            }, options.delay || 300);\r\n          })\r\n          .on(\"focus.bs\", function() {\r\n            // console.log('input focus');\r\n            adjustDropMenuPos($input, $dropdownMenu, options);\r\n          })\r\n          .on(\"blur.bs\", function() {\r\n            if (!isMouseenterMenu) {\r\n              // 不是进入下拉列表状态，则隐藏列表\r\n              hideDropMenu($input, options);\r\n              inputLock = true;\r\n              setTimeout(function() {\r\n                inputLock = FALSE;\r\n              });\r\n            }\r\n          })\r\n          .on(\"click.bs\", function() {\r\n            // console.log('input click');\r\n            var word = $input.val();\r\n\r\n            if (\r\n              $.trim(word) &&\r\n              word === setOrGetAlt($input) &&\r\n              $dropdownMenu.find(\"table tr\").length\r\n            ) {\r\n              return showDropMenu($input, options);\r\n            }\r\n\r\n            if ($dropdownMenu.is(\":visible\")) {\r\n              return;\r\n            }\r\n\r\n            if (options.multiWord) {\r\n              word = word.split(options.separator).reverse()[0];\r\n            }\r\n\r\n            // 是否允许空数据查询\r\n            if (!word.length && !options.allowNoKeyword) {\r\n              return;\r\n            }\r\n\r\n            // console.log('word', word);\r\n            options.fnGetData($.trim(word), $input, refreshDropMenu, options);\r\n          });\r\n\r\n        // 下拉按钮点击时\r\n        $parent\r\n          .find(\".btn:eq(0)\")\r\n          .attr(\"data-toggle\", \"\")\r\n          .click(function() {\r\n            if (!$dropdownMenu.is(\":visible\")) {\r\n              if (options.url) {\r\n                $input.click().focus();\r\n                if (!$dropdownMenu.find(\"tr\").length) {\r\n                  return FALSE;\r\n                }\r\n              } else {\r\n                // 不以 keyword 作为过滤，展示所有的数据\r\n                refreshDropMenu($input, options.data, options);\r\n              }\r\n              showDropMenu($input, options);\r\n            } else {\r\n              hideDropMenu($input, options);\r\n            }\r\n\r\n            return FALSE;\r\n          });\r\n\r\n        // 列表中滑动时，输入框失去焦点\r\n        $dropdownMenu\r\n          .mouseenter(function() {\r\n            // console.log('mouseenter')\r\n            isMouseenterMenu = 1;\r\n            $input.blur();\r\n          })\r\n          .mouseleave(function() {\r\n            // console.log('mouseleave')\r\n            isMouseenterMenu = 0;\r\n            $input.focus();\r\n          })\r\n          .on(\"mouseenter\", \"tbody tr\", function() {\r\n            // 行上的移动事件\r\n            unHoverAll($dropdownMenu, options);\r\n            $(this).addClass(options.listHoverCSS);\r\n\r\n            return FALSE; // 阻止冒泡\r\n          })\r\n          .on(\"mousedown\", \"tbody tr\", function() {\r\n            var keywords = getPointKeyword($(this));\r\n            setValue($input, keywords, options);\r\n            setOrGetAlt($input, keywords.key);\r\n            setBackground($input, options);\r\n\r\n            if (options.hideOnSelect) {\r\n              hideDropMenu($input, options);\r\n            }\r\n          });\r\n\r\n        // 存在清空按钮\r\n        if ($iClear.length) {\r\n          $iClear.click(function() {\r\n            setOrGetDataId($input, \"\").val(\"\");\r\n            setBackground($input, options);\r\n          });\r\n\r\n          $parent\r\n            .mouseenter(function() {\r\n              if (!$input.prop(DISABLED)) {\r\n                $iClear\r\n                  .css(\r\n                    \"right\",\r\n                    options.showBtn\r\n                      ? Math.max($input.next().width(), 33) + 2\r\n                      : 12\r\n                  )\r\n                  .show();\r\n              }\r\n            })\r\n            .mouseleave(function() {\r\n              $iClear.hide();\r\n            });\r\n        }\r\n      });\r\n    },\r\n    show: function() {\r\n      return this.each(function() {\r\n        $(this).click();\r\n      });\r\n    },\r\n    hide: function() {\r\n      return this.each(function() {\r\n        hideDropMenu($(this));\r\n      });\r\n    },\r\n    disable: function() {\r\n      return this.each(function() {\r\n        $(this)\r\n          .attr(DISABLED, TRUE)\r\n          .parent()\r\n          .find(\".btn:eq(0)\")\r\n          .prop(DISABLED, TRUE);\r\n      });\r\n    },\r\n    enable: function() {\r\n      return this.each(function() {\r\n        $(this)\r\n          .attr(DISABLED, FALSE)\r\n          .parent()\r\n          .find(\".btn:eq(0)\")\r\n          .prop(DISABLED, FALSE);\r\n      });\r\n    },\r\n    destroy: function() {\r\n      return this.each(function() {\r\n        var evNameList =\r\n          \"click.bs keydown.bs compositionstart.bs compositionend.bs keyup.bs input.bs paste.bs focus.bs click.bs\";\r\n        $(this)\r\n          .off(evNameList)\r\n          .removeData(BSSUGGEST)\r\n          .removeAttr(\"style\")\r\n          .parent()\r\n          .find(\".btn:eq(0)\")\r\n          .off()\r\n          .show()\r\n          .attr(\"data-toggle\", \"dropdown\")\r\n          .prop(DISABLED, FALSE) // .addClass(DISABLED);\r\n          .next()\r\n          .css(\"display\", \"\")\r\n          .off();\r\n      });\r\n    },\r\n    version: function() {\r\n      return VERSION;\r\n    }\r\n  };\r\n\r\n  $.fn[BSSUGGEST] = function(options) {\r\n    // 方法判断\r\n    if (typeof options === \"string\" && methods[options]) {\r\n      var inited = TRUE;\r\n      this.each(function() {\r\n        if (!$(this).data(BSSUGGEST)) {\r\n          return (inited = FALSE);\r\n        }\r\n      });\r\n      // 只要有一个未初始化，则全部都不执行方法，除非是 init 或 version\r\n      if (!inited && \"init\" !== options && \"version\" !== options) {\r\n        return this;\r\n      }\r\n\r\n      // 如果是方法，则参数第一个为函数名，从第二个开始为函数参数\r\n      return methods[options].apply(this, [].slice.call(arguments, 1));\r\n    } else {\r\n      // 调用初始化方法\r\n      return methods.init.apply(this, arguments);\r\n    }\r\n  };\r\n});"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/summernote/summernote-zh-CN.js",
    "content": "(function ($) {\n  $.extend($.summernote.lang, {\n    'zh-CN': {\n      font: {\n        bold: '粗体',\n        italic: '斜体',\n        underline: '下划线',\n        clear: '清除格式',\n        height: '行高',\n        name: '字体',\n        strikethrough: '删除线',\n        subscript: '下标',\n        superscript: '上标',\n        size: '字号'\n      },\n      image: {\n        image: '图片',\n        insert: '插入图片',\n        resizeFull: '缩放至 100%',\n        resizeHalf: '缩放至 50%',\n        resizeQuarter: '缩放至 25%',\n        floatLeft: '靠左浮动',\n        floatRight: '靠右浮动',\n        floatNone: '取消浮动',\n        shapeRounded: '形状: 圆角',\n        shapeCircle: '形状: 圆',\n        shapeThumbnail: '形状: 缩略图',\n        shapeNone: '形状: 无',\n        dragImageHere: '将图片拖拽至此处',\n        dropImage: '拖拽图片或文本',\n        selectFromFiles: '从本地上传',\n        maximumFileSize: '文件大小最大值',\n        maximumFileSizeError: '文件大小超出最大值。',\n        url: '图片地址',\n        remove: '移除图片',\n        original: '原始图片'\n      },\n      video: {\n        video: '视频',\n        videoLink: '视频链接',\n        insert: '插入视频',\n        url: '视频地址',\n        providers: '(优酷, 腾讯, Instagram, DailyMotion, Youtube等)'\n      },\n      link: {\n        link: '链接',\n        insert: '插入链接',\n        unlink: '去除链接',\n        edit: '编辑链接',\n        textToDisplay: '显示文本',\n        url: '链接地址',\n        openInNewWindow: '在新窗口打开'\n      },\n      table: {\n        table: '表格',\n        addRowAbove: '在上方插入行',\n        addRowBelow: '在下方插入行',\n        addColLeft: '在左侧插入列',\n        addColRight: '在右侧插入列',\n        delRow: '删除行',\n        delCol: '删除列',\n        delTable: '删除表格'\n      },\n      hr: {\n        insert: '水平线'\n      },\n      style: {\n        style: '样式',\n        p: '普通',\n        blockquote: '引用',\n        pre: '代码',\n        h1: '标题 1',\n        h2: '标题 2',\n        h3: '标题 3',\n        h4: '标题 4',\n        h5: '标题 5',\n        h6: '标题 6'\n      },\n      lists: {\n        unordered: '无序列表',\n        ordered: '有序列表'\n      },\n      options: {\n        help: '帮助',\n        fullscreen: '全屏',\n        codeview: '源代码'\n      },\n      paragraph: {\n        paragraph: '段落',\n        outdent: '减少缩进',\n        indent: '增加缩进',\n        left: '左对齐',\n        center: '居中对齐',\n        right: '右对齐',\n        justify: '两端对齐'\n      },\n      color: {\n        recent: '最近使用',\n        more: '更多',\n        background: '背景',\n        foreground: '前景',\n        transparent: '透明',\n        setTransparent: '透明',\n        reset: '重置',\n        resetToDefault: '默认'\n      },\n      shortcut: {\n        shortcuts: '快捷键',\n        close: '关闭',\n        textFormatting: '文本格式',\n        action: '动作',\n        paragraphFormatting: '段落格式',\n        documentStyle: '文档样式',\n        extraKeys: '额外按键'\n      },\n      help: {\n        insertParagraph: '插入段落',\n        undo: '撤销',\n        redo: '重做',\n        tab: '增加缩进',\n        untab: '减少缩进',\n        bold: '粗体',\n        italic: '斜体',\n        underline: '下划线',\n        strikethrough: '删除线',\n        removeFormat: '清除格式',\n        justifyLeft: '左对齐',\n        justifyCenter: '居中对齐',\n        justifyRight: '右对齐',\n        justifyFull: '两端对齐',\n        insertUnorderedList: '无序列表',\n        insertOrderedList: '有序列表',\n        outdent: '减少缩进',\n        indent: '增加缩进',\n        formatPara: '设置选中内容样式为 普通',\n        formatH1: '设置选中内容样式为 标题1',\n        formatH2: '设置选中内容样式为 标题2',\n        formatH3: '设置选中内容样式为 标题3',\n        formatH4: '设置选中内容样式为 标题4',\n        formatH5: '设置选中内容样式为 标题5',\n        formatH6: '设置选中内容样式为 标题6',\n        insertHorizontalRule: '插入水平线',\n        'linkDialog.show': '显示链接对话框'\n      },\n      history: {\n        undo: '撤销',\n        redo: '重做'\n      },\n      specialChar: {\n        specialChar: '特殊字符',\n        select: '选取特殊字符'\n      }\n    }\n  });\n})(jQuery);\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/summernote/summernote.css",
    "content": "/*!\n * \n * Super simple wysiwyg editor v0.8.18\n * https://summernote.org\n * \n * \n * Copyright 2013- Alan Hong. and other contributors\n * summernote may be freely distributed under the MIT license.\n * \n * Date: 2020-05-20T18:09Z\n * \n */\n@font-face{font-family:\"summernote\";font-style:normal;font-weight:400;font-display:auto;src:url(font/summernote.eot);src:url(font/summernote.eot?#iefix) format(\"embedded-opentype\"),url(font/summernote.woff2) format(\"woff2\"),url(font/summernote.woff) format(\"woff\"),url(font/summernote.ttf) format(\"truetype\")}[class^=note-icon]:before,[class*=\" note-icon\"]:before{display:inline-block;font-family:summernote;font-style:normal;font-size:inherit;text-decoration:inherit;text-rendering:auto;text-transform:none;vertical-align:middle;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;speak:none}.note-icon-fw{text-align:center;width:1.25em}.note-icon-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.note-icon-pull-left{float:left}.note-icon-pull-right{float:right}.note-icon.note-icon-pull-left{margin-right:.3em}.note-icon.note-icon-pull-right{margin-left:.3em}.note-icon-align::before{content:\"\"}.note-icon-align-center::before{content:\"\"}.note-icon-align-indent::before{content:\"\"}.note-icon-align-justify::before{content:\"\"}.note-icon-align-left::before{content:\"\"}.note-icon-align-outdent::before{content:\"\"}.note-icon-align-right::before{content:\"\"}.note-icon-arrow-circle-down::before{content:\"\"}.note-icon-arrow-circle-left::before{content:\"\"}.note-icon-arrow-circle-right::before{content:\"\"}.note-icon-arrow-circle-up::before{content:\"\"}.note-icon-arrows-alt::before{content:\"\"}.note-icon-arrows-h::before{content:\"\"}.note-icon-arrows-v::before{content:\"\"}.note-icon-bold::before{content:\"\"}.note-icon-caret::before{content:\"\"}.note-icon-chain-broken::before{content:\"\"}.note-icon-circle::before{content:\"\"}.note-icon-close::before{content:\"\"}.note-icon-code::before{content:\"\"}.note-icon-col-after::before{content:\"\"}.note-icon-col-before::before{content:\"\"}.note-icon-col-remove::before{content:\"\"}.note-icon-eraser::before{content:\"\"}.note-icon-float-left::before{content:\"\"}.note-icon-float-none::before{content:\"\"}.note-icon-float-right::before{content:\"\"}.note-icon-font::before{content:\"\"}.note-icon-frame::before{content:\"\"}.note-icon-italic::before{content:\"\"}.note-icon-link::before{content:\"\"}.note-icon-magic::before{content:\"\"}.note-icon-menu-check::before{content:\"\"}.note-icon-minus::before{content:\"\"}.note-icon-orderedlist::before{content:\"\"}.note-icon-pencil::before{content:\"\"}.note-icon-picture::before{content:\"\"}.note-icon-question::before{content:\"\"}.note-icon-redo::before{content:\"\"}.note-icon-rollback::before{content:\"\"}.note-icon-row-above::before{content:\"\"}.note-icon-row-below::before{content:\"\"}.note-icon-row-remove::before{content:\"\"}.note-icon-special-character::before{content:\"\"}.note-icon-square::before{content:\"\"}.note-icon-strikethrough::before{content:\"\"}.note-icon-subscript::before{content:\"\"}.note-icon-summernote::before{content:\"\"}.note-icon-superscript::before{content:\"\"}.note-icon-table::before{content:\"\"}.note-icon-text-height::before{content:\"\"}.note-icon-trash::before{content:\"\"}.note-icon-underline::before{content:\"\"}.note-icon-undo::before{content:\"\"}.note-icon-unorderedlist::before{content:\"\"}.note-icon-video::before{content:\"\"}.note-editor{position:relative}.note-editor .note-dropzone{position:absolute;display:none;z-index:100;color:#87cefa;background-color:#fff;opacity:.95}.note-editor .note-dropzone .note-dropzone-message{display:table-cell;vertical-align:middle;text-align:center;font-size:28px;font-weight:700}.note-editor .note-dropzone.hover{color:#098ddf}.note-editor.dragover .note-dropzone{display:table}.note-editor .note-editing-area{position:relative}.note-editor .note-editing-area .note-editable{outline:none}.note-editor .note-editing-area .note-editable sup{vertical-align:super}.note-editor .note-editing-area .note-editable sub{vertical-align:sub}.note-editor .note-editing-area .note-editable img.note-float-left{margin-right:10px}.note-editor .note-editing-area .note-editable img.note-float-right{margin-left:10px}.note-editor.note-frame,.note-editor.note-airframe{border:1px solid #00000032}.note-editor.note-frame.codeview .note-editing-area .note-editable,.note-editor.note-airframe.codeview .note-editing-area .note-editable{display:none}.note-editor.note-frame.codeview .note-editing-area .note-codable,.note-editor.note-airframe.codeview .note-editing-area .note-codable{display:block}.note-editor.note-frame .note-editing-area,.note-editor.note-airframe .note-editing-area{overflow:hidden}.note-editor.note-frame .note-editing-area .note-editable,.note-editor.note-airframe .note-editing-area .note-editable{padding:10px;overflow:auto;word-wrap:break-word}.note-editor.note-frame .note-editing-area .note-editable[contenteditable=false],.note-editor.note-airframe .note-editing-area .note-editable[contenteditable=false]{background-color:#8080801d}.note-editor.note-frame .note-editing-area .note-codable,.note-editor.note-airframe .note-editing-area .note-codable{display:none;width:100%;padding:10px;border:none;box-shadow:none;font-family:Menlo,Monaco,monospace,sans-serif;font-size:14px;color:#ccc;background-color:#222;resize:none;outline:none;-ms-box-sizing:border-box;box-sizing:border-box;border-radius:0;margin-bottom:0}.note-editor.note-frame.fullscreen,.note-editor.note-airframe.fullscreen{position:fixed;top:0;left:0;width:100% !important;z-index:1050}.note-editor.note-frame.fullscreen .note-resizebar,.note-editor.note-airframe.fullscreen .note-resizebar{display:none}.note-editor.note-frame .note-status-output,.note-editor.note-airframe .note-status-output{display:block;width:100%;font-size:14px;line-height:1.42857143;height:20px;margin-bottom:0;color:#000;border:0;border-top:1px solid #e2e2e2}.note-editor.note-frame .note-status-output:empty,.note-editor.note-airframe .note-status-output:empty{height:0;border-top:0 solid transparent}.note-editor.note-frame .note-status-output .pull-right,.note-editor.note-airframe .note-status-output .pull-right{float:right !important}.note-editor.note-frame .note-status-output .text-muted,.note-editor.note-airframe .note-status-output .text-muted{color:#777}.note-editor.note-frame .note-status-output .text-primary,.note-editor.note-airframe .note-status-output .text-primary{color:#286090}.note-editor.note-frame .note-status-output .text-success,.note-editor.note-airframe .note-status-output .text-success{color:#3c763d}.note-editor.note-frame .note-status-output .text-info,.note-editor.note-airframe .note-status-output .text-info{color:#31708f}.note-editor.note-frame .note-status-output .text-warning,.note-editor.note-airframe .note-status-output .text-warning{color:#8a6d3b}.note-editor.note-frame .note-status-output .text-danger,.note-editor.note-airframe .note-status-output .text-danger{color:#a94442}.note-editor.note-frame .note-status-output .alert,.note-editor.note-airframe .note-status-output .alert{margin:-7px 0 0 0;padding:7px 10px 2px 10px;border-radius:0;color:#000;background-color:#f5f5f5}.note-editor.note-frame .note-status-output .alert .note-icon,.note-editor.note-airframe .note-status-output .alert .note-icon{margin-right:5px}.note-editor.note-frame .note-status-output .alert-success,.note-editor.note-airframe .note-status-output .alert-success{color:#3c763d !important;background-color:#dff0d8 !important}.note-editor.note-frame .note-status-output .alert-info,.note-editor.note-airframe .note-status-output .alert-info{color:#31708f !important;background-color:#d9edf7 !important}.note-editor.note-frame .note-status-output .alert-warning,.note-editor.note-airframe .note-status-output .alert-warning{color:#8a6d3b !important;background-color:#fcf8e3 !important}.note-editor.note-frame .note-status-output .alert-danger,.note-editor.note-airframe .note-status-output .alert-danger{color:#a94442 !important;background-color:#f2dede !important}.note-editor.note-frame .note-statusbar,.note-editor.note-airframe .note-statusbar{background-color:#8080801d;border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-top:1px solid #00000032}.note-editor.note-frame .note-statusbar .note-resizebar,.note-editor.note-airframe .note-statusbar .note-resizebar{padding-top:1px;height:9px;width:100%;cursor:ns-resize}.note-editor.note-frame .note-statusbar .note-resizebar .note-icon-bar,.note-editor.note-airframe .note-statusbar .note-resizebar .note-icon-bar{width:20px;margin:1px auto;border-top:1px solid #00000032}.note-editor.note-frame .note-statusbar.locked .note-resizebar,.note-editor.note-airframe .note-statusbar.locked .note-resizebar{cursor:default}.note-editor.note-frame .note-statusbar.locked .note-resizebar .note-icon-bar,.note-editor.note-airframe .note-statusbar.locked .note-resizebar .note-icon-bar{display:none}.note-editor.note-frame .note-placeholder,.note-editor.note-airframe .note-placeholder{padding:10px}.note-editor.note-airframe{border:0}.note-editor.note-airframe .note-editing-area .note-editable{padding:0}.note-popover.popover{display:none;max-width:none}.note-popover.popover .popover-content a{display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.note-popover.popover .arrow{left:20px !important}.note-toolbar{position:relative}.note-popover .popover-content,.note-editor .note-toolbar{margin:0;padding:0 0 5px 5px}.note-popover .popover-content>.note-btn-group,.note-editor .note-toolbar>.note-btn-group{margin-top:5px;margin-left:0;margin-right:5px}.note-popover .popover-content .note-btn-group .note-table,.note-editor .note-toolbar .note-btn-group .note-table{min-width:0;padding:5px}.note-popover .popover-content .note-btn-group .note-table .note-dimension-picker,.note-editor .note-toolbar .note-btn-group .note-table .note-dimension-picker{font-size:18px}.note-popover .popover-content .note-btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher,.note-editor .note-toolbar .note-btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute !important;z-index:3;width:10em;height:10em;cursor:pointer}.note-popover .popover-content .note-btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted,.note-editor .note-toolbar .note-btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative !important;z-index:1;width:5em;height:5em;background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC\") repeat}.note-popover .popover-content .note-btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted,.note-editor .note-toolbar .note-btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted{position:absolute !important;z-index:2;width:1em;height:1em;background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC\") repeat}.note-popover .popover-content .note-style .dropdown-style blockquote,.note-popover .popover-content .note-style .dropdown-style pre,.note-editor .note-toolbar .note-style .dropdown-style blockquote,.note-editor .note-toolbar .note-style .dropdown-style pre{margin:0;padding:5px 10px}.note-popover .popover-content .note-style .dropdown-style h1,.note-popover .popover-content .note-style .dropdown-style h2,.note-popover .popover-content .note-style .dropdown-style h3,.note-popover .popover-content .note-style .dropdown-style h4,.note-popover .popover-content .note-style .dropdown-style h5,.note-popover .popover-content .note-style .dropdown-style h6,.note-popover .popover-content .note-style .dropdown-style p,.note-editor .note-toolbar .note-style .dropdown-style h1,.note-editor .note-toolbar .note-style .dropdown-style h2,.note-editor .note-toolbar .note-style .dropdown-style h3,.note-editor .note-toolbar .note-style .dropdown-style h4,.note-editor .note-toolbar .note-style .dropdown-style h5,.note-editor .note-toolbar .note-style .dropdown-style h6,.note-editor .note-toolbar .note-style .dropdown-style p{margin:0;padding:0}.note-popover .popover-content .note-color-all .note-dropdown-menu,.note-editor .note-toolbar .note-color-all .note-dropdown-menu{min-width:337px}.note-popover .popover-content .note-color .dropdown-toggle,.note-editor .note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette{display:inline-block;margin:0;width:160px}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette:first-child,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette:first-child{margin:0 5px}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-palette-title,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-palette-title{font-size:12px;margin:2px 7px;text-align:center;border-bottom:1px solid #eee}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-color-reset,.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-color-select,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-color-reset,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-color-select{font-size:11px;margin:3px;padding:0 3px;cursor:pointer;width:100%;border-radius:5px}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-color-reset:hover,.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-color-select:hover,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-color-reset:hover,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-color-select:hover{background:#eee}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-color-row,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-color-row{height:20px}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-color-select-btn,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-color-select-btn{display:none}.note-popover .popover-content .note-color .note-dropdown-menu .note-palette .note-holder-custom .note-color-btn,.note-editor .note-toolbar .note-color .note-dropdown-menu .note-palette .note-holder-custom .note-color-btn{border:1px solid #eee}.note-popover .popover-content .note-para .note-dropdown-menu,.note-editor .note-toolbar .note-para .note-dropdown-menu{min-width:228px;padding:5px}.note-popover .popover-content .note-para .note-dropdown-menu>div+div,.note-editor .note-toolbar .note-para .note-dropdown-menu>div+div{margin-left:5px}.note-popover .popover-content .note-dropdown-menu,.note-editor .note-toolbar .note-dropdown-menu{min-width:160px}.note-popover .popover-content .note-dropdown-menu.right,.note-editor .note-toolbar .note-dropdown-menu.right{right:0;left:auto}.note-popover .popover-content .note-dropdown-menu.right::before,.note-editor .note-toolbar .note-dropdown-menu.right::before{right:9px;left:auto !important}.note-popover .popover-content .note-dropdown-menu.right::after,.note-editor .note-toolbar .note-dropdown-menu.right::after{right:10px;left:auto !important}.note-popover .popover-content .note-dropdown-menu.note-check a i,.note-editor .note-toolbar .note-dropdown-menu.note-check a i{color:#00bfff;visibility:hidden}.note-popover .popover-content .note-dropdown-menu.note-check a.checked i,.note-editor .note-toolbar .note-dropdown-menu.note-check a.checked i{visibility:visible}.note-popover .popover-content .note-fontsize-10,.note-editor .note-toolbar .note-fontsize-10{font-size:10px}.note-popover .popover-content .note-color-palette,.note-editor .note-toolbar .note-color-palette{line-height:1}.note-popover .popover-content .note-color-palette div .note-color-btn,.note-editor .note-toolbar .note-color-palette div .note-color-btn{width:20px;height:20px;padding:0;margin:0;border:0;border-radius:0}.note-popover .popover-content .note-color-palette div .note-color-btn:hover,.note-editor .note-toolbar .note-color-palette div .note-color-btn:hover{transform:scale(1.2);transition:all .2s}.note-modal .modal-dialog{outline:0;border-radius:5px;}.note-modal .form-group{margin-left:0;margin-right:0}.note-modal .note-modal-form{margin:0}.note-modal .note-image-dialog .note-dropzone{min-height:100px;font-size:30px;line-height:4;color:#d3d3d3;text-align:center;border:4px dashed #d3d3d3;margin-bottom:10px}@-moz-document url-prefix(){.note-modal .note-image-input{height:auto}}.note-placeholder{position:absolute;display:none;color:gray}.note-handle .note-control-selection{position:absolute;display:none;border:1px solid #000}.note-handle .note-control-selection>div{position:absolute}.note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;background-color:#000;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;opacity:.3;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);filter:alpha(opacity=30)}.note-handle .note-control-selection .note-control-handle,.note-handle .note-control-selection .note-control-sizing,.note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid #000}.note-handle .note-control-selection .note-control-sizing{background-color:#000}.note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:none;border-bottom:none}.note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:none;border-left:none}.note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:none;border-right:none}.note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-handle .note-control-selection .note-control-se.note-control-holder{cursor:default;border-top:none;border-left:none}.note-handle .note-control-selection .note-control-selection-info{right:0;bottom:0;padding:5px;margin:5px;color:#fff;background-color:#000;font-size:12px;border-radius:5px;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;opacity:.7;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);filter:alpha(opacity=70)}.note-hint-popover{min-width:100px;padding:2px}.note-hint-popover .popover-content{padding:3px;max-height:150px;overflow:auto}.note-hint-popover .popover-content .note-hint-group .note-hint-item{display:block !important;padding:3px}.note-hint-popover .popover-content .note-hint-group .note-hint-item.active,.note-hint-popover .popover-content .note-hint-group .note-hint-item:hover{display:block;clear:both;font-weight:400;line-height:1.4;color:#fff;white-space:nowrap;text-decoration:none;background-color:#428bca;outline:0;cursor:pointer}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/summernote/summernote.js",
    "content": "/*!\n * \n * Super simple wysiwyg editor v0.8.18\n * https://summernote.org\n * \n * \n * Copyright 2013- Alan Hong. and other contributors\n * summernote may be freely distributed under the MIT license.\n * \n * Date: 2020-05-20T18:09Z\n * \n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"jquery\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"jquery\"], factory);\n\telse {\n\t\tvar a = typeof exports === 'object' ? factory(require(\"jquery\")) : factory(root[\"jQuery\"]);\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(window, function(__WEBPACK_EXTERNAL_MODULE__0__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 52);\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ 0:\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE__0__;\n\n/***/ }),\n\n/***/ 1:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);\n/* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar Renderer = /*#__PURE__*/function () {\n  function Renderer(markup, children, options, callback) {\n    _classCallCheck(this, Renderer);\n\n    this.markup = markup;\n    this.children = children;\n    this.options = options;\n    this.callback = callback;\n  }\n\n  _createClass(Renderer, [{\n    key: \"render\",\n    value: function render($parent) {\n      var $node = jquery__WEBPACK_IMPORTED_MODULE_0___default()(this.markup);\n\n      if (this.options && this.options.contents) {\n        $node.html(this.options.contents);\n      }\n\n      if (this.options && this.options.className) {\n        $node.addClass(this.options.className);\n      }\n\n      if (this.options && this.options.data) {\n        jquery__WEBPACK_IMPORTED_MODULE_0___default.a.each(this.options.data, function (k, v) {\n          $node.attr('data-' + k, v);\n        });\n      }\n\n      if (this.options && this.options.click) {\n        $node.on('click', this.options.click);\n      }\n\n      if (this.children) {\n        var $container = $node.find('.note-children-container');\n        this.children.forEach(function (child) {\n          child.render($container.length ? $container : $node);\n        });\n      }\n\n      if (this.callback) {\n        this.callback($node, this.options);\n      }\n\n      if (this.options && this.options.callback) {\n        this.options.callback($node);\n      }\n\n      if ($parent) {\n        $parent.append($node);\n      }\n\n      return $node;\n    }\n  }]);\n\n  return Renderer;\n}();\n\n/* harmony default export */ __webpack_exports__[\"a\"] = ({\n  create: function create(markup, callback) {\n    return function () {\n      var options = _typeof(arguments[1]) === 'object' ? arguments[1] : arguments[0];\n      var children = Array.isArray(arguments[0]) ? arguments[0] : [];\n\n      if (options && options.children) {\n        children = options.children;\n      }\n\n      return new Renderer(markup, children, options, callback);\n    };\n  }\n});\n\n/***/ }),\n\n/***/ 2:\n/***/ (function(module, exports) {\n\n/* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {/* globals __webpack_amd_options__ */\nmodule.exports = __webpack_amd_options__;\n\n/* WEBPACK VAR INJECTION */}.call(this, {}))\n\n/***/ }),\n\n/***/ 3:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXTERNAL MODULE: external {\"root\":\"jQuery\",\"commonjs2\":\"jquery\",\"commonjs\":\"jquery\",\"amd\":\"jquery\"}\nvar external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_ = __webpack_require__(0);\nvar external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default = /*#__PURE__*/__webpack_require__.n(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_);\n\n// CONCATENATED MODULE: ./src/js/base/summernote-en-US.js\n\nexternal_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote || {\n  lang: {}\n};\nexternal_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.lang, {\n  'en-US': {\n    font: {\n      bold: 'Bold',\n      italic: 'Italic',\n      underline: 'Underline',\n      clear: 'Remove Font Style',\n      height: 'Line Height',\n      name: 'Font Family',\n      strikethrough: 'Strikethrough',\n      subscript: 'Subscript',\n      superscript: 'Superscript',\n      size: 'Font Size',\n      sizeunit: 'Font Size Unit'\n    },\n    image: {\n      image: 'Picture',\n      insert: 'Insert Image',\n      resizeFull: 'Resize full',\n      resizeHalf: 'Resize half',\n      resizeQuarter: 'Resize quarter',\n      resizeNone: 'Original size',\n      floatLeft: 'Float Left',\n      floatRight: 'Float Right',\n      floatNone: 'Remove float',\n      shapeRounded: 'Shape: Rounded',\n      shapeCircle: 'Shape: Circle',\n      shapeThumbnail: 'Shape: Thumbnail',\n      shapeNone: 'Shape: None',\n      dragImageHere: 'Drag image or text here',\n      dropImage: 'Drop image or Text',\n      selectFromFiles: 'Select from files',\n      maximumFileSize: 'Maximum file size',\n      maximumFileSizeError: 'Maximum file size exceeded.',\n      url: 'Image URL',\n      remove: 'Remove Image',\n      original: 'Original'\n    },\n    video: {\n      video: 'Video',\n      videoLink: 'Video Link',\n      insert: 'Insert Video',\n      url: 'Video URL',\n      providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion or Youku)'\n    },\n    link: {\n      link: 'Link',\n      insert: 'Insert Link',\n      unlink: 'Unlink',\n      edit: 'Edit',\n      textToDisplay: 'Text to display',\n      url: 'To what URL should this link go?',\n      openInNewWindow: 'Open in new window',\n      useProtocol: 'Use default protocol'\n    },\n    table: {\n      table: 'Table',\n      addRowAbove: 'Add row above',\n      addRowBelow: 'Add row below',\n      addColLeft: 'Add column left',\n      addColRight: 'Add column right',\n      delRow: 'Delete row',\n      delCol: 'Delete column',\n      delTable: 'Delete table'\n    },\n    hr: {\n      insert: 'Insert Horizontal Rule'\n    },\n    style: {\n      style: 'Style',\n      p: 'Normal',\n      blockquote: 'Quote',\n      pre: 'Code',\n      h1: 'Header 1',\n      h2: 'Header 2',\n      h3: 'Header 3',\n      h4: 'Header 4',\n      h5: 'Header 5',\n      h6: 'Header 6'\n    },\n    lists: {\n      unordered: 'Unordered list',\n      ordered: 'Ordered list'\n    },\n    options: {\n      help: 'Help',\n      fullscreen: 'Full Screen',\n      codeview: 'Code View'\n    },\n    paragraph: {\n      paragraph: 'Paragraph',\n      outdent: 'Outdent',\n      indent: 'Indent',\n      left: 'Align left',\n      center: 'Align center',\n      right: 'Align right',\n      justify: 'Justify full'\n    },\n    color: {\n      recent: 'Recent Color',\n      more: 'More Color',\n      background: 'Background Color',\n      foreground: 'Text Color',\n      transparent: 'Transparent',\n      setTransparent: 'Set transparent',\n      reset: 'Reset',\n      resetToDefault: 'Reset to default',\n      cpSelect: 'Select'\n    },\n    shortcut: {\n      shortcuts: 'Keyboard shortcuts',\n      close: 'Close',\n      textFormatting: 'Text formatting',\n      action: 'Action',\n      paragraphFormatting: 'Paragraph formatting',\n      documentStyle: 'Document Style',\n      extraKeys: 'Extra keys'\n    },\n    help: {\n      'escape': 'Escape',\n      'insertParagraph': 'Insert Paragraph',\n      'undo': 'Undo the last command',\n      'redo': 'Redo the last command',\n      'tab': 'Tab',\n      'untab': 'Untab',\n      'bold': 'Set a bold style',\n      'italic': 'Set a italic style',\n      'underline': 'Set a underline style',\n      'strikethrough': 'Set a strikethrough style',\n      'removeFormat': 'Clean a style',\n      'justifyLeft': 'Set left align',\n      'justifyCenter': 'Set center align',\n      'justifyRight': 'Set right align',\n      'justifyFull': 'Set full align',\n      'insertUnorderedList': 'Toggle unordered list',\n      'insertOrderedList': 'Toggle ordered list',\n      'outdent': 'Outdent on current paragraph',\n      'indent': 'Indent on current paragraph',\n      'formatPara': 'Change current block\\'s format as a paragraph(P tag)',\n      'formatH1': 'Change current block\\'s format as H1',\n      'formatH2': 'Change current block\\'s format as H2',\n      'formatH3': 'Change current block\\'s format as H3',\n      'formatH4': 'Change current block\\'s format as H4',\n      'formatH5': 'Change current block\\'s format as H5',\n      'formatH6': 'Change current block\\'s format as H6',\n      'insertHorizontalRule': 'Insert horizontal rule',\n      'linkDialog.show': 'Show Link Dialog'\n    },\n    history: {\n      undo: 'Undo',\n      redo: 'Redo'\n    },\n    specialChar: {\n      specialChar: 'SPECIAL CHARACTERS',\n      select: 'Select Special characters'\n    },\n    output: {\n      noSelection: 'No Selection Made!'\n    }\n  }\n});\n// CONCATENATED MODULE: ./src/js/base/core/env.js\n\nvar isSupportAmd = typeof define === 'function' && __webpack_require__(2); // eslint-disable-line\n\n/**\n * returns whether font is installed or not.\n *\n * @param {String} fontName\n * @return {Boolean}\n */\n\nvar genericFontFamilies = ['sans-serif', 'serif', 'monospace', 'cursive', 'fantasy'];\n\nfunction validFontName(fontName) {\n  return external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.inArray(fontName.toLowerCase(), genericFontFamilies) === -1 ? \"'\".concat(fontName, \"'\") : fontName;\n}\n\nfunction env_isFontInstalled(fontName) {\n  var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';\n  var testText = 'mmmmmmmmmmwwwww';\n  var testSize = '200px';\n  var canvas = document.createElement('canvas');\n  var context = canvas.getContext('2d');\n  context.font = testSize + \" '\" + testFontName + \"'\";\n  var originalWidth = context.measureText(testText).width;\n  context.font = testSize + ' ' + validFontName(fontName) + ', \"' + testFontName + '\"';\n  var width = context.measureText(testText).width;\n  return originalWidth !== width;\n}\n\nvar userAgent = navigator.userAgent;\nvar isMSIE = /MSIE|Trident/i.test(userAgent);\nvar browserVersion;\n\nif (isMSIE) {\n  var matches = /MSIE (\\d+[.]\\d+)/.exec(userAgent);\n\n  if (matches) {\n    browserVersion = parseFloat(matches[1]);\n  }\n\n  matches = /Trident\\/.*rv:([0-9]{1,}[.0-9]{0,})/.exec(userAgent);\n\n  if (matches) {\n    browserVersion = parseFloat(matches[1]);\n  }\n}\n\nvar isEdge = /Edge\\/\\d+/.test(userAgent);\nvar isSupportTouch = 'ontouchstart' in window || navigator.MaxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; // [workaround] IE doesn't have input events for contentEditable\n// - see: https://goo.gl/4bfIvA\n\nvar inputEventName = isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';\n/**\n * @class core.env\n *\n * Object which check platform and agent\n *\n * @singleton\n * @alternateClassName env\n */\n\n/* harmony default export */ var env = ({\n  isMac: navigator.appVersion.indexOf('Mac') > -1,\n  isMSIE: isMSIE,\n  isEdge: isEdge,\n  isFF: !isEdge && /firefox/i.test(userAgent),\n  isPhantom: /PhantomJS/i.test(userAgent),\n  isWebkit: !isEdge && /webkit/i.test(userAgent),\n  isChrome: !isEdge && /chrome/i.test(userAgent),\n  isSafari: !isEdge && /safari/i.test(userAgent) && !/chrome/i.test(userAgent),\n  browserVersion: browserVersion,\n  jqueryVersion: parseFloat(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.fn.jquery),\n  isSupportAmd: isSupportAmd,\n  isSupportTouch: isSupportTouch,\n  isFontInstalled: env_isFontInstalled,\n  isW3CRangeSupport: !!document.createRange,\n  inputEventName: inputEventName,\n  genericFontFamilies: genericFontFamilies,\n  validFontName: validFontName\n});\n// CONCATENATED MODULE: ./src/js/base/core/func.js\n\n/**\n * @class core.func\n *\n * func utils (for high-order func's arg)\n *\n * @singleton\n * @alternateClassName func\n */\n\nfunction eq(itemA) {\n  return function (itemB) {\n    return itemA === itemB;\n  };\n}\n\nfunction eq2(itemA, itemB) {\n  return itemA === itemB;\n}\n\nfunction peq2(propName) {\n  return function (itemA, itemB) {\n    return itemA[propName] === itemB[propName];\n  };\n}\n\nfunction ok() {\n  return true;\n}\n\nfunction fail() {\n  return false;\n}\n\nfunction not(f) {\n  return function () {\n    return !f.apply(f, arguments);\n  };\n}\n\nfunction and(fA, fB) {\n  return function (item) {\n    return fA(item) && fB(item);\n  };\n}\n\nfunction func_self(a) {\n  return a;\n}\n\nfunction func_invoke(obj, method) {\n  return function () {\n    return obj[method].apply(obj, arguments);\n  };\n}\n\nvar idCounter = 0;\n/**\n * reset globally-unique id\n *\n */\n\nfunction resetUniqueId() {\n  idCounter = 0;\n}\n/**\n * generate a globally-unique id\n *\n * @param {String} [prefix]\n */\n\n\nfunction uniqueId(prefix) {\n  var id = ++idCounter + '';\n  return prefix ? prefix + id : id;\n}\n/**\n * returns bnd (bounds) from rect\n *\n * - IE Compatibility Issue: http://goo.gl/sRLOAo\n * - Scroll Issue: http://goo.gl/sNjUc\n *\n * @param {Rect} rect\n * @return {Object} bounds\n * @return {Number} bounds.top\n * @return {Number} bounds.left\n * @return {Number} bounds.width\n * @return {Number} bounds.height\n */\n\n\nfunction rect2bnd(rect) {\n  var $document = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document);\n  return {\n    top: rect.top + $document.scrollTop(),\n    left: rect.left + $document.scrollLeft(),\n    width: rect.right - rect.left,\n    height: rect.bottom - rect.top\n  };\n}\n/**\n * returns a copy of the object where the keys have become the values and the values the keys.\n * @param {Object} obj\n * @return {Object}\n */\n\n\nfunction invertObject(obj) {\n  var inverted = {};\n\n  for (var key in obj) {\n    if (Object.prototype.hasOwnProperty.call(obj, key)) {\n      inverted[obj[key]] = key;\n    }\n  }\n\n  return inverted;\n}\n/**\n * @param {String} namespace\n * @param {String} [prefix]\n * @return {String}\n */\n\n\nfunction namespaceToCamel(namespace, prefix) {\n  prefix = prefix || '';\n  return prefix + namespace.split('.').map(function (name) {\n    return name.substring(0, 1).toUpperCase() + name.substring(1);\n  }).join('');\n}\n/**\n * Returns a function, that, as long as it continues to be invoked, will not\n * be triggered. The function will be called after it stops being called for\n * N milliseconds. If `immediate` is passed, trigger the function on the\n * leading edge, instead of the trailing.\n * @param {Function} func\n * @param {Number} wait\n * @param {Boolean} immediate\n * @return {Function}\n */\n\n\nfunction debounce(func, wait, immediate) {\n  var timeout;\n  return function () {\n    var context = this;\n    var args = arguments;\n\n    var later = function later() {\n      timeout = null;\n\n      if (!immediate) {\n        func.apply(context, args);\n      }\n    };\n\n    var callNow = immediate && !timeout;\n    clearTimeout(timeout);\n    timeout = setTimeout(later, wait);\n\n    if (callNow) {\n      func.apply(context, args);\n    }\n  };\n}\n/**\n *\n * @param {String} url\n * @return {Boolean}\n */\n\n\nfunction isValidUrl(url) {\n  var expression = /[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)/gi;\n  return expression.test(url);\n}\n\n/* harmony default export */ var func = ({\n  eq: eq,\n  eq2: eq2,\n  peq2: peq2,\n  ok: ok,\n  fail: fail,\n  self: func_self,\n  not: not,\n  and: and,\n  invoke: func_invoke,\n  resetUniqueId: resetUniqueId,\n  uniqueId: uniqueId,\n  rect2bnd: rect2bnd,\n  invertObject: invertObject,\n  namespaceToCamel: namespaceToCamel,\n  debounce: debounce,\n  isValidUrl: isValidUrl\n});\n// CONCATENATED MODULE: ./src/js/base/core/lists.js\n\n/**\n * returns the first item of an array.\n *\n * @param {Array} array\n */\n\nfunction lists_head(array) {\n  return array[0];\n}\n/**\n * returns the last item of an array.\n *\n * @param {Array} array\n */\n\n\nfunction lists_last(array) {\n  return array[array.length - 1];\n}\n/**\n * returns everything but the last entry of the array.\n *\n * @param {Array} array\n */\n\n\nfunction initial(array) {\n  return array.slice(0, array.length - 1);\n}\n/**\n * returns the rest of the items in an array.\n *\n * @param {Array} array\n */\n\n\nfunction tail(array) {\n  return array.slice(1);\n}\n/**\n * returns item of array\n */\n\n\nfunction find(array, pred) {\n  for (var idx = 0, len = array.length; idx < len; idx++) {\n    var item = array[idx];\n\n    if (pred(item)) {\n      return item;\n    }\n  }\n}\n/**\n * returns true if all of the values in the array pass the predicate truth test.\n */\n\n\nfunction lists_all(array, pred) {\n  for (var idx = 0, len = array.length; idx < len; idx++) {\n    if (!pred(array[idx])) {\n      return false;\n    }\n  }\n\n  return true;\n}\n/**\n * returns true if the value is present in the list.\n */\n\n\nfunction contains(array, item) {\n  if (array && array.length && item) {\n    if (array.indexOf) {\n      return array.indexOf(item) !== -1;\n    } else if (array.contains) {\n      // `DOMTokenList` doesn't implement `.indexOf`, but it implements `.contains`\n      return array.contains(item);\n    }\n  }\n\n  return false;\n}\n/**\n * get sum from a list\n *\n * @param {Array} array - array\n * @param {Function} fn - iterator\n */\n\n\nfunction sum(array, fn) {\n  fn = fn || func.self;\n  return array.reduce(function (memo, v) {\n    return memo + fn(v);\n  }, 0);\n}\n/**\n * returns a copy of the collection with array type.\n * @param {Collection} collection - collection eg) node.childNodes, ...\n */\n\n\nfunction from(collection) {\n  var result = [];\n  var length = collection.length;\n  var idx = -1;\n\n  while (++idx < length) {\n    result[idx] = collection[idx];\n  }\n\n  return result;\n}\n/**\n * returns whether list is empty or not\n */\n\n\nfunction lists_isEmpty(array) {\n  return !array || !array.length;\n}\n/**\n * cluster elements by predicate function.\n *\n * @param {Array} array - array\n * @param {Function} fn - predicate function for cluster rule\n * @param {Array[]}\n */\n\n\nfunction clusterBy(array, fn) {\n  if (!array.length) {\n    return [];\n  }\n\n  var aTail = tail(array);\n  return aTail.reduce(function (memo, v) {\n    var aLast = lists_last(memo);\n\n    if (fn(lists_last(aLast), v)) {\n      aLast[aLast.length] = v;\n    } else {\n      memo[memo.length] = [v];\n    }\n\n    return memo;\n  }, [[lists_head(array)]]);\n}\n/**\n * returns a copy of the array with all false values removed\n *\n * @param {Array} array - array\n * @param {Function} fn - predicate function for cluster rule\n */\n\n\nfunction compact(array) {\n  var aResult = [];\n\n  for (var idx = 0, len = array.length; idx < len; idx++) {\n    if (array[idx]) {\n      aResult.push(array[idx]);\n    }\n  }\n\n  return aResult;\n}\n/**\n * produces a duplicate-free version of the array\n *\n * @param {Array} array\n */\n\n\nfunction unique(array) {\n  var results = [];\n\n  for (var idx = 0, len = array.length; idx < len; idx++) {\n    if (!contains(results, array[idx])) {\n      results.push(array[idx]);\n    }\n  }\n\n  return results;\n}\n/**\n * returns next item.\n * @param {Array} array\n */\n\n\nfunction lists_next(array, item) {\n  if (array && array.length && item) {\n    var idx = array.indexOf(item);\n    return idx === -1 ? null : array[idx + 1];\n  }\n\n  return null;\n}\n/**\n * returns prev item.\n * @param {Array} array\n */\n\n\nfunction prev(array, item) {\n  if (array && array.length && item) {\n    var idx = array.indexOf(item);\n    return idx === -1 ? null : array[idx - 1];\n  }\n\n  return null;\n}\n/**\n * @class core.list\n *\n * list utils\n *\n * @singleton\n * @alternateClassName list\n */\n\n\n/* harmony default export */ var lists = ({\n  head: lists_head,\n  last: lists_last,\n  initial: initial,\n  tail: tail,\n  prev: prev,\n  next: lists_next,\n  find: find,\n  contains: contains,\n  all: lists_all,\n  sum: sum,\n  from: from,\n  isEmpty: lists_isEmpty,\n  clusterBy: clusterBy,\n  compact: compact,\n  unique: unique\n});\n// CONCATENATED MODULE: ./src/js/base/core/dom.js\n\n\n\n\nvar NBSP_CHAR = String.fromCharCode(160);\nvar ZERO_WIDTH_NBSP_CHAR = \"\\uFEFF\";\n/**\n * @method isEditable\n *\n * returns whether node is `note-editable` or not.\n *\n * @param {Node} node\n * @return {Boolean}\n */\n\nfunction isEditable(node) {\n  return node && external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(node).hasClass('note-editable');\n}\n/**\n * @method isControlSizing\n *\n * returns whether node is `note-control-sizing` or not.\n *\n * @param {Node} node\n * @return {Boolean}\n */\n\n\nfunction isControlSizing(node) {\n  return node && external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(node).hasClass('note-control-sizing');\n}\n/**\n * @method makePredByNodeName\n *\n * returns predicate which judge whether nodeName is same\n *\n * @param {String} nodeName\n * @return {Function}\n */\n\n\nfunction makePredByNodeName(nodeName) {\n  nodeName = nodeName.toUpperCase();\n  return function (node) {\n    return node && node.nodeName.toUpperCase() === nodeName;\n  };\n}\n/**\n * @method isText\n *\n *\n *\n * @param {Node} node\n * @return {Boolean} true if node's type is text(3)\n */\n\n\nfunction isText(node) {\n  return node && node.nodeType === 3;\n}\n/**\n * @method isElement\n *\n *\n *\n * @param {Node} node\n * @return {Boolean} true if node's type is element(1)\n */\n\n\nfunction isElement(node) {\n  return node && node.nodeType === 1;\n}\n/**\n * ex) br, col, embed, hr, img, input, ...\n * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements\n */\n\n\nfunction isVoid(node) {\n  return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON|^INPUT|^AUDIO|^VIDEO|^EMBED/.test(node.nodeName.toUpperCase());\n}\n\nfunction isPara(node) {\n  if (isEditable(node)) {\n    return false;\n  } // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph\n\n\n  return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());\n}\n\nfunction isHeading(node) {\n  return node && /^H[1-7]/.test(node.nodeName.toUpperCase());\n}\n\nvar isPre = makePredByNodeName('PRE');\nvar isLi = makePredByNodeName('LI');\n\nfunction isPurePara(node) {\n  return isPara(node) && !isLi(node);\n}\n\nvar isTable = makePredByNodeName('TABLE');\nvar isData = makePredByNodeName('DATA');\n\nfunction dom_isInline(node) {\n  return !isBodyContainer(node) && !isList(node) && !isHr(node) && !isPara(node) && !isTable(node) && !isBlockquote(node) && !isData(node);\n}\n\nfunction isList(node) {\n  return node && /^UL|^OL/.test(node.nodeName.toUpperCase());\n}\n\nvar isHr = makePredByNodeName('HR');\n\nfunction dom_isCell(node) {\n  return node && /^TD|^TH/.test(node.nodeName.toUpperCase());\n}\n\nvar isBlockquote = makePredByNodeName('BLOCKQUOTE');\n\nfunction isBodyContainer(node) {\n  return dom_isCell(node) || isBlockquote(node) || isEditable(node);\n}\n\nvar isAnchor = makePredByNodeName('A');\n\nfunction isParaInline(node) {\n  return dom_isInline(node) && !!dom_ancestor(node, isPara);\n}\n\nfunction isBodyInline(node) {\n  return dom_isInline(node) && !dom_ancestor(node, isPara);\n}\n\nvar isBody = makePredByNodeName('BODY');\n/**\n * returns whether nodeB is closest sibling of nodeA\n *\n * @param {Node} nodeA\n * @param {Node} nodeB\n * @return {Boolean}\n */\n\nfunction isClosestSibling(nodeA, nodeB) {\n  return nodeA.nextSibling === nodeB || nodeA.previousSibling === nodeB;\n}\n/**\n * returns array of closest siblings with node\n *\n * @param {Node} node\n * @param {function} [pred] - predicate function\n * @return {Node[]}\n */\n\n\nfunction withClosestSiblings(node, pred) {\n  pred = pred || func.ok;\n  var siblings = [];\n\n  if (node.previousSibling && pred(node.previousSibling)) {\n    siblings.push(node.previousSibling);\n  }\n\n  siblings.push(node);\n\n  if (node.nextSibling && pred(node.nextSibling)) {\n    siblings.push(node.nextSibling);\n  }\n\n  return siblings;\n}\n/**\n * blank HTML for cursor position\n * - [workaround] old IE only works with &nbsp;\n * - [workaround] IE11 and other browser works with bogus br\n */\n\n\nvar blankHTML = env.isMSIE && env.browserVersion < 11 ? '&nbsp;' : '<br>';\n/**\n * @method nodeLength\n *\n * returns #text's text size or element's childNodes size\n *\n * @param {Node} node\n */\n\nfunction nodeLength(node) {\n  if (isText(node)) {\n    return node.nodeValue.length;\n  }\n\n  if (node) {\n    return node.childNodes.length;\n  }\n\n  return 0;\n}\n/**\n * returns whether deepest child node is empty or not.\n *\n * @param {Node} node\n * @return {Boolean}\n */\n\n\nfunction deepestChildIsEmpty(node) {\n  do {\n    if (node.firstElementChild === null || node.firstElementChild.innerHTML === '') break;\n  } while (node = node.firstElementChild);\n\n  return dom_isEmpty(node);\n}\n/**\n * returns whether node is empty or not.\n *\n * @param {Node} node\n * @return {Boolean}\n */\n\n\nfunction dom_isEmpty(node) {\n  var len = nodeLength(node);\n\n  if (len === 0) {\n    return true;\n  } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {\n    // ex) <p><br></p>, <span><br></span>\n    return true;\n  } else if (lists.all(node.childNodes, isText) && node.innerHTML === '') {\n    // ex) <p></p>, <span></span>\n    return true;\n  }\n\n  return false;\n}\n/**\n * padding blankHTML if node is empty (for cursor position)\n */\n\n\nfunction paddingBlankHTML(node) {\n  if (!isVoid(node) && !nodeLength(node)) {\n    node.innerHTML = blankHTML;\n  }\n}\n/**\n * find nearest ancestor predicate hit\n *\n * @param {Node} node\n * @param {Function} pred - predicate function\n */\n\n\nfunction dom_ancestor(node, pred) {\n  while (node) {\n    if (pred(node)) {\n      return node;\n    }\n\n    if (isEditable(node)) {\n      break;\n    }\n\n    node = node.parentNode;\n  }\n\n  return null;\n}\n/**\n * find nearest ancestor only single child blood line and predicate hit\n *\n * @param {Node} node\n * @param {Function} pred - predicate function\n */\n\n\nfunction singleChildAncestor(node, pred) {\n  node = node.parentNode;\n\n  while (node) {\n    if (nodeLength(node) !== 1) {\n      break;\n    }\n\n    if (pred(node)) {\n      return node;\n    }\n\n    if (isEditable(node)) {\n      break;\n    }\n\n    node = node.parentNode;\n  }\n\n  return null;\n}\n/**\n * returns new array of ancestor nodes (until predicate hit).\n *\n * @param {Node} node\n * @param {Function} [optional] pred - predicate function\n */\n\n\nfunction listAncestor(node, pred) {\n  pred = pred || func.fail;\n  var ancestors = [];\n  dom_ancestor(node, function (el) {\n    if (!isEditable(el)) {\n      ancestors.push(el);\n    }\n\n    return pred(el);\n  });\n  return ancestors;\n}\n/**\n * find farthest ancestor predicate hit\n */\n\n\nfunction lastAncestor(node, pred) {\n  var ancestors = listAncestor(node);\n  return lists.last(ancestors.filter(pred));\n}\n/**\n * returns common ancestor node between two nodes.\n *\n * @param {Node} nodeA\n * @param {Node} nodeB\n */\n\n\nfunction dom_commonAncestor(nodeA, nodeB) {\n  var ancestors = listAncestor(nodeA);\n\n  for (var n = nodeB; n; n = n.parentNode) {\n    if (ancestors.indexOf(n) > -1) return n;\n  }\n\n  return null; // difference document area\n}\n/**\n * listing all previous siblings (until predicate hit).\n *\n * @param {Node} node\n * @param {Function} [optional] pred - predicate function\n */\n\n\nfunction listPrev(node, pred) {\n  pred = pred || func.fail;\n  var nodes = [];\n\n  while (node) {\n    if (pred(node)) {\n      break;\n    }\n\n    nodes.push(node);\n    node = node.previousSibling;\n  }\n\n  return nodes;\n}\n/**\n * listing next siblings (until predicate hit).\n *\n * @param {Node} node\n * @param {Function} [pred] - predicate function\n */\n\n\nfunction listNext(node, pred) {\n  pred = pred || func.fail;\n  var nodes = [];\n\n  while (node) {\n    if (pred(node)) {\n      break;\n    }\n\n    nodes.push(node);\n    node = node.nextSibling;\n  }\n\n  return nodes;\n}\n/**\n * listing descendant nodes\n *\n * @param {Node} node\n * @param {Function} [pred] - predicate function\n */\n\n\nfunction listDescendant(node, pred) {\n  var descendants = [];\n  pred = pred || func.ok; // start DFS(depth first search) with node\n\n  (function fnWalk(current) {\n    if (node !== current && pred(current)) {\n      descendants.push(current);\n    }\n\n    for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {\n      fnWalk(current.childNodes[idx]);\n    }\n  })(node);\n\n  return descendants;\n}\n/**\n * wrap node with new tag.\n *\n * @param {Node} node\n * @param {Node} tagName of wrapper\n * @return {Node} - wrapper\n */\n\n\nfunction wrap(node, wrapperName) {\n  var parent = node.parentNode;\n  var wrapper = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<' + wrapperName + '>')[0];\n  parent.insertBefore(wrapper, node);\n  wrapper.appendChild(node);\n  return wrapper;\n}\n/**\n * insert node after preceding\n *\n * @param {Node} node\n * @param {Node} preceding - predicate function\n */\n\n\nfunction insertAfter(node, preceding) {\n  var next = preceding.nextSibling;\n  var parent = preceding.parentNode;\n\n  if (next) {\n    parent.insertBefore(node, next);\n  } else {\n    parent.appendChild(node);\n  }\n\n  return node;\n}\n/**\n * append elements.\n *\n * @param {Node} node\n * @param {Collection} aChild\n */\n\n\nfunction appendChildNodes(node, aChild) {\n  external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(aChild, function (idx, child) {\n    node.appendChild(child);\n  });\n  return node;\n}\n/**\n * returns whether boundaryPoint is left edge or not.\n *\n * @param {BoundaryPoint} point\n * @return {Boolean}\n */\n\n\nfunction isLeftEdgePoint(point) {\n  return point.offset === 0;\n}\n/**\n * returns whether boundaryPoint is right edge or not.\n *\n * @param {BoundaryPoint} point\n * @return {Boolean}\n */\n\n\nfunction isRightEdgePoint(point) {\n  return point.offset === nodeLength(point.node);\n}\n/**\n * returns whether boundaryPoint is edge or not.\n *\n * @param {BoundaryPoint} point\n * @return {Boolean}\n */\n\n\nfunction isEdgePoint(point) {\n  return isLeftEdgePoint(point) || isRightEdgePoint(point);\n}\n/**\n * returns whether node is left edge of ancestor or not.\n *\n * @param {Node} node\n * @param {Node} ancestor\n * @return {Boolean}\n */\n\n\nfunction dom_isLeftEdgeOf(node, ancestor) {\n  while (node && node !== ancestor) {\n    if (dom_position(node) !== 0) {\n      return false;\n    }\n\n    node = node.parentNode;\n  }\n\n  return true;\n}\n/**\n * returns whether node is right edge of ancestor or not.\n *\n * @param {Node} node\n * @param {Node} ancestor\n * @return {Boolean}\n */\n\n\nfunction isRightEdgeOf(node, ancestor) {\n  if (!ancestor) {\n    return false;\n  }\n\n  while (node && node !== ancestor) {\n    if (dom_position(node) !== nodeLength(node.parentNode) - 1) {\n      return false;\n    }\n\n    node = node.parentNode;\n  }\n\n  return true;\n}\n/**\n * returns whether point is left edge of ancestor or not.\n * @param {BoundaryPoint} point\n * @param {Node} ancestor\n * @return {Boolean}\n */\n\n\nfunction isLeftEdgePointOf(point, ancestor) {\n  return isLeftEdgePoint(point) && dom_isLeftEdgeOf(point.node, ancestor);\n}\n/**\n * returns whether point is right edge of ancestor or not.\n * @param {BoundaryPoint} point\n * @param {Node} ancestor\n * @return {Boolean}\n */\n\n\nfunction isRightEdgePointOf(point, ancestor) {\n  return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);\n}\n/**\n * returns offset from parent.\n *\n * @param {Node} node\n */\n\n\nfunction dom_position(node) {\n  var offset = 0;\n\n  while (node = node.previousSibling) {\n    offset += 1;\n  }\n\n  return offset;\n}\n\nfunction hasChildren(node) {\n  return !!(node && node.childNodes && node.childNodes.length);\n}\n/**\n * returns previous boundaryPoint\n *\n * @param {BoundaryPoint} point\n * @param {Boolean} isSkipInnerOffset\n * @return {BoundaryPoint}\n */\n\n\nfunction dom_prevPoint(point, isSkipInnerOffset) {\n  var node;\n  var offset;\n\n  if (point.offset === 0) {\n    if (isEditable(point.node)) {\n      return null;\n    }\n\n    node = point.node.parentNode;\n    offset = dom_position(point.node);\n  } else if (hasChildren(point.node)) {\n    node = point.node.childNodes[point.offset - 1];\n    offset = nodeLength(node);\n  } else {\n    node = point.node;\n    offset = isSkipInnerOffset ? 0 : point.offset - 1;\n  }\n\n  return {\n    node: node,\n    offset: offset\n  };\n}\n/**\n * returns next boundaryPoint\n *\n * @param {BoundaryPoint} point\n * @param {Boolean} isSkipInnerOffset\n * @return {BoundaryPoint}\n */\n\n\nfunction dom_nextPoint(point, isSkipInnerOffset) {\n  var node, offset;\n\n  if (nodeLength(point.node) === point.offset) {\n    if (isEditable(point.node)) {\n      return null;\n    }\n\n    var nextTextNode = getNextTextNode(point.node);\n\n    if (nextTextNode) {\n      node = nextTextNode;\n      offset = 0;\n    } else {\n      node = point.node.parentNode;\n      offset = dom_position(point.node) + 1;\n    }\n  } else if (hasChildren(point.node)) {\n    node = point.node.childNodes[point.offset];\n    offset = 0;\n  } else {\n    node = point.node;\n    offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;\n  }\n\n  return {\n    node: node,\n    offset: offset\n  };\n}\n/**\n * returns next boundaryPoint with empty node\n *\n * @param {BoundaryPoint} point\n * @param {Boolean} isSkipInnerOffset\n * @return {BoundaryPoint}\n */\n\n\nfunction nextPointWithEmptyNode(point, isSkipInnerOffset) {\n  var node, offset; // if node is empty string node, return current node's sibling.\n\n  if (dom_isEmpty(point.node)) {\n    node = point.node.nextSibling;\n    offset = 0;\n    return {\n      node: node,\n      offset: offset\n    };\n  }\n\n  if (nodeLength(point.node) === point.offset) {\n    if (isEditable(point.node)) {\n      return null;\n    }\n\n    var nextTextNode = getNextTextNode(point.node);\n\n    if (nextTextNode) {\n      node = nextTextNode;\n      offset = 0;\n    } else {\n      node = point.node.parentNode;\n      offset = dom_position(point.node) + 1;\n    } // if next node is editable, return current node's sibling node.\n\n\n    if (isEditable(node)) {\n      node = point.node.nextSibling;\n      offset = 0;\n    }\n  } else if (hasChildren(point.node)) {\n    node = point.node.childNodes[point.offset];\n    offset = 0;\n\n    if (dom_isEmpty(node)) {\n      return null;\n    }\n  } else {\n    node = point.node;\n    offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;\n\n    if (dom_isEmpty(node)) {\n      return null;\n    }\n  }\n\n  return {\n    node: node,\n    offset: offset\n  };\n}\n/*\n* returns the next Text node index or 0 if not found.\n*/\n\n\nfunction getNextTextNode(actual) {\n  if (!actual.nextSibling) return undefined;\n  if (actual.parent !== actual.nextSibling.parent) return undefined;\n  if (isText(actual.nextSibling)) return actual.nextSibling;\n  return getNextTextNode(actual.nextSibling);\n}\n/**\n * returns whether pointA and pointB is same or not.\n *\n * @param {BoundaryPoint} pointA\n * @param {BoundaryPoint} pointB\n * @return {Boolean}\n */\n\n\nfunction isSamePoint(pointA, pointB) {\n  return pointA.node === pointB.node && pointA.offset === pointB.offset;\n}\n/**\n * returns whether point is visible (can set cursor) or not.\n *\n * @param {BoundaryPoint} point\n * @return {Boolean}\n */\n\n\nfunction isVisiblePoint(point) {\n  if (isText(point.node) || !hasChildren(point.node) || dom_isEmpty(point.node)) {\n    return true;\n  }\n\n  var leftNode = point.node.childNodes[point.offset - 1];\n  var rightNode = point.node.childNodes[point.offset];\n\n  if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {\n    return true;\n  }\n\n  return false;\n}\n/**\n * @method prevPointUtil\n *\n * @param {BoundaryPoint} point\n * @param {Function} pred\n * @return {BoundaryPoint}\n */\n\n\nfunction prevPointUntil(point, pred) {\n  while (point) {\n    if (pred(point)) {\n      return point;\n    }\n\n    point = dom_prevPoint(point);\n  }\n\n  return null;\n}\n/**\n * @method nextPointUntil\n *\n * @param {BoundaryPoint} point\n * @param {Function} pred\n * @return {BoundaryPoint}\n */\n\n\nfunction nextPointUntil(point, pred) {\n  while (point) {\n    if (pred(point)) {\n      return point;\n    }\n\n    point = dom_nextPoint(point);\n  }\n\n  return null;\n}\n/**\n * returns whether point has character or not.\n *\n * @param {Point} point\n * @return {Boolean}\n */\n\n\nfunction isCharPoint(point) {\n  if (!isText(point.node)) {\n    return false;\n  }\n\n  var ch = point.node.nodeValue.charAt(point.offset - 1);\n  return ch && ch !== ' ' && ch !== NBSP_CHAR;\n}\n/**\n * returns whether point has space or not.\n *\n * @param {Point} point\n * @return {Boolean}\n */\n\n\nfunction isSpacePoint(point) {\n  if (!isText(point.node)) {\n    return false;\n  }\n\n  var ch = point.node.nodeValue.charAt(point.offset - 1);\n  return ch === ' ' || ch === NBSP_CHAR;\n}\n/**\n * @method walkPoint\n *\n * @param {BoundaryPoint} startPoint\n * @param {BoundaryPoint} endPoint\n * @param {Function} handler\n * @param {Boolean} isSkipInnerOffset\n */\n\n\nfunction walkPoint(startPoint, endPoint, handler, isSkipInnerOffset) {\n  var point = startPoint;\n\n  while (point) {\n    handler(point);\n\n    if (isSamePoint(point, endPoint)) {\n      break;\n    }\n\n    var isSkipOffset = isSkipInnerOffset && startPoint.node !== point.node && endPoint.node !== point.node;\n    point = nextPointWithEmptyNode(point, isSkipOffset);\n  }\n}\n/**\n * @method makeOffsetPath\n *\n * return offsetPath(array of offset) from ancestor\n *\n * @param {Node} ancestor - ancestor node\n * @param {Node} node\n */\n\n\nfunction makeOffsetPath(ancestor, node) {\n  var ancestors = listAncestor(node, func.eq(ancestor));\n  return ancestors.map(dom_position).reverse();\n}\n/**\n * @method fromOffsetPath\n *\n * return element from offsetPath(array of offset)\n *\n * @param {Node} ancestor - ancestor node\n * @param {array} offsets - offsetPath\n */\n\n\nfunction fromOffsetPath(ancestor, offsets) {\n  var current = ancestor;\n\n  for (var i = 0, len = offsets.length; i < len; i++) {\n    if (current.childNodes.length <= offsets[i]) {\n      current = current.childNodes[current.childNodes.length - 1];\n    } else {\n      current = current.childNodes[offsets[i]];\n    }\n  }\n\n  return current;\n}\n/**\n * @method splitNode\n *\n * split element or #text\n *\n * @param {BoundaryPoint} point\n * @param {Object} [options]\n * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n * @param {Boolean} [options.isDiscardEmptySplits] - default: false\n * @return {Node} right node of boundaryPoint\n */\n\n\nfunction splitNode(point, options) {\n  var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;\n  var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;\n  var isDiscardEmptySplits = options && options.isDiscardEmptySplits;\n\n  if (isDiscardEmptySplits) {\n    isSkipPaddingBlankHTML = true;\n  } // edge case\n\n\n  if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {\n    if (isLeftEdgePoint(point)) {\n      return point.node;\n    } else if (isRightEdgePoint(point)) {\n      return point.node.nextSibling;\n    }\n  } // split #text\n\n\n  if (isText(point.node)) {\n    return point.node.splitText(point.offset);\n  } else {\n    var childNode = point.node.childNodes[point.offset];\n    var clone = insertAfter(point.node.cloneNode(false), point.node);\n    appendChildNodes(clone, listNext(childNode));\n\n    if (!isSkipPaddingBlankHTML) {\n      paddingBlankHTML(point.node);\n      paddingBlankHTML(clone);\n    }\n\n    if (isDiscardEmptySplits) {\n      if (dom_isEmpty(point.node)) {\n        remove(point.node);\n      }\n\n      if (dom_isEmpty(clone)) {\n        remove(clone);\n        return point.node.nextSibling;\n      }\n    }\n\n    return clone;\n  }\n}\n/**\n * @method splitTree\n *\n * split tree by point\n *\n * @param {Node} root - split root\n * @param {BoundaryPoint} point\n * @param {Object} [options]\n * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n * @return {Node} right node of boundaryPoint\n */\n\n\nfunction splitTree(root, point, options) {\n  // ex) [#text, <span>, <p>]\n  var ancestors = listAncestor(point.node, func.eq(root));\n\n  if (!ancestors.length) {\n    return null;\n  } else if (ancestors.length === 1) {\n    return splitNode(point, options);\n  }\n\n  return ancestors.reduce(function (node, parent) {\n    if (node === point.node) {\n      node = splitNode(point, options);\n    }\n\n    return splitNode({\n      node: parent,\n      offset: node ? dom_position(node) : nodeLength(parent)\n    }, options);\n  });\n}\n/**\n * split point\n *\n * @param {Point} point\n * @param {Boolean} isInline\n * @return {Object}\n */\n\n\nfunction splitPoint(point, isInline) {\n  // find splitRoot, container\n  //  - inline: splitRoot is a child of paragraph\n  //  - block: splitRoot is a child of bodyContainer\n  var pred = isInline ? isPara : isBodyContainer;\n  var ancestors = listAncestor(point.node, pred);\n  var topAncestor = lists.last(ancestors) || point.node;\n  var splitRoot, container;\n\n  if (pred(topAncestor)) {\n    splitRoot = ancestors[ancestors.length - 2];\n    container = topAncestor;\n  } else {\n    splitRoot = topAncestor;\n    container = splitRoot.parentNode;\n  } // if splitRoot is exists, split with splitTree\n\n\n  var pivot = splitRoot && splitTree(splitRoot, point, {\n    isSkipPaddingBlankHTML: isInline,\n    isNotSplitEdgePoint: isInline\n  }); // if container is point.node, find pivot with point.offset\n\n  if (!pivot && container === point.node) {\n    pivot = point.node.childNodes[point.offset];\n  }\n\n  return {\n    rightNode: pivot,\n    container: container\n  };\n}\n\nfunction dom_create(nodeName) {\n  return document.createElement(nodeName);\n}\n\nfunction createText(text) {\n  return document.createTextNode(text);\n}\n/**\n * @method remove\n *\n * remove node, (isRemoveChild: remove child or not)\n *\n * @param {Node} node\n * @param {Boolean} isRemoveChild\n */\n\n\nfunction remove(node, isRemoveChild) {\n  if (!node || !node.parentNode) {\n    return;\n  }\n\n  if (node.removeNode) {\n    return node.removeNode(isRemoveChild);\n  }\n\n  var parent = node.parentNode;\n\n  if (!isRemoveChild) {\n    var nodes = [];\n\n    for (var i = 0, len = node.childNodes.length; i < len; i++) {\n      nodes.push(node.childNodes[i]);\n    }\n\n    for (var _i = 0, _len = nodes.length; _i < _len; _i++) {\n      parent.insertBefore(nodes[_i], node);\n    }\n  }\n\n  parent.removeChild(node);\n}\n/**\n * @method removeWhile\n *\n * @param {Node} node\n * @param {Function} pred\n */\n\n\nfunction removeWhile(node, pred) {\n  while (node) {\n    if (isEditable(node) || !pred(node)) {\n      break;\n    }\n\n    var parent = node.parentNode;\n    remove(node);\n    node = parent;\n  }\n}\n/**\n * @method replace\n *\n * replace node with provided nodeName\n *\n * @param {Node} node\n * @param {String} nodeName\n * @return {Node} - new node\n */\n\n\nfunction dom_replace(node, nodeName) {\n  if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {\n    return node;\n  }\n\n  var newNode = dom_create(nodeName);\n\n  if (node.style.cssText) {\n    newNode.style.cssText = node.style.cssText;\n  }\n\n  appendChildNodes(newNode, lists.from(node.childNodes));\n  insertAfter(newNode, node);\n  remove(node);\n  return newNode;\n}\n\nvar isTextarea = makePredByNodeName('TEXTAREA');\n/**\n * @param {jQuery} $node\n * @param {Boolean} [stripLinebreaks] - default: false\n */\n\nfunction dom_value($node, stripLinebreaks) {\n  var val = isTextarea($node[0]) ? $node.val() : $node.html();\n\n  if (stripLinebreaks) {\n    return val.replace(/[\\n\\r]/g, '');\n  }\n\n  return val;\n}\n/**\n * @method html\n *\n * get the HTML contents of node\n *\n * @param {jQuery} $node\n * @param {Boolean} [isNewlineOnBlock]\n */\n\n\nfunction dom_html($node, isNewlineOnBlock) {\n  var markup = dom_value($node);\n\n  if (isNewlineOnBlock) {\n    var regexTag = /<(\\/?)(\\b(?!!)[^>\\s]*)(.*?)(\\s*\\/?>)/g;\n    markup = markup.replace(regexTag, function (match, endSlash, name) {\n      name = name.toUpperCase();\n      var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) && !!endSlash;\n      var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);\n      return match + (isEndOfInlineContainer || isBlockNode ? '\\n' : '');\n    });\n    markup = markup.trim();\n  }\n\n  return markup;\n}\n\nfunction posFromPlaceholder(placeholder) {\n  var $placeholder = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(placeholder);\n  var pos = $placeholder.offset();\n  var height = $placeholder.outerHeight(true); // include margin\n\n  return {\n    left: pos.left,\n    top: pos.top + height\n  };\n}\n\nfunction attachEvents($node, events) {\n  Object.keys(events).forEach(function (key) {\n    $node.on(key, events[key]);\n  });\n}\n\nfunction detachEvents($node, events) {\n  Object.keys(events).forEach(function (key) {\n    $node.off(key, events[key]);\n  });\n}\n/**\n * @method isCustomStyleTag\n *\n * assert if a node contains a \"note-styletag\" class,\n * which implies that's a custom-made style tag node\n *\n * @param {Node} an HTML DOM node\n */\n\n\nfunction isCustomStyleTag(node) {\n  return node && !isText(node) && lists.contains(node.classList, 'note-styletag');\n}\n\n/* harmony default export */ var dom = ({\n  /** @property {String} NBSP_CHAR */\n  NBSP_CHAR: NBSP_CHAR,\n\n  /** @property {String} ZERO_WIDTH_NBSP_CHAR */\n  ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,\n\n  /** @property {String} blank */\n  blank: blankHTML,\n\n  /** @property {String} emptyPara */\n  emptyPara: \"<p>\".concat(blankHTML, \"</p>\"),\n  makePredByNodeName: makePredByNodeName,\n  isEditable: isEditable,\n  isControlSizing: isControlSizing,\n  isText: isText,\n  isElement: isElement,\n  isVoid: isVoid,\n  isPara: isPara,\n  isPurePara: isPurePara,\n  isHeading: isHeading,\n  isInline: dom_isInline,\n  isBlock: func.not(dom_isInline),\n  isBodyInline: isBodyInline,\n  isBody: isBody,\n  isParaInline: isParaInline,\n  isPre: isPre,\n  isList: isList,\n  isTable: isTable,\n  isData: isData,\n  isCell: dom_isCell,\n  isBlockquote: isBlockquote,\n  isBodyContainer: isBodyContainer,\n  isAnchor: isAnchor,\n  isDiv: makePredByNodeName('DIV'),\n  isLi: isLi,\n  isBR: makePredByNodeName('BR'),\n  isSpan: makePredByNodeName('SPAN'),\n  isB: makePredByNodeName('B'),\n  isU: makePredByNodeName('U'),\n  isS: makePredByNodeName('S'),\n  isI: makePredByNodeName('I'),\n  isImg: makePredByNodeName('IMG'),\n  isTextarea: isTextarea,\n  deepestChildIsEmpty: deepestChildIsEmpty,\n  isEmpty: dom_isEmpty,\n  isEmptyAnchor: func.and(isAnchor, dom_isEmpty),\n  isClosestSibling: isClosestSibling,\n  withClosestSiblings: withClosestSiblings,\n  nodeLength: nodeLength,\n  isLeftEdgePoint: isLeftEdgePoint,\n  isRightEdgePoint: isRightEdgePoint,\n  isEdgePoint: isEdgePoint,\n  isLeftEdgeOf: dom_isLeftEdgeOf,\n  isRightEdgeOf: isRightEdgeOf,\n  isLeftEdgePointOf: isLeftEdgePointOf,\n  isRightEdgePointOf: isRightEdgePointOf,\n  prevPoint: dom_prevPoint,\n  nextPoint: dom_nextPoint,\n  nextPointWithEmptyNode: nextPointWithEmptyNode,\n  isSamePoint: isSamePoint,\n  isVisiblePoint: isVisiblePoint,\n  prevPointUntil: prevPointUntil,\n  nextPointUntil: nextPointUntil,\n  isCharPoint: isCharPoint,\n  isSpacePoint: isSpacePoint,\n  walkPoint: walkPoint,\n  ancestor: dom_ancestor,\n  singleChildAncestor: singleChildAncestor,\n  listAncestor: listAncestor,\n  lastAncestor: lastAncestor,\n  listNext: listNext,\n  listPrev: listPrev,\n  listDescendant: listDescendant,\n  commonAncestor: dom_commonAncestor,\n  wrap: wrap,\n  insertAfter: insertAfter,\n  appendChildNodes: appendChildNodes,\n  position: dom_position,\n  hasChildren: hasChildren,\n  makeOffsetPath: makeOffsetPath,\n  fromOffsetPath: fromOffsetPath,\n  splitTree: splitTree,\n  splitPoint: splitPoint,\n  create: dom_create,\n  createText: createText,\n  remove: remove,\n  removeWhile: removeWhile,\n  replace: dom_replace,\n  html: dom_html,\n  value: dom_value,\n  posFromPlaceholder: posFromPlaceholder,\n  attachEvents: attachEvents,\n  detachEvents: detachEvents,\n  isCustomStyleTag: isCustomStyleTag\n});\n// CONCATENATED MODULE: ./src/js/base/Context.js\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\nvar Context_Context = /*#__PURE__*/function () {\n  /**\n   * @param {jQuery} $note\n   * @param {Object} options\n   */\n  function Context($note, options) {\n    _classCallCheck(this, Context);\n\n    this.$note = $note;\n    this.memos = {};\n    this.modules = {};\n    this.layoutInfo = {};\n    this.options = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(true, {}, options); // init ui with options\n\n    external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui_template(this.options);\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.initialize();\n  }\n  /**\n   * create layout and initialize modules and other resources\n   */\n\n\n  _createClass(Context, [{\n    key: \"initialize\",\n    value: function initialize() {\n      this.layoutInfo = this.ui.createLayout(this.$note);\n\n      this._initialize();\n\n      this.$note.hide();\n      return this;\n    }\n    /**\n     * destroy modules and other resources and remove layout\n     */\n\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this._destroy();\n\n      this.$note.removeData('summernote');\n      this.ui.removeLayout(this.$note, this.layoutInfo);\n    }\n    /**\n     * destory modules and other resources and initialize it again\n     */\n\n  }, {\n    key: \"reset\",\n    value: function reset() {\n      var disabled = this.isDisabled();\n      this.code(dom.emptyPara);\n\n      this._destroy();\n\n      this._initialize();\n\n      if (disabled) {\n        this.disable();\n      }\n    }\n  }, {\n    key: \"_initialize\",\n    value: function _initialize() {\n      var _this = this;\n\n      // set own id\n      this.options.id = func.uniqueId(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.now()); // set default container for tooltips, popovers, and dialogs\n\n      this.options.container = this.options.container || this.layoutInfo.editor; // add optional buttons\n\n      var buttons = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend({}, this.options.buttons);\n      Object.keys(buttons).forEach(function (key) {\n        _this.memo('button.' + key, buttons[key]);\n      });\n      var modules = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend({}, this.options.modules, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.plugins || {}); // add and initialize modules\n\n      Object.keys(modules).forEach(function (key) {\n        _this.module(key, modules[key], true);\n      });\n      Object.keys(this.modules).forEach(function (key) {\n        _this.initializeModule(key);\n      });\n    }\n  }, {\n    key: \"_destroy\",\n    value: function _destroy() {\n      var _this2 = this;\n\n      // destroy modules with reversed order\n      Object.keys(this.modules).reverse().forEach(function (key) {\n        _this2.removeModule(key);\n      });\n      Object.keys(this.memos).forEach(function (key) {\n        _this2.removeMemo(key);\n      }); // trigger custom onDestroy callback\n\n      this.triggerEvent('destroy', this);\n    }\n  }, {\n    key: \"code\",\n    value: function code(html) {\n      var isActivated = this.invoke('codeview.isActivated');\n\n      if (html === undefined) {\n        this.invoke('codeview.sync');\n        return isActivated ? this.layoutInfo.codable.val() : this.layoutInfo.editable.html();\n      } else {\n        if (isActivated) {\n          this.invoke('codeview.sync', html);\n        } else {\n          this.layoutInfo.editable.html(html);\n        }\n\n        this.$note.val(html);\n        this.triggerEvent('change', html, this.layoutInfo.editable);\n      }\n    }\n  }, {\n    key: \"isDisabled\",\n    value: function isDisabled() {\n      return this.layoutInfo.editable.attr('contenteditable') === 'false';\n    }\n  }, {\n    key: \"enable\",\n    value: function enable() {\n      this.layoutInfo.editable.attr('contenteditable', true);\n      this.invoke('toolbar.activate', true);\n      this.triggerEvent('disable', false);\n      this.options.editing = true;\n    }\n  }, {\n    key: \"disable\",\n    value: function disable() {\n      // close codeview if codeview is opend\n      if (this.invoke('codeview.isActivated')) {\n        this.invoke('codeview.deactivate');\n      }\n\n      this.layoutInfo.editable.attr('contenteditable', false);\n      this.options.editing = false;\n      this.invoke('toolbar.deactivate', true);\n      this.triggerEvent('disable', true);\n    }\n  }, {\n    key: \"triggerEvent\",\n    value: function triggerEvent() {\n      var namespace = lists.head(arguments);\n      var args = lists.tail(lists.from(arguments));\n      var callback = this.options.callbacks[func.namespaceToCamel(namespace, 'on')];\n\n      if (callback) {\n        callback.apply(this.$note[0], args);\n      }\n\n      this.$note.trigger('summernote.' + namespace, args);\n    }\n  }, {\n    key: \"initializeModule\",\n    value: function initializeModule(key) {\n      var module = this.modules[key];\n      module.shouldInitialize = module.shouldInitialize || func.ok;\n\n      if (!module.shouldInitialize()) {\n        return;\n      } // initialize module\n\n\n      if (module.initialize) {\n        module.initialize();\n      } // attach events\n\n\n      if (module.events) {\n        dom.attachEvents(this.$note, module.events);\n      }\n    }\n  }, {\n    key: \"module\",\n    value: function module(key, ModuleClass, withoutIntialize) {\n      if (arguments.length === 1) {\n        return this.modules[key];\n      }\n\n      this.modules[key] = new ModuleClass(this);\n\n      if (!withoutIntialize) {\n        this.initializeModule(key);\n      }\n    }\n  }, {\n    key: \"removeModule\",\n    value: function removeModule(key) {\n      var module = this.modules[key];\n\n      if (module.shouldInitialize()) {\n        if (module.events) {\n          dom.detachEvents(this.$note, module.events);\n        }\n\n        if (module.destroy) {\n          module.destroy();\n        }\n      }\n\n      delete this.modules[key];\n    }\n  }, {\n    key: \"memo\",\n    value: function memo(key, obj) {\n      if (arguments.length === 1) {\n        return this.memos[key];\n      }\n\n      this.memos[key] = obj;\n    }\n  }, {\n    key: \"removeMemo\",\n    value: function removeMemo(key) {\n      if (this.memos[key] && this.memos[key].destroy) {\n        this.memos[key].destroy();\n      }\n\n      delete this.memos[key];\n    }\n    /**\n     * Some buttons need to change their visual style immediately once they get pressed\n     */\n\n  }, {\n    key: \"createInvokeHandlerAndUpdateState\",\n    value: function createInvokeHandlerAndUpdateState(namespace, value) {\n      var _this3 = this;\n\n      return function (event) {\n        _this3.createInvokeHandler(namespace, value)(event);\n\n        _this3.invoke('buttons.updateCurrentStyle');\n      };\n    }\n  }, {\n    key: \"createInvokeHandler\",\n    value: function createInvokeHandler(namespace, value) {\n      var _this4 = this;\n\n      return function (event) {\n        event.preventDefault();\n        var $target = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(event.target);\n\n        _this4.invoke(namespace, value || $target.closest('[data-value]').data('value'), $target);\n      };\n    }\n  }, {\n    key: \"invoke\",\n    value: function invoke() {\n      var namespace = lists.head(arguments);\n      var args = lists.tail(lists.from(arguments));\n      var splits = namespace.split('.');\n      var hasSeparator = splits.length > 1;\n      var moduleName = hasSeparator && lists.head(splits);\n      var methodName = hasSeparator ? lists.last(splits) : lists.head(splits);\n      var module = this.modules[moduleName || 'editor'];\n\n      if (!moduleName && this[methodName]) {\n        return this[methodName].apply(this, args);\n      } else if (module && module[methodName] && module.shouldInitialize()) {\n        return module[methodName].apply(module, args);\n      }\n    }\n  }]);\n\n  return Context;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/summernote.js\n\n\n\n\nexternal_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.fn.extend({\n  /**\n   * Summernote API\n   *\n   * @param {Object|String}\n   * @return {this}\n   */\n  summernote: function summernote() {\n    var type = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.type(lists.head(arguments));\n    var isExternalAPICalled = type === 'string';\n    var hasInitOptions = type === 'object';\n    var options = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend({}, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.options, hasInitOptions ? lists.head(arguments) : {}); // Update options\n\n    options.langInfo = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(true, {}, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.lang['en-US'], external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.lang[options.lang]);\n    options.icons = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(true, {}, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.options.icons, options.icons);\n    options.tooltip = options.tooltip === 'auto' ? !env.isSupportTouch : options.tooltip;\n    this.each(function (idx, note) {\n      var $note = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(note);\n\n      if (!$note.data('summernote')) {\n        var context = new Context_Context($note, options);\n        $note.data('summernote', context);\n        $note.data('summernote').triggerEvent('init', context.layoutInfo);\n      }\n    });\n    var $note = this.first();\n\n    if ($note.length) {\n      var context = $note.data('summernote');\n\n      if (isExternalAPICalled) {\n        return context.invoke.apply(context, lists.from(arguments));\n      } else if (options.focus) {\n        context.invoke('editor.focus');\n      }\n    }\n\n    return this;\n  }\n});\n// CONCATENATED MODULE: ./src/js/base/core/range.js\nfunction range_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction range_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction range_createClass(Constructor, protoProps, staticProps) { if (protoProps) range_defineProperties(Constructor.prototype, protoProps); if (staticProps) range_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\n/**\n * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js\n *\n * @param {TextRange} textRange\n * @param {Boolean} isStart\n * @return {BoundaryPoint}\n *\n * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx\n */\n\nfunction textRangeToPoint(textRange, isStart) {\n  var container = textRange.parentElement();\n  var offset;\n  var tester = document.body.createTextRange();\n  var prevContainer;\n  var childNodes = lists.from(container.childNodes);\n\n  for (offset = 0; offset < childNodes.length; offset++) {\n    if (dom.isText(childNodes[offset])) {\n      continue;\n    }\n\n    tester.moveToElementText(childNodes[offset]);\n\n    if (tester.compareEndPoints('StartToStart', textRange) >= 0) {\n      break;\n    }\n\n    prevContainer = childNodes[offset];\n  }\n\n  if (offset !== 0 && dom.isText(childNodes[offset - 1])) {\n    var textRangeStart = document.body.createTextRange();\n    var curTextNode = null;\n    textRangeStart.moveToElementText(prevContainer || container);\n    textRangeStart.collapse(!prevContainer);\n    curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;\n    var pointTester = textRange.duplicate();\n    pointTester.setEndPoint('StartToStart', textRangeStart);\n    var textCount = pointTester.text.replace(/[\\r\\n]/g, '').length;\n\n    while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {\n      textCount -= curTextNode.nodeValue.length;\n      curTextNode = curTextNode.nextSibling;\n    } // [workaround] enforce IE to re-reference curTextNode, hack\n\n\n    var dummy = curTextNode.nodeValue; // eslint-disable-line\n\n    if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) && textCount === curTextNode.nodeValue.length) {\n      textCount -= curTextNode.nodeValue.length;\n      curTextNode = curTextNode.nextSibling;\n    }\n\n    container = curTextNode;\n    offset = textCount;\n  }\n\n  return {\n    cont: container,\n    offset: offset\n  };\n}\n/**\n * return TextRange from boundary point (inspired by google closure-library)\n * @param {BoundaryPoint} point\n * @return {TextRange}\n */\n\n\nfunction pointToTextRange(point) {\n  var textRangeInfo = function textRangeInfo(container, offset) {\n    var node, isCollapseToStart;\n\n    if (dom.isText(container)) {\n      var prevTextNodes = dom.listPrev(container, func.not(dom.isText));\n      var prevContainer = lists.last(prevTextNodes).previousSibling;\n      node = prevContainer || container.parentNode;\n      offset += lists.sum(lists.tail(prevTextNodes), dom.nodeLength);\n      isCollapseToStart = !prevContainer;\n    } else {\n      node = container.childNodes[offset] || container;\n\n      if (dom.isText(node)) {\n        return textRangeInfo(node, 0);\n      }\n\n      offset = 0;\n      isCollapseToStart = false;\n    }\n\n    return {\n      node: node,\n      collapseToStart: isCollapseToStart,\n      offset: offset\n    };\n  };\n\n  var textRange = document.body.createTextRange();\n  var info = textRangeInfo(point.node, point.offset);\n  textRange.moveToElementText(info.node);\n  textRange.collapse(info.collapseToStart);\n  textRange.moveStart('character', info.offset);\n  return textRange;\n}\n/**\n   * Wrapped Range\n   *\n   * @constructor\n   * @param {Node} sc - start container\n   * @param {Number} so - start offset\n   * @param {Node} ec - end container\n   * @param {Number} eo - end offset\n   */\n\n\nvar range_WrappedRange = /*#__PURE__*/function () {\n  function WrappedRange(sc, so, ec, eo) {\n    range_classCallCheck(this, WrappedRange);\n\n    this.sc = sc;\n    this.so = so;\n    this.ec = ec;\n    this.eo = eo; // isOnEditable: judge whether range is on editable or not\n\n    this.isOnEditable = this.makeIsOn(dom.isEditable); // isOnList: judge whether range is on list node or not\n\n    this.isOnList = this.makeIsOn(dom.isList); // isOnAnchor: judge whether range is on anchor node or not\n\n    this.isOnAnchor = this.makeIsOn(dom.isAnchor); // isOnCell: judge whether range is on cell node or not\n\n    this.isOnCell = this.makeIsOn(dom.isCell); // isOnData: judge whether range is on data node or not\n\n    this.isOnData = this.makeIsOn(dom.isData);\n  } // nativeRange: get nativeRange from sc, so, ec, eo\n\n\n  range_createClass(WrappedRange, [{\n    key: \"nativeRange\",\n    value: function nativeRange() {\n      if (env.isW3CRangeSupport) {\n        var w3cRange = document.createRange();\n        w3cRange.setStart(this.sc, this.so);\n        w3cRange.setEnd(this.ec, this.eo);\n        return w3cRange;\n      } else {\n        var textRange = pointToTextRange({\n          node: this.sc,\n          offset: this.so\n        });\n        textRange.setEndPoint('EndToEnd', pointToTextRange({\n          node: this.ec,\n          offset: this.eo\n        }));\n        return textRange;\n      }\n    }\n  }, {\n    key: \"getPoints\",\n    value: function getPoints() {\n      return {\n        sc: this.sc,\n        so: this.so,\n        ec: this.ec,\n        eo: this.eo\n      };\n    }\n  }, {\n    key: \"getStartPoint\",\n    value: function getStartPoint() {\n      return {\n        node: this.sc,\n        offset: this.so\n      };\n    }\n  }, {\n    key: \"getEndPoint\",\n    value: function getEndPoint() {\n      return {\n        node: this.ec,\n        offset: this.eo\n      };\n    }\n    /**\n     * select update visible range\n     */\n\n  }, {\n    key: \"select\",\n    value: function select() {\n      var nativeRng = this.nativeRange();\n\n      if (env.isW3CRangeSupport) {\n        var selection = document.getSelection();\n\n        if (selection.rangeCount > 0) {\n          selection.removeAllRanges();\n        }\n\n        selection.addRange(nativeRng);\n      } else {\n        nativeRng.select();\n      }\n\n      return this;\n    }\n    /**\n     * Moves the scrollbar to start container(sc) of current range\n     *\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"scrollIntoView\",\n    value: function scrollIntoView(container) {\n      var height = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(container).height();\n\n      if (container.scrollTop + height < this.sc.offsetTop) {\n        container.scrollTop += Math.abs(container.scrollTop + height - this.sc.offsetTop);\n      }\n\n      return this;\n    }\n    /**\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"normalize\",\n    value: function normalize() {\n      /**\n       * @param {BoundaryPoint} point\n       * @param {Boolean} isLeftToRight - true: prefer to choose right node\n       *                                - false: prefer to choose left node\n       * @return {BoundaryPoint}\n       */\n      var getVisiblePoint = function getVisiblePoint(point, isLeftToRight) {\n        if (!point) {\n          return point;\n        } // Just use the given point [XXX:Adhoc]\n        //  - case 01. if the point is on the middle of the node\n        //  - case 02. if the point is on the right edge and prefer to choose left node\n        //  - case 03. if the point is on the left edge and prefer to choose right node\n        //  - case 04. if the point is on the right edge and prefer to choose right node but the node is void\n        //  - case 05. if the point is on the left edge and prefer to choose left node but the node is void\n        //  - case 06. if the point is on the block node and there is no children\n\n\n        if (dom.isVisiblePoint(point)) {\n          if (!dom.isEdgePoint(point) || dom.isRightEdgePoint(point) && !isLeftToRight || dom.isLeftEdgePoint(point) && isLeftToRight || dom.isRightEdgePoint(point) && isLeftToRight && dom.isVoid(point.node.nextSibling) || dom.isLeftEdgePoint(point) && !isLeftToRight && dom.isVoid(point.node.previousSibling) || dom.isBlock(point.node) && dom.isEmpty(point.node)) {\n            return point;\n          }\n        } // point on block's edge\n\n\n        var block = dom.ancestor(point.node, dom.isBlock);\n        var hasRightNode = false;\n\n        if (!hasRightNode) {\n          var prevPoint = dom.prevPoint(point) || {\n            node: null\n          };\n          hasRightNode = (dom.isLeftEdgePointOf(point, block) || dom.isVoid(prevPoint.node)) && !isLeftToRight;\n        }\n\n        var hasLeftNode = false;\n\n        if (!hasLeftNode) {\n          var _nextPoint = dom.nextPoint(point) || {\n            node: null\n          };\n\n          hasLeftNode = (dom.isRightEdgePointOf(point, block) || dom.isVoid(_nextPoint.node)) && isLeftToRight;\n        }\n\n        if (hasRightNode || hasLeftNode) {\n          // returns point already on visible point\n          if (dom.isVisiblePoint(point)) {\n            return point;\n          } // reverse direction\n\n\n          isLeftToRight = !isLeftToRight;\n        }\n\n        var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint) : dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);\n        return nextPoint || point;\n      };\n\n      var endPoint = getVisiblePoint(this.getEndPoint(), false);\n      var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);\n      return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);\n    }\n    /**\n     * returns matched nodes on range\n     *\n     * @param {Function} [pred] - predicate function\n     * @param {Object} [options]\n     * @param {Boolean} [options.includeAncestor]\n     * @param {Boolean} [options.fullyContains]\n     * @return {Node[]}\n     */\n\n  }, {\n    key: \"nodes\",\n    value: function nodes(pred, options) {\n      pred = pred || func.ok;\n      var includeAncestor = options && options.includeAncestor;\n      var fullyContains = options && options.fullyContains; // TODO compare points and sort\n\n      var startPoint = this.getStartPoint();\n      var endPoint = this.getEndPoint();\n      var nodes = [];\n      var leftEdgeNodes = [];\n      dom.walkPoint(startPoint, endPoint, function (point) {\n        if (dom.isEditable(point.node)) {\n          return;\n        }\n\n        var node;\n\n        if (fullyContains) {\n          if (dom.isLeftEdgePoint(point)) {\n            leftEdgeNodes.push(point.node);\n          }\n\n          if (dom.isRightEdgePoint(point) && lists.contains(leftEdgeNodes, point.node)) {\n            node = point.node;\n          }\n        } else if (includeAncestor) {\n          node = dom.ancestor(point.node, pred);\n        } else {\n          node = point.node;\n        }\n\n        if (node && pred(node)) {\n          nodes.push(node);\n        }\n      }, true);\n      return lists.unique(nodes);\n    }\n    /**\n     * returns commonAncestor of range\n     * @return {Element} - commonAncestor\n     */\n\n  }, {\n    key: \"commonAncestor\",\n    value: function commonAncestor() {\n      return dom.commonAncestor(this.sc, this.ec);\n    }\n    /**\n     * returns expanded range by pred\n     *\n     * @param {Function} pred - predicate function\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"expand\",\n    value: function expand(pred) {\n      var startAncestor = dom.ancestor(this.sc, pred);\n      var endAncestor = dom.ancestor(this.ec, pred);\n\n      if (!startAncestor && !endAncestor) {\n        return new WrappedRange(this.sc, this.so, this.ec, this.eo);\n      }\n\n      var boundaryPoints = this.getPoints();\n\n      if (startAncestor) {\n        boundaryPoints.sc = startAncestor;\n        boundaryPoints.so = 0;\n      }\n\n      if (endAncestor) {\n        boundaryPoints.ec = endAncestor;\n        boundaryPoints.eo = dom.nodeLength(endAncestor);\n      }\n\n      return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);\n    }\n    /**\n     * @param {Boolean} isCollapseToStart\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"collapse\",\n    value: function collapse(isCollapseToStart) {\n      if (isCollapseToStart) {\n        return new WrappedRange(this.sc, this.so, this.sc, this.so);\n      } else {\n        return new WrappedRange(this.ec, this.eo, this.ec, this.eo);\n      }\n    }\n    /**\n     * splitText on range\n     */\n\n  }, {\n    key: \"splitText\",\n    value: function splitText() {\n      var isSameContainer = this.sc === this.ec;\n      var boundaryPoints = this.getPoints();\n\n      if (dom.isText(this.ec) && !dom.isEdgePoint(this.getEndPoint())) {\n        this.ec.splitText(this.eo);\n      }\n\n      if (dom.isText(this.sc) && !dom.isEdgePoint(this.getStartPoint())) {\n        boundaryPoints.sc = this.sc.splitText(this.so);\n        boundaryPoints.so = 0;\n\n        if (isSameContainer) {\n          boundaryPoints.ec = boundaryPoints.sc;\n          boundaryPoints.eo = this.eo - this.so;\n        }\n      }\n\n      return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);\n    }\n    /**\n     * delete contents on range\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"deleteContents\",\n    value: function deleteContents() {\n      if (this.isCollapsed()) {\n        return this;\n      }\n\n      var rng = this.splitText();\n      var nodes = rng.nodes(null, {\n        fullyContains: true\n      }); // find new cursor point\n\n      var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {\n        return !lists.contains(nodes, point.node);\n      });\n      var emptyParents = [];\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(nodes, function (idx, node) {\n        // find empty parents\n        var parent = node.parentNode;\n\n        if (point.node !== parent && dom.nodeLength(parent) === 1) {\n          emptyParents.push(parent);\n        }\n\n        dom.remove(node, false);\n      }); // remove empty parents\n\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(emptyParents, function (idx, node) {\n        dom.remove(node, false);\n      });\n      return new WrappedRange(point.node, point.offset, point.node, point.offset).normalize();\n    }\n    /**\n     * makeIsOn: return isOn(pred) function\n     */\n\n  }, {\n    key: \"makeIsOn\",\n    value: function makeIsOn(pred) {\n      return function () {\n        var ancestor = dom.ancestor(this.sc, pred);\n        return !!ancestor && ancestor === dom.ancestor(this.ec, pred);\n      };\n    }\n    /**\n     * @param {Function} pred\n     * @return {Boolean}\n     */\n\n  }, {\n    key: \"isLeftEdgeOf\",\n    value: function isLeftEdgeOf(pred) {\n      if (!dom.isLeftEdgePoint(this.getStartPoint())) {\n        return false;\n      }\n\n      var node = dom.ancestor(this.sc, pred);\n      return node && dom.isLeftEdgeOf(this.sc, node);\n    }\n    /**\n     * returns whether range was collapsed or not\n     */\n\n  }, {\n    key: \"isCollapsed\",\n    value: function isCollapsed() {\n      return this.sc === this.ec && this.so === this.eo;\n    }\n    /**\n     * wrap inline nodes which children of body with paragraph\n     *\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"wrapBodyInlineWithPara\",\n    value: function wrapBodyInlineWithPara() {\n      if (dom.isBodyContainer(this.sc) && dom.isEmpty(this.sc)) {\n        this.sc.innerHTML = dom.emptyPara;\n        return new WrappedRange(this.sc.firstChild, 0, this.sc.firstChild, 0);\n      }\n      /**\n       * [workaround] firefox often create range on not visible point. so normalize here.\n       *  - firefox: |<p>text</p>|\n       *  - chrome: <p>|text|</p>\n       */\n\n\n      var rng = this.normalize();\n\n      if (dom.isParaInline(this.sc) || dom.isPara(this.sc)) {\n        return rng;\n      } // find inline top ancestor\n\n\n      var topAncestor;\n\n      if (dom.isInline(rng.sc)) {\n        var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));\n        topAncestor = lists.last(ancestors);\n\n        if (!dom.isInline(topAncestor)) {\n          topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];\n        }\n      } else {\n        topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];\n      }\n\n      if (topAncestor) {\n        // siblings not in paragraph\n        var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();\n        inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline)); // wrap with paragraph\n\n        if (inlineSiblings.length) {\n          var para = dom.wrap(lists.head(inlineSiblings), 'p');\n          dom.appendChildNodes(para, lists.tail(inlineSiblings));\n        }\n      }\n\n      return this.normalize();\n    }\n    /**\n     * insert node at current cursor\n     *\n     * @param {Node} node\n     * @return {Node}\n     */\n\n  }, {\n    key: \"insertNode\",\n    value: function insertNode(node) {\n      var rng = this;\n\n      if (dom.isText(node) || dom.isInline(node)) {\n        rng = this.wrapBodyInlineWithPara().deleteContents();\n      }\n\n      var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));\n\n      if (info.rightNode) {\n        info.rightNode.parentNode.insertBefore(node, info.rightNode);\n\n        if (dom.isEmpty(info.rightNode) && dom.isPara(node)) {\n          info.rightNode.parentNode.removeChild(info.rightNode);\n        }\n      } else {\n        info.container.appendChild(node);\n      }\n\n      return node;\n    }\n    /**\n     * insert html at current cursor\n     */\n\n  }, {\n    key: \"pasteHTML\",\n    value: function pasteHTML(markup) {\n      markup = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.trim(markup);\n      var contentsContainer = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div></div>').html(markup)[0];\n      var childNodes = lists.from(contentsContainer.childNodes); // const rng = this.wrapBodyInlineWithPara().deleteContents();\n\n      var rng = this;\n      var reversed = false;\n\n      if (rng.so >= 0) {\n        childNodes = childNodes.reverse();\n        reversed = true;\n      }\n\n      childNodes = childNodes.map(function (childNode) {\n        return rng.insertNode(childNode);\n      });\n\n      if (reversed) {\n        childNodes = childNodes.reverse();\n      }\n\n      return childNodes;\n    }\n    /**\n     * returns text in range\n     *\n     * @return {String}\n     */\n\n  }, {\n    key: \"toString\",\n    value: function toString() {\n      var nativeRng = this.nativeRange();\n      return env.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;\n    }\n    /**\n     * returns range for word before cursor\n     *\n     * @param {Boolean} [findAfter] - find after cursor, default: false\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"getWordRange\",\n    value: function getWordRange(findAfter) {\n      var endPoint = this.getEndPoint();\n\n      if (!dom.isCharPoint(endPoint)) {\n        return this;\n      }\n\n      var startPoint = dom.prevPointUntil(endPoint, function (point) {\n        return !dom.isCharPoint(point);\n      });\n\n      if (findAfter) {\n        endPoint = dom.nextPointUntil(endPoint, function (point) {\n          return !dom.isCharPoint(point);\n        });\n      }\n\n      return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);\n    }\n    /**\n     * returns range for words before cursor\n     *\n     * @param {Boolean} [findAfter] - find after cursor, default: false\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"getWordsRange\",\n    value: function getWordsRange(findAfter) {\n      var endPoint = this.getEndPoint();\n\n      var isNotTextPoint = function isNotTextPoint(point) {\n        return !dom.isCharPoint(point) && !dom.isSpacePoint(point);\n      };\n\n      if (isNotTextPoint(endPoint)) {\n        return this;\n      }\n\n      var startPoint = dom.prevPointUntil(endPoint, isNotTextPoint);\n\n      if (findAfter) {\n        endPoint = dom.nextPointUntil(endPoint, isNotTextPoint);\n      }\n\n      return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);\n    }\n    /**\n     * returns range for words before cursor that match with a Regex\n     *\n     * example:\n     *  range: 'hi @Peter Pan'\n     *  regex: '/@[a-z ]+/i'\n     *  return range: '@Peter Pan'\n     *\n     * @param {RegExp} [regex]\n     * @return {WrappedRange|null}\n     */\n\n  }, {\n    key: \"getWordsMatchRange\",\n    value: function getWordsMatchRange(regex) {\n      var endPoint = this.getEndPoint();\n      var startPoint = dom.prevPointUntil(endPoint, function (point) {\n        if (!dom.isCharPoint(point) && !dom.isSpacePoint(point)) {\n          return true;\n        }\n\n        var rng = new WrappedRange(point.node, point.offset, endPoint.node, endPoint.offset);\n        var result = regex.exec(rng.toString());\n        return result && result.index === 0;\n      });\n      var rng = new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);\n      var text = rng.toString();\n      var result = regex.exec(text);\n\n      if (result && result[0].length === text.length) {\n        return rng;\n      } else {\n        return null;\n      }\n    }\n    /**\n     * create offsetPath bookmark\n     *\n     * @param {Node} editable\n     */\n\n  }, {\n    key: \"bookmark\",\n    value: function bookmark(editable) {\n      return {\n        s: {\n          path: dom.makeOffsetPath(editable, this.sc),\n          offset: this.so\n        },\n        e: {\n          path: dom.makeOffsetPath(editable, this.ec),\n          offset: this.eo\n        }\n      };\n    }\n    /**\n     * create offsetPath bookmark base on paragraph\n     *\n     * @param {Node[]} paras\n     */\n\n  }, {\n    key: \"paraBookmark\",\n    value: function paraBookmark(paras) {\n      return {\n        s: {\n          path: lists.tail(dom.makeOffsetPath(lists.head(paras), this.sc)),\n          offset: this.so\n        },\n        e: {\n          path: lists.tail(dom.makeOffsetPath(lists.last(paras), this.ec)),\n          offset: this.eo\n        }\n      };\n    }\n    /**\n     * getClientRects\n     * @return {Rect[]}\n     */\n\n  }, {\n    key: \"getClientRects\",\n    value: function getClientRects() {\n      var nativeRng = this.nativeRange();\n      return nativeRng.getClientRects();\n    }\n  }]);\n\n  return WrappedRange;\n}();\n/**\n * Data structure\n *  * BoundaryPoint: a point of dom tree\n *  * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range\n *\n * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position\n */\n\n\n/* harmony default export */ var range = ({\n  /**\n   * create Range Object From arguments or Browser Selection\n   *\n   * @param {Node} sc - start container\n   * @param {Number} so - start offset\n   * @param {Node} ec - end container\n   * @param {Number} eo - end offset\n   * @return {WrappedRange}\n   */\n  create: function create(sc, so, ec, eo) {\n    if (arguments.length === 4) {\n      return new range_WrappedRange(sc, so, ec, eo);\n    } else if (arguments.length === 2) {\n      // collapsed\n      ec = sc;\n      eo = so;\n      return new range_WrappedRange(sc, so, ec, eo);\n    } else {\n      var wrappedRange = this.createFromSelection();\n\n      if (!wrappedRange && arguments.length === 1) {\n        var bodyElement = arguments[0];\n\n        if (dom.isEditable(bodyElement)) {\n          bodyElement = bodyElement.lastChild;\n        }\n\n        return this.createFromBodyElement(bodyElement, dom.emptyPara === arguments[0].innerHTML);\n      }\n\n      return wrappedRange;\n    }\n  },\n  createFromBodyElement: function createFromBodyElement(bodyElement) {\n    var isCollapseToStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n    var wrappedRange = this.createFromNode(bodyElement);\n    return wrappedRange.collapse(isCollapseToStart);\n  },\n  createFromSelection: function createFromSelection() {\n    var sc, so, ec, eo;\n\n    if (env.isW3CRangeSupport) {\n      var selection = document.getSelection();\n\n      if (!selection || selection.rangeCount === 0) {\n        return null;\n      } else if (dom.isBody(selection.anchorNode)) {\n        // Firefox: returns entire body as range on initialization.\n        // We won't never need it.\n        return null;\n      }\n\n      var nativeRng = selection.getRangeAt(0);\n      sc = nativeRng.startContainer;\n      so = nativeRng.startOffset;\n      ec = nativeRng.endContainer;\n      eo = nativeRng.endOffset;\n    } else {\n      // IE8: TextRange\n      var textRange = document.selection.createRange();\n      var textRangeEnd = textRange.duplicate();\n      textRangeEnd.collapse(false);\n      var textRangeStart = textRange;\n      textRangeStart.collapse(true);\n      var startPoint = textRangeToPoint(textRangeStart, true);\n      var endPoint = textRangeToPoint(textRangeEnd, false); // same visible point case: range was collapsed.\n\n      if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) && dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) && endPoint.node.nextSibling === startPoint.node) {\n        startPoint = endPoint;\n      }\n\n      sc = startPoint.cont;\n      so = startPoint.offset;\n      ec = endPoint.cont;\n      eo = endPoint.offset;\n    }\n\n    return new range_WrappedRange(sc, so, ec, eo);\n  },\n\n  /**\n   * @method\n   *\n   * create WrappedRange from node\n   *\n   * @param {Node} node\n   * @return {WrappedRange}\n   */\n  createFromNode: function createFromNode(node) {\n    var sc = node;\n    var so = 0;\n    var ec = node;\n    var eo = dom.nodeLength(ec); // browsers can't target a picture or void node\n\n    if (dom.isVoid(sc)) {\n      so = dom.listPrev(sc).length - 1;\n      sc = sc.parentNode;\n    }\n\n    if (dom.isBR(ec)) {\n      eo = dom.listPrev(ec).length - 1;\n      ec = ec.parentNode;\n    } else if (dom.isVoid(ec)) {\n      eo = dom.listPrev(ec).length;\n      ec = ec.parentNode;\n    }\n\n    return this.create(sc, so, ec, eo);\n  },\n\n  /**\n   * create WrappedRange from node after position\n   *\n   * @param {Node} node\n   * @return {WrappedRange}\n   */\n  createFromNodeBefore: function createFromNodeBefore(node) {\n    return this.createFromNode(node).collapse(true);\n  },\n\n  /**\n   * create WrappedRange from node after position\n   *\n   * @param {Node} node\n   * @return {WrappedRange}\n   */\n  createFromNodeAfter: function createFromNodeAfter(node) {\n    return this.createFromNode(node).collapse();\n  },\n\n  /**\n   * @method\n   *\n   * create WrappedRange from bookmark\n   *\n   * @param {Node} editable\n   * @param {Object} bookmark\n   * @return {WrappedRange}\n   */\n  createFromBookmark: function createFromBookmark(editable, bookmark) {\n    var sc = dom.fromOffsetPath(editable, bookmark.s.path);\n    var so = bookmark.s.offset;\n    var ec = dom.fromOffsetPath(editable, bookmark.e.path);\n    var eo = bookmark.e.offset;\n    return new range_WrappedRange(sc, so, ec, eo);\n  },\n\n  /**\n   * @method\n   *\n   * create WrappedRange from paraBookmark\n   *\n   * @param {Object} bookmark\n   * @param {Node[]} paras\n   * @return {WrappedRange}\n   */\n  createFromParaBookmark: function createFromParaBookmark(bookmark, paras) {\n    var so = bookmark.s.offset;\n    var eo = bookmark.e.offset;\n    var sc = dom.fromOffsetPath(lists.head(paras), bookmark.s.path);\n    var ec = dom.fromOffsetPath(lists.last(paras), bookmark.e.path);\n    return new range_WrappedRange(sc, so, ec, eo);\n  }\n});\n// CONCATENATED MODULE: ./src/js/base/core/key.js\n\n\nvar KEY_MAP = {\n  'BACKSPACE': 8,\n  'TAB': 9,\n  'ENTER': 13,\n  'ESCAPE': 27,\n  'SPACE': 32,\n  'DELETE': 46,\n  // Arrow\n  'LEFT': 37,\n  'UP': 38,\n  'RIGHT': 39,\n  'DOWN': 40,\n  // Number: 0-9\n  'NUM0': 48,\n  'NUM1': 49,\n  'NUM2': 50,\n  'NUM3': 51,\n  'NUM4': 52,\n  'NUM5': 53,\n  'NUM6': 54,\n  'NUM7': 55,\n  'NUM8': 56,\n  // Alphabet: a-z\n  'B': 66,\n  'E': 69,\n  'I': 73,\n  'J': 74,\n  'K': 75,\n  'L': 76,\n  'R': 82,\n  'S': 83,\n  'U': 85,\n  'V': 86,\n  'Y': 89,\n  'Z': 90,\n  'SLASH': 191,\n  'LEFTBRACKET': 219,\n  'BACKSLASH': 220,\n  'RIGHTBRACKET': 221,\n  // Navigation\n  'HOME': 36,\n  'END': 35,\n  'PAGEUP': 33,\n  'PAGEDOWN': 34\n};\n/**\n * @class core.key\n *\n * Object for keycodes.\n *\n * @singleton\n * @alternateClassName key\n */\n\n/* harmony default export */ var core_key = ({\n  /**\n   * @method isEdit\n   *\n   * @param {Number} keyCode\n   * @return {Boolean}\n   */\n  isEdit: function isEdit(keyCode) {\n    return lists.contains([KEY_MAP.BACKSPACE, KEY_MAP.TAB, KEY_MAP.ENTER, KEY_MAP.SPACE, KEY_MAP.DELETE], keyCode);\n  },\n\n  /**\n   * @method isMove\n   *\n   * @param {Number} keyCode\n   * @return {Boolean}\n   */\n  isMove: function isMove(keyCode) {\n    return lists.contains([KEY_MAP.LEFT, KEY_MAP.UP, KEY_MAP.RIGHT, KEY_MAP.DOWN], keyCode);\n  },\n\n  /**\n   * @method isNavigation\n   *\n   * @param {Number} keyCode\n   * @return {Boolean}\n   */\n  isNavigation: function isNavigation(keyCode) {\n    return lists.contains([KEY_MAP.HOME, KEY_MAP.END, KEY_MAP.PAGEUP, KEY_MAP.PAGEDOWN], keyCode);\n  },\n\n  /**\n   * @property {Object} nameFromCode\n   * @property {String} nameFromCode.8 \"BACKSPACE\"\n   */\n  nameFromCode: func.invertObject(KEY_MAP),\n  code: KEY_MAP\n});\n// CONCATENATED MODULE: ./src/js/base/core/async.js\n\n/**\n * @method readFileAsDataURL\n *\n * read contents of file as representing URL\n *\n * @param {File} file\n * @return {Promise} - then: dataUrl\n */\n\nfunction readFileAsDataURL(file) {\n  return external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.Deferred(function (deferred) {\n    external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(new FileReader(), {\n      onload: function onload(e) {\n        var dataURL = e.target.result;\n        deferred.resolve(dataURL);\n      },\n      onerror: function onerror(err) {\n        deferred.reject(err);\n      }\n    }).readAsDataURL(file);\n  }).promise();\n}\n/**\n * @method createImage\n *\n * create `<image>` from url string\n *\n * @param {String} url\n * @return {Promise} - then: $image\n */\n\nfunction createImage(url) {\n  return external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.Deferred(function (deferred) {\n    var $img = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<img>');\n    $img.one('load', function () {\n      $img.off('error abort');\n      deferred.resolve($img);\n    }).one('error abort', function () {\n      $img.off('load').detach();\n      deferred.reject($img);\n    }).css({\n      display: 'none'\n    }).appendTo(document.body).attr('src', url);\n  }).promise();\n}\n// CONCATENATED MODULE: ./src/js/base/editing/History.js\nfunction History_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction History_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction History_createClass(Constructor, protoProps, staticProps) { if (protoProps) History_defineProperties(Constructor.prototype, protoProps); if (staticProps) History_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar History_History = /*#__PURE__*/function () {\n  function History(context) {\n    History_classCallCheck(this, History);\n\n    this.stack = [];\n    this.stackOffset = -1;\n    this.context = context;\n    this.$editable = context.layoutInfo.editable;\n    this.editable = this.$editable[0];\n  }\n\n  History_createClass(History, [{\n    key: \"makeSnapshot\",\n    value: function makeSnapshot() {\n      var rng = range.create(this.editable);\n      var emptyBookmark = {\n        s: {\n          path: [],\n          offset: 0\n        },\n        e: {\n          path: [],\n          offset: 0\n        }\n      };\n      return {\n        contents: this.$editable.html(),\n        bookmark: rng && rng.isOnEditable() ? rng.bookmark(this.editable) : emptyBookmark\n      };\n    }\n  }, {\n    key: \"applySnapshot\",\n    value: function applySnapshot(snapshot) {\n      if (snapshot.contents !== null) {\n        this.$editable.html(snapshot.contents);\n      }\n\n      if (snapshot.bookmark !== null) {\n        range.createFromBookmark(this.editable, snapshot.bookmark).select();\n      }\n    }\n    /**\n    * @method rewind\n    * Rewinds the history stack back to the first snapshot taken.\n    * Leaves the stack intact, so that \"Redo\" can still be used.\n    */\n\n  }, {\n    key: \"rewind\",\n    value: function rewind() {\n      // Create snap shot if not yet recorded\n      if (this.$editable.html() !== this.stack[this.stackOffset].contents) {\n        this.recordUndo();\n      } // Return to the first available snapshot.\n\n\n      this.stackOffset = 0; // Apply that snapshot.\n\n      this.applySnapshot(this.stack[this.stackOffset]);\n    }\n    /**\n    *  @method commit\n    *  Resets history stack, but keeps current editor's content.\n    */\n\n  }, {\n    key: \"commit\",\n    value: function commit() {\n      // Clear the stack.\n      this.stack = []; // Restore stackOffset to its original value.\n\n      this.stackOffset = -1; // Record our first snapshot (of nothing).\n\n      this.recordUndo();\n    }\n    /**\n    * @method reset\n    * Resets the history stack completely; reverting to an empty editor.\n    */\n\n  }, {\n    key: \"reset\",\n    value: function reset() {\n      // Clear the stack.\n      this.stack = []; // Restore stackOffset to its original value.\n\n      this.stackOffset = -1; // Clear the editable area.\n\n      this.$editable.html(''); // Record our first snapshot (of nothing).\n\n      this.recordUndo();\n    }\n    /**\n     * undo\n     */\n\n  }, {\n    key: \"undo\",\n    value: function undo() {\n      // Create snap shot if not yet recorded\n      if (this.$editable.html() !== this.stack[this.stackOffset].contents) {\n        this.recordUndo();\n      }\n\n      if (this.stackOffset > 0) {\n        this.stackOffset--;\n        this.applySnapshot(this.stack[this.stackOffset]);\n      }\n    }\n    /**\n     * redo\n     */\n\n  }, {\n    key: \"redo\",\n    value: function redo() {\n      if (this.stack.length - 1 > this.stackOffset) {\n        this.stackOffset++;\n        this.applySnapshot(this.stack[this.stackOffset]);\n      }\n    }\n    /**\n     * recorded undo\n     */\n\n  }, {\n    key: \"recordUndo\",\n    value: function recordUndo() {\n      this.stackOffset++; // Wash out stack after stackOffset\n\n      if (this.stack.length > this.stackOffset) {\n        this.stack = this.stack.slice(0, this.stackOffset);\n      } // Create new snapshot and push it to the end\n\n\n      this.stack.push(this.makeSnapshot()); // If the stack size reachs to the limit, then slice it\n\n      if (this.stack.length > this.context.options.historyLimit) {\n        this.stack.shift();\n        this.stackOffset -= 1;\n      }\n    }\n  }]);\n\n  return History;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/editing/Style.js\nfunction Style_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Style_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Style_createClass(Constructor, protoProps, staticProps) { if (protoProps) Style_defineProperties(Constructor.prototype, protoProps); if (staticProps) Style_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\n\nvar Style_Style = /*#__PURE__*/function () {\n  function Style() {\n    Style_classCallCheck(this, Style);\n  }\n\n  Style_createClass(Style, [{\n    key: \"jQueryCSS\",\n\n    /**\n     * @method jQueryCSS\n     *\n     * [workaround] for old jQuery\n     * passing an array of style properties to .css()\n     * will result in an object of property-value pairs.\n     * (compability with version < 1.9)\n     *\n     * @private\n     * @param  {jQuery} $obj\n     * @param  {Array} propertyNames - An array of one or more CSS properties.\n     * @return {Object}\n     */\n    value: function jQueryCSS($obj, propertyNames) {\n      if (env.jqueryVersion < 1.9) {\n        var result = {};\n        external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(propertyNames, function (idx, propertyName) {\n          result[propertyName] = $obj.css(propertyName);\n        });\n        return result;\n      }\n\n      return $obj.css(propertyNames);\n    }\n    /**\n     * returns style object from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n\n  }, {\n    key: \"fromNode\",\n    value: function fromNode($node) {\n      var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];\n      var styleInfo = this.jQueryCSS($node, properties) || {};\n      var fontSize = $node[0].style.fontSize || styleInfo['font-size'];\n      styleInfo['font-size'] = parseInt(fontSize, 10);\n      styleInfo['font-size-unit'] = fontSize.match(/[a-z%]+$/);\n      return styleInfo;\n    }\n    /**\n     * paragraph level style\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} styleInfo\n     */\n\n  }, {\n    key: \"stylePara\",\n    value: function stylePara(rng, styleInfo) {\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(rng.nodes(dom.isPara, {\n        includeAncestor: true\n      }), function (idx, para) {\n        external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(para).css(styleInfo);\n      });\n    }\n    /**\n     * insert and returns styleNodes on range.\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} [options] - options for styleNodes\n     * @param {String} [options.nodeName] - default: `SPAN`\n     * @param {Boolean} [options.expandClosestSibling] - default: `false`\n     * @param {Boolean} [options.onlyPartialContains] - default: `false`\n     * @return {Node[]}\n     */\n\n  }, {\n    key: \"styleNodes\",\n    value: function styleNodes(rng, options) {\n      rng = rng.splitText();\n      var nodeName = options && options.nodeName || 'SPAN';\n      var expandClosestSibling = !!(options && options.expandClosestSibling);\n      var onlyPartialContains = !!(options && options.onlyPartialContains);\n\n      if (rng.isCollapsed()) {\n        return [rng.insertNode(dom.create(nodeName))];\n      }\n\n      var pred = dom.makePredByNodeName(nodeName);\n      var nodes = rng.nodes(dom.isText, {\n        fullyContains: true\n      }).map(function (text) {\n        return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);\n      });\n\n      if (expandClosestSibling) {\n        if (onlyPartialContains) {\n          var nodesInRange = rng.nodes(); // compose with partial contains predication\n\n          pred = func.and(pred, function (node) {\n            return lists.contains(nodesInRange, node);\n          });\n        }\n\n        return nodes.map(function (node) {\n          var siblings = dom.withClosestSiblings(node, pred);\n          var head = lists.head(siblings);\n          var tails = lists.tail(siblings);\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(tails, function (idx, elem) {\n            dom.appendChildNodes(head, elem.childNodes);\n            dom.remove(elem);\n          });\n          return lists.head(siblings);\n        });\n      } else {\n        return nodes;\n      }\n    }\n    /**\n     * get current style on cursor\n     *\n     * @param {WrappedRange} rng\n     * @return {Object} - object contains style properties.\n     */\n\n  }, {\n    key: \"current\",\n    value: function current(rng) {\n      var $cont = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(!dom.isElement(rng.sc) ? rng.sc.parentNode : rng.sc);\n      var styleInfo = this.fromNode($cont); // document.queryCommandState for toggle state\n      // [workaround] prevent Firefox nsresult: \"0x80004005 (NS_ERROR_FAILURE)\"\n\n      try {\n        styleInfo = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(styleInfo, {\n          'font-bold': document.queryCommandState('bold') ? 'bold' : 'normal',\n          'font-italic': document.queryCommandState('italic') ? 'italic' : 'normal',\n          'font-underline': document.queryCommandState('underline') ? 'underline' : 'normal',\n          'font-subscript': document.queryCommandState('subscript') ? 'subscript' : 'normal',\n          'font-superscript': document.queryCommandState('superscript') ? 'superscript' : 'normal',\n          'font-strikethrough': document.queryCommandState('strikethrough') ? 'strikethrough' : 'normal',\n          'font-family': document.queryCommandValue('fontname') || styleInfo['font-family']\n        });\n      } catch (e) {} // eslint-disable-next-line\n      // list-style-type to list-style(unordered, ordered)\n\n\n      if (!rng.isOnList()) {\n        styleInfo['list-style'] = 'none';\n      } else {\n        var orderedTypes = ['circle', 'disc', 'disc-leading-zero', 'square'];\n        var isUnordered = orderedTypes.indexOf(styleInfo['list-style-type']) > -1;\n        styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';\n      }\n\n      var para = dom.ancestor(rng.sc, dom.isPara);\n\n      if (para && para.style['line-height']) {\n        styleInfo['line-height'] = para.style.lineHeight;\n      } else {\n        var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);\n        styleInfo['line-height'] = lineHeight.toFixed(1);\n      }\n\n      styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);\n      styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);\n      styleInfo.range = rng;\n      return styleInfo;\n    }\n  }]);\n\n  return Style;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/editing/Bullet.js\nfunction Bullet_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Bullet_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Bullet_createClass(Constructor, protoProps, staticProps) { if (protoProps) Bullet_defineProperties(Constructor.prototype, protoProps); if (staticProps) Bullet_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\n\nvar Bullet_Bullet = /*#__PURE__*/function () {\n  function Bullet() {\n    Bullet_classCallCheck(this, Bullet);\n  }\n\n  Bullet_createClass(Bullet, [{\n    key: \"insertOrderedList\",\n\n    /**\n     * toggle ordered list\n     */\n    value: function insertOrderedList(editable) {\n      this.toggleList('OL', editable);\n    }\n    /**\n     * toggle unordered list\n     */\n\n  }, {\n    key: \"insertUnorderedList\",\n    value: function insertUnorderedList(editable) {\n      this.toggleList('UL', editable);\n    }\n    /**\n     * indent\n     */\n\n  }, {\n    key: \"indent\",\n    value: function indent(editable) {\n      var _this = this;\n\n      var rng = range.create(editable).wrapBodyInlineWithPara();\n      var paras = rng.nodes(dom.isPara, {\n        includeAncestor: true\n      });\n      var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(clustereds, function (idx, paras) {\n        var head = lists.head(paras);\n\n        if (dom.isLi(head)) {\n          var previousList = _this.findList(head.previousSibling);\n\n          if (previousList) {\n            paras.map(function (para) {\n              return previousList.appendChild(para);\n            });\n          } else {\n            _this.wrapList(paras, head.parentNode.nodeName);\n\n            paras.map(function (para) {\n              return para.parentNode;\n            }).map(function (para) {\n              return _this.appendToPrevious(para);\n            });\n          }\n        } else {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(paras, function (idx, para) {\n            external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(para).css('marginLeft', function (idx, val) {\n              return (parseInt(val, 10) || 0) + 25;\n            });\n          });\n        }\n      });\n      rng.select();\n    }\n    /**\n     * outdent\n     */\n\n  }, {\n    key: \"outdent\",\n    value: function outdent(editable) {\n      var _this2 = this;\n\n      var rng = range.create(editable).wrapBodyInlineWithPara();\n      var paras = rng.nodes(dom.isPara, {\n        includeAncestor: true\n      });\n      var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(clustereds, function (idx, paras) {\n        var head = lists.head(paras);\n\n        if (dom.isLi(head)) {\n          _this2.releaseList([paras]);\n        } else {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(paras, function (idx, para) {\n            external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(para).css('marginLeft', function (idx, val) {\n              val = parseInt(val, 10) || 0;\n              return val > 25 ? val - 25 : '';\n            });\n          });\n        }\n      });\n      rng.select();\n    }\n    /**\n     * toggle list\n     *\n     * @param {String} listName - OL or UL\n     */\n\n  }, {\n    key: \"toggleList\",\n    value: function toggleList(listName, editable) {\n      var _this3 = this;\n\n      var rng = range.create(editable).wrapBodyInlineWithPara();\n      var paras = rng.nodes(dom.isPara, {\n        includeAncestor: true\n      });\n      var bookmark = rng.paraBookmark(paras);\n      var clustereds = lists.clusterBy(paras, func.peq2('parentNode')); // paragraph to list\n\n      if (lists.find(paras, dom.isPurePara)) {\n        var wrappedParas = [];\n        external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(clustereds, function (idx, paras) {\n          wrappedParas = wrappedParas.concat(_this3.wrapList(paras, listName));\n        });\n        paras = wrappedParas; // list to paragraph or change list style\n      } else {\n        var diffLists = rng.nodes(dom.isList, {\n          includeAncestor: true\n        }).filter(function (listNode) {\n          return !external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.nodeName(listNode, listName);\n        });\n\n        if (diffLists.length) {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(diffLists, function (idx, listNode) {\n            dom.replace(listNode, listName);\n          });\n        } else {\n          paras = this.releaseList(clustereds, true);\n        }\n      }\n\n      range.createFromParaBookmark(bookmark, paras).select();\n    }\n    /**\n     * @param {Node[]} paras\n     * @param {String} listName\n     * @return {Node[]}\n     */\n\n  }, {\n    key: \"wrapList\",\n    value: function wrapList(paras, listName) {\n      var head = lists.head(paras);\n      var last = lists.last(paras);\n      var prevList = dom.isList(head.previousSibling) && head.previousSibling;\n      var nextList = dom.isList(last.nextSibling) && last.nextSibling;\n      var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last); // P to LI\n\n      paras = paras.map(function (para) {\n        return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;\n      }); // append to list(<ul>, <ol>)\n\n      dom.appendChildNodes(listNode, paras);\n\n      if (nextList) {\n        dom.appendChildNodes(listNode, lists.from(nextList.childNodes));\n        dom.remove(nextList);\n      }\n\n      return paras;\n    }\n    /**\n     * @method releaseList\n     *\n     * @param {Array[]} clustereds\n     * @param {Boolean} isEscapseToBody\n     * @return {Node[]}\n     */\n\n  }, {\n    key: \"releaseList\",\n    value: function releaseList(clustereds, isEscapseToBody) {\n      var _this4 = this;\n\n      var releasedParas = [];\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(clustereds, function (idx, paras) {\n        var head = lists.head(paras);\n        var last = lists.last(paras);\n        var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) : head.parentNode;\n        var parentItem = headList.parentNode;\n\n        if (headList.parentNode.nodeName === 'LI') {\n          paras.map(function (para) {\n            var newList = _this4.findNextSiblings(para);\n\n            if (parentItem.nextSibling) {\n              parentItem.parentNode.insertBefore(para, parentItem.nextSibling);\n            } else {\n              parentItem.parentNode.appendChild(para);\n            }\n\n            if (newList.length) {\n              _this4.wrapList(newList, headList.nodeName);\n\n              para.appendChild(newList[0].parentNode);\n            }\n          });\n\n          if (headList.children.length === 0) {\n            parentItem.removeChild(headList);\n          }\n\n          if (parentItem.childNodes.length === 0) {\n            parentItem.parentNode.removeChild(parentItem);\n          }\n        } else {\n          var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {\n            node: last.parentNode,\n            offset: dom.position(last) + 1\n          }, {\n            isSkipPaddingBlankHTML: true\n          }) : null;\n          var middleList = dom.splitTree(headList, {\n            node: head.parentNode,\n            offset: dom.position(head)\n          }, {\n            isSkipPaddingBlankHTML: true\n          });\n          paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) : lists.from(middleList.childNodes).filter(dom.isLi); // LI to P\n\n          if (isEscapseToBody || !dom.isList(headList.parentNode)) {\n            paras = paras.map(function (para) {\n              return dom.replace(para, 'P');\n            });\n          }\n\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(lists.from(paras).reverse(), function (idx, para) {\n            dom.insertAfter(para, headList);\n          }); // remove empty lists\n\n          var rootLists = lists.compact([headList, middleList, lastList]);\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(rootLists, function (idx, rootList) {\n            var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));\n            external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(listNodes.reverse(), function (idx, listNode) {\n              if (!dom.nodeLength(listNode)) {\n                dom.remove(listNode, true);\n              }\n            });\n          });\n        }\n\n        releasedParas = releasedParas.concat(paras);\n      });\n      return releasedParas;\n    }\n    /**\n     * @method appendToPrevious\n     *\n     * Appends list to previous list item, if\n     * none exist it wraps the list in a new list item.\n     *\n     * @param {HTMLNode} ListItem\n     * @return {HTMLNode}\n     */\n\n  }, {\n    key: \"appendToPrevious\",\n    value: function appendToPrevious(node) {\n      return node.previousSibling ? dom.appendChildNodes(node.previousSibling, [node]) : this.wrapList([node], 'LI');\n    }\n    /**\n     * @method findList\n     *\n     * Finds an existing list in list item\n     *\n     * @param {HTMLNode} ListItem\n     * @return {Array[]}\n     */\n\n  }, {\n    key: \"findList\",\n    value: function findList(node) {\n      return node ? lists.find(node.children, function (child) {\n        return ['OL', 'UL'].indexOf(child.nodeName) > -1;\n      }) : null;\n    }\n    /**\n     * @method findNextSiblings\n     *\n     * Finds all list item siblings that follow it\n     *\n     * @param {HTMLNode} ListItem\n     * @return {HTMLNode}\n     */\n\n  }, {\n    key: \"findNextSiblings\",\n    value: function findNextSiblings(node) {\n      var siblings = [];\n\n      while (node.nextSibling) {\n        siblings.push(node.nextSibling);\n        node = node.nextSibling;\n      }\n\n      return siblings;\n    }\n  }]);\n\n  return Bullet;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/editing/Typing.js\nfunction Typing_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Typing_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Typing_createClass(Constructor, protoProps, staticProps) { if (protoProps) Typing_defineProperties(Constructor.prototype, protoProps); if (staticProps) Typing_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n/**\n * @class editing.Typing\n *\n * Typing\n *\n */\n\nvar Typing_Typing = /*#__PURE__*/function () {\n  function Typing(context) {\n    Typing_classCallCheck(this, Typing);\n\n    // a Bullet instance to toggle lists off\n    this.bullet = new Bullet_Bullet();\n    this.options = context.options;\n  }\n  /**\n   * insert tab\n   *\n   * @param {WrappedRange} rng\n   * @param {Number} tabsize\n   */\n\n\n  Typing_createClass(Typing, [{\n    key: \"insertTab\",\n    value: function insertTab(rng, tabsize) {\n      var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));\n      rng = rng.deleteContents();\n      rng.insertNode(tab, true);\n      rng = range.create(tab, tabsize);\n      rng.select();\n    }\n    /**\n     * insert paragraph\n     *\n     * @param {jQuery} $editable\n     * @param {WrappedRange} rng Can be used in unit tests to \"mock\" the range\n     *\n     * blockquoteBreakingLevel\n     *   0 - No break, the new paragraph remains inside the quote\n     *   1 - Break the first blockquote in the ancestors list\n     *   2 - Break all blockquotes, so that the new paragraph is not quoted (this is the default)\n     */\n\n  }, {\n    key: \"insertParagraph\",\n    value: function insertParagraph(editable, rng) {\n      rng = rng || range.create(editable); // deleteContents on range.\n\n      rng = rng.deleteContents(); // Wrap range if it needs to be wrapped by paragraph\n\n      rng = rng.wrapBodyInlineWithPara(); // finding paragraph\n\n      var splitRoot = dom.ancestor(rng.sc, dom.isPara);\n      var nextPara; // on paragraph: split paragraph\n\n      if (splitRoot) {\n        // if it is an empty line with li\n        if (dom.isLi(splitRoot) && (dom.isEmpty(splitRoot) || dom.deepestChildIsEmpty(splitRoot))) {\n          // toggle UL/OL and escape\n          this.bullet.toggleList(splitRoot.parentNode.nodeName);\n          return;\n        } else {\n          var blockquote = null;\n\n          if (this.options.blockquoteBreakingLevel === 1) {\n            blockquote = dom.ancestor(splitRoot, dom.isBlockquote);\n          } else if (this.options.blockquoteBreakingLevel === 2) {\n            blockquote = dom.lastAncestor(splitRoot, dom.isBlockquote);\n          }\n\n          if (blockquote) {\n            // We're inside a blockquote and options ask us to break it\n            nextPara = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(dom.emptyPara)[0]; // If the split is right before a <br>, remove it so that there's no \"empty line\"\n            // after the split in the new blockquote created\n\n            if (dom.isRightEdgePoint(rng.getStartPoint()) && dom.isBR(rng.sc.nextSibling)) {\n              external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(rng.sc.nextSibling).remove();\n            }\n\n            var split = dom.splitTree(blockquote, rng.getStartPoint(), {\n              isDiscardEmptySplits: true\n            });\n\n            if (split) {\n              split.parentNode.insertBefore(nextPara, split);\n            } else {\n              dom.insertAfter(nextPara, blockquote); // There's no split if we were at the end of the blockquote\n            }\n          } else {\n            nextPara = dom.splitTree(splitRoot, rng.getStartPoint()); // not a blockquote, just insert the paragraph\n\n            var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);\n            emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));\n            external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(emptyAnchors, function (idx, anchor) {\n              dom.remove(anchor);\n            }); // replace empty heading, pre or custom-made styleTag with P tag\n\n            if ((dom.isHeading(nextPara) || dom.isPre(nextPara) || dom.isCustomStyleTag(nextPara)) && dom.isEmpty(nextPara)) {\n              nextPara = dom.replace(nextPara, 'p');\n            }\n          }\n        } // no paragraph: insert empty paragraph\n\n      } else {\n        var next = rng.sc.childNodes[rng.so];\n        nextPara = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(dom.emptyPara)[0];\n\n        if (next) {\n          rng.sc.insertBefore(nextPara, next);\n        } else {\n          rng.sc.appendChild(nextPara);\n        }\n      }\n\n      range.create(nextPara, 0).normalize().select().scrollIntoView(editable);\n    }\n  }]);\n\n  return Typing;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/editing/Table.js\nfunction Table_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Table_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Table_createClass(Constructor, protoProps, staticProps) { if (protoProps) Table_defineProperties(Constructor.prototype, protoProps); if (staticProps) Table_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n/**\n * @class Create a virtual table to create what actions to do in change.\n * @param {object} startPoint Cell selected to apply change.\n * @param {enum} where  Where change will be applied Row or Col. Use enum: TableResultAction.where\n * @param {enum} action Action to be applied. Use enum: TableResultAction.requestAction\n * @param {object} domTable Dom element of table to make changes.\n */\n\nvar TableResultAction = function TableResultAction(startPoint, where, action, domTable) {\n  var _startPoint = {\n    'colPos': 0,\n    'rowPos': 0\n  };\n  var _virtualTable = [];\n  var _actionCellList = []; /// ///////////////////////////////////////////\n  // Private functions\n  /// ///////////////////////////////////////////\n\n  /**\n   * Set the startPoint of action.\n   */\n\n  function setStartPoint() {\n    if (!startPoint || !startPoint.tagName || startPoint.tagName.toLowerCase() !== 'td' && startPoint.tagName.toLowerCase() !== 'th') {\n      // Impossible to identify start Cell point\n      return;\n    }\n\n    _startPoint.colPos = startPoint.cellIndex;\n\n    if (!startPoint.parentElement || !startPoint.parentElement.tagName || startPoint.parentElement.tagName.toLowerCase() !== 'tr') {\n      // Impossible to identify start Row point\n      return;\n    }\n\n    _startPoint.rowPos = startPoint.parentElement.rowIndex;\n  }\n  /**\n   * Define virtual table position info object.\n   *\n   * @param {int} rowIndex Index position in line of virtual table.\n   * @param {int} cellIndex Index position in column of virtual table.\n   * @param {object} baseRow Row affected by this position.\n   * @param {object} baseCell Cell affected by this position.\n   * @param {bool} isSpan Inform if it is an span cell/row.\n   */\n\n\n  function setVirtualTablePosition(rowIndex, cellIndex, baseRow, baseCell, isRowSpan, isColSpan, isVirtualCell) {\n    var objPosition = {\n      'baseRow': baseRow,\n      'baseCell': baseCell,\n      'isRowSpan': isRowSpan,\n      'isColSpan': isColSpan,\n      'isVirtual': isVirtualCell\n    };\n\n    if (!_virtualTable[rowIndex]) {\n      _virtualTable[rowIndex] = [];\n    }\n\n    _virtualTable[rowIndex][cellIndex] = objPosition;\n  }\n  /**\n   * Create action cell object.\n   *\n   * @param {object} virtualTableCellObj Object of specific position on virtual table.\n   * @param {enum} resultAction Action to be applied in that item.\n   */\n\n\n  function getActionCell(virtualTableCellObj, resultAction, virtualRowPosition, virtualColPosition) {\n    return {\n      'baseCell': virtualTableCellObj.baseCell,\n      'action': resultAction,\n      'virtualTable': {\n        'rowIndex': virtualRowPosition,\n        'cellIndex': virtualColPosition\n      }\n    };\n  }\n  /**\n   * Recover free index of row to append Cell.\n   *\n   * @param {int} rowIndex Index of row to find free space.\n   * @param {int} cellIndex Index of cell to find free space in table.\n   */\n\n\n  function recoverCellIndex(rowIndex, cellIndex) {\n    if (!_virtualTable[rowIndex]) {\n      return cellIndex;\n    }\n\n    if (!_virtualTable[rowIndex][cellIndex]) {\n      return cellIndex;\n    }\n\n    var newCellIndex = cellIndex;\n\n    while (_virtualTable[rowIndex][newCellIndex]) {\n      newCellIndex++;\n\n      if (!_virtualTable[rowIndex][newCellIndex]) {\n        return newCellIndex;\n      }\n    }\n  }\n  /**\n   * Recover info about row and cell and add information to virtual table.\n   *\n   * @param {object} row Row to recover information.\n   * @param {object} cell Cell to recover information.\n   */\n\n\n  function addCellInfoToVirtual(row, cell) {\n    var cellIndex = recoverCellIndex(row.rowIndex, cell.cellIndex);\n    var cellHasColspan = cell.colSpan > 1;\n    var cellHasRowspan = cell.rowSpan > 1;\n    var isThisSelectedCell = row.rowIndex === _startPoint.rowPos && cell.cellIndex === _startPoint.colPos;\n    setVirtualTablePosition(row.rowIndex, cellIndex, row, cell, cellHasRowspan, cellHasColspan, false); // Add span rows to virtual Table.\n\n    var rowspanNumber = cell.attributes.rowSpan ? parseInt(cell.attributes.rowSpan.value, 10) : 0;\n\n    if (rowspanNumber > 1) {\n      for (var rp = 1; rp < rowspanNumber; rp++) {\n        var rowspanIndex = row.rowIndex + rp;\n        adjustStartPoint(rowspanIndex, cellIndex, cell, isThisSelectedCell);\n        setVirtualTablePosition(rowspanIndex, cellIndex, row, cell, true, cellHasColspan, true);\n      }\n    } // Add span cols to virtual table.\n\n\n    var colspanNumber = cell.attributes.colSpan ? parseInt(cell.attributes.colSpan.value, 10) : 0;\n\n    if (colspanNumber > 1) {\n      for (var cp = 1; cp < colspanNumber; cp++) {\n        var cellspanIndex = recoverCellIndex(row.rowIndex, cellIndex + cp);\n        adjustStartPoint(row.rowIndex, cellspanIndex, cell, isThisSelectedCell);\n        setVirtualTablePosition(row.rowIndex, cellspanIndex, row, cell, cellHasRowspan, true, true);\n      }\n    }\n  }\n  /**\n   * Process validation and adjust of start point if needed\n   *\n   * @param {int} rowIndex\n   * @param {int} cellIndex\n   * @param {object} cell\n   * @param {bool} isSelectedCell\n   */\n\n\n  function adjustStartPoint(rowIndex, cellIndex, cell, isSelectedCell) {\n    if (rowIndex === _startPoint.rowPos && _startPoint.colPos >= cell.cellIndex && cell.cellIndex <= cellIndex && !isSelectedCell) {\n      _startPoint.colPos++;\n    }\n  }\n  /**\n   * Create virtual table of cells with all cells, including span cells.\n   */\n\n\n  function createVirtualTable() {\n    var rows = domTable.rows;\n\n    for (var rowIndex = 0; rowIndex < rows.length; rowIndex++) {\n      var cells = rows[rowIndex].cells;\n\n      for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) {\n        addCellInfoToVirtual(rows[rowIndex], cells[cellIndex]);\n      }\n    }\n  }\n  /**\n   * Get action to be applied on the cell.\n   *\n   * @param {object} cell virtual table cell to apply action\n   */\n\n\n  function getDeleteResultActionToCell(cell) {\n    switch (where) {\n      case TableResultAction.where.Column:\n        if (cell.isColSpan) {\n          return TableResultAction.resultAction.SubtractSpanCount;\n        }\n\n        break;\n\n      case TableResultAction.where.Row:\n        if (!cell.isVirtual && cell.isRowSpan) {\n          return TableResultAction.resultAction.AddCell;\n        } else if (cell.isRowSpan) {\n          return TableResultAction.resultAction.SubtractSpanCount;\n        }\n\n        break;\n    }\n\n    return TableResultAction.resultAction.RemoveCell;\n  }\n  /**\n   * Get action to be applied on the cell.\n   *\n   * @param {object} cell virtual table cell to apply action\n   */\n\n\n  function getAddResultActionToCell(cell) {\n    switch (where) {\n      case TableResultAction.where.Column:\n        if (cell.isColSpan) {\n          return TableResultAction.resultAction.SumSpanCount;\n        } else if (cell.isRowSpan && cell.isVirtual) {\n          return TableResultAction.resultAction.Ignore;\n        }\n\n        break;\n\n      case TableResultAction.where.Row:\n        if (cell.isRowSpan) {\n          return TableResultAction.resultAction.SumSpanCount;\n        } else if (cell.isColSpan && cell.isVirtual) {\n          return TableResultAction.resultAction.Ignore;\n        }\n\n        break;\n    }\n\n    return TableResultAction.resultAction.AddCell;\n  }\n\n  function init() {\n    setStartPoint();\n    createVirtualTable();\n  } /// ///////////////////////////////////////////\n  // Public functions\n  /// ///////////////////////////////////////////\n\n  /**\n   * Recover array os what to do in table.\n   */\n\n\n  this.getActionList = function () {\n    var fixedRow = where === TableResultAction.where.Row ? _startPoint.rowPos : -1;\n    var fixedCol = where === TableResultAction.where.Column ? _startPoint.colPos : -1;\n    var actualPosition = 0;\n    var canContinue = true;\n\n    while (canContinue) {\n      var rowPosition = fixedRow >= 0 ? fixedRow : actualPosition;\n      var colPosition = fixedCol >= 0 ? fixedCol : actualPosition;\n      var row = _virtualTable[rowPosition];\n\n      if (!row) {\n        canContinue = false;\n        return _actionCellList;\n      }\n\n      var cell = row[colPosition];\n\n      if (!cell) {\n        canContinue = false;\n        return _actionCellList;\n      } // Define action to be applied in this cell\n\n\n      var resultAction = TableResultAction.resultAction.Ignore;\n\n      switch (action) {\n        case TableResultAction.requestAction.Add:\n          resultAction = getAddResultActionToCell(cell);\n          break;\n\n        case TableResultAction.requestAction.Delete:\n          resultAction = getDeleteResultActionToCell(cell);\n          break;\n      }\n\n      _actionCellList.push(getActionCell(cell, resultAction, rowPosition, colPosition));\n\n      actualPosition++;\n    }\n\n    return _actionCellList;\n  };\n\n  init();\n};\n/**\n*\n* Where action occours enum.\n*/\n\n\nTableResultAction.where = {\n  'Row': 0,\n  'Column': 1\n};\n/**\n*\n* Requested action to apply enum.\n*/\n\nTableResultAction.requestAction = {\n  'Add': 0,\n  'Delete': 1\n};\n/**\n*\n* Result action to be executed enum.\n*/\n\nTableResultAction.resultAction = {\n  'Ignore': 0,\n  'SubtractSpanCount': 1,\n  'RemoveCell': 2,\n  'AddCell': 3,\n  'SumSpanCount': 4\n};\n/**\n *\n * @class editing.Table\n *\n * Table\n *\n */\n\nvar Table_Table = /*#__PURE__*/function () {\n  function Table() {\n    Table_classCallCheck(this, Table);\n  }\n\n  Table_createClass(Table, [{\n    key: \"tab\",\n\n    /**\n     * handle tab key\n     *\n     * @param {WrappedRange} rng\n     * @param {Boolean} isShift\n     */\n    value: function tab(rng, isShift) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var table = dom.ancestor(cell, dom.isTable);\n      var cells = dom.listDescendant(table, dom.isCell);\n      var nextCell = lists[isShift ? 'prev' : 'next'](cells, cell);\n\n      if (nextCell) {\n        range.create(nextCell, 0).select();\n      }\n    }\n    /**\n     * Add a new row\n     *\n     * @param {WrappedRange} rng\n     * @param {String} position (top/bottom)\n     * @return {Node}\n     */\n\n  }, {\n    key: \"addRow\",\n    value: function addRow(rng, position) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var currentTr = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(cell).closest('tr');\n      var trAttributes = this.recoverAttributes(currentTr);\n      var html = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<tr' + trAttributes + '></tr>');\n      var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Add, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(currentTr).closest('table')[0]);\n      var actions = vTable.getActionList();\n\n      for (var idCell = 0; idCell < actions.length; idCell++) {\n        var currentCell = actions[idCell];\n        var tdAttributes = this.recoverAttributes(currentCell.baseCell);\n\n        switch (currentCell.action) {\n          case TableResultAction.resultAction.AddCell:\n            html.append('<td' + tdAttributes + '>' + dom.blank + '</td>');\n            break;\n\n          case TableResultAction.resultAction.SumSpanCount:\n            {\n              if (position === 'top') {\n                var baseCellTr = currentCell.baseCell.parent;\n                var isTopFromRowSpan = (!baseCellTr ? 0 : currentCell.baseCell.closest('tr').rowIndex) <= currentTr[0].rowIndex;\n\n                if (isTopFromRowSpan) {\n                  var newTd = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div></div>').append(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<td' + tdAttributes + '>' + dom.blank + '</td>').removeAttr('rowspan')).html();\n                  html.append(newTd);\n                  break;\n                }\n              }\n\n              var rowspanNumber = parseInt(currentCell.baseCell.rowSpan, 10);\n              rowspanNumber++;\n              currentCell.baseCell.setAttribute('rowSpan', rowspanNumber);\n            }\n            break;\n        }\n      }\n\n      if (position === 'top') {\n        currentTr.before(html);\n      } else {\n        var cellHasRowspan = cell.rowSpan > 1;\n\n        if (cellHasRowspan) {\n          var lastTrIndex = currentTr[0].rowIndex + (cell.rowSpan - 2);\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(currentTr).parent().find('tr')[lastTrIndex]).after(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(html));\n          return;\n        }\n\n        currentTr.after(html);\n      }\n    }\n    /**\n     * Add a new col\n     *\n     * @param {WrappedRange} rng\n     * @param {String} position (left/right)\n     * @return {Node}\n     */\n\n  }, {\n    key: \"addCol\",\n    value: function addCol(rng, position) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var row = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(cell).closest('tr');\n      var rowsGroup = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(row).siblings();\n      rowsGroup.push(row);\n      var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Add, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(row).closest('table')[0]);\n      var actions = vTable.getActionList();\n\n      for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {\n        var currentCell = actions[actionIndex];\n        var tdAttributes = this.recoverAttributes(currentCell.baseCell);\n\n        switch (currentCell.action) {\n          case TableResultAction.resultAction.AddCell:\n            if (position === 'right') {\n              external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(currentCell.baseCell).after('<td' + tdAttributes + '>' + dom.blank + '</td>');\n            } else {\n              external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');\n            }\n\n            break;\n\n          case TableResultAction.resultAction.SumSpanCount:\n            if (position === 'right') {\n              var colspanNumber = parseInt(currentCell.baseCell.colSpan, 10);\n              colspanNumber++;\n              currentCell.baseCell.setAttribute('colSpan', colspanNumber);\n            } else {\n              external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');\n            }\n\n            break;\n        }\n      }\n    }\n    /*\n    * Copy attributes from element.\n    *\n    * @param {object} Element to recover attributes.\n    * @return {string} Copied string elements.\n    */\n\n  }, {\n    key: \"recoverAttributes\",\n    value: function recoverAttributes(el) {\n      var resultStr = '';\n\n      if (!el) {\n        return resultStr;\n      }\n\n      var attrList = el.attributes || [];\n\n      for (var i = 0; i < attrList.length; i++) {\n        if (attrList[i].name.toLowerCase() === 'id') {\n          continue;\n        }\n\n        if (attrList[i].specified) {\n          resultStr += ' ' + attrList[i].name + '=\\'' + attrList[i].value + '\\'';\n        }\n      }\n\n      return resultStr;\n    }\n    /**\n     * Delete current row\n     *\n     * @param {WrappedRange} rng\n     * @return {Node}\n     */\n\n  }, {\n    key: \"deleteRow\",\n    value: function deleteRow(rng) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var row = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(cell).closest('tr');\n      var cellPos = row.children('td, th').index(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(cell));\n      var rowPos = row[0].rowIndex;\n      var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Delete, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(row).closest('table')[0]);\n      var actions = vTable.getActionList();\n\n      for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {\n        if (!actions[actionIndex]) {\n          continue;\n        }\n\n        var baseCell = actions[actionIndex].baseCell;\n        var virtualPosition = actions[actionIndex].virtualTable;\n        var hasRowspan = baseCell.rowSpan && baseCell.rowSpan > 1;\n        var rowspanNumber = hasRowspan ? parseInt(baseCell.rowSpan, 10) : 0;\n\n        switch (actions[actionIndex].action) {\n          case TableResultAction.resultAction.Ignore:\n            continue;\n\n          case TableResultAction.resultAction.AddCell:\n            {\n              var nextRow = row.next('tr')[0];\n\n              if (!nextRow) {\n                continue;\n              }\n\n              var cloneRow = row[0].cells[cellPos];\n\n              if (hasRowspan) {\n                if (rowspanNumber > 2) {\n                  rowspanNumber--;\n                  nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);\n                  nextRow.cells[cellPos].setAttribute('rowSpan', rowspanNumber);\n                  nextRow.cells[cellPos].innerHTML = '';\n                } else if (rowspanNumber === 2) {\n                  nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);\n                  nextRow.cells[cellPos].removeAttribute('rowSpan');\n                  nextRow.cells[cellPos].innerHTML = '';\n                }\n              }\n            }\n            continue;\n\n          case TableResultAction.resultAction.SubtractSpanCount:\n            if (hasRowspan) {\n              if (rowspanNumber > 2) {\n                rowspanNumber--;\n                baseCell.setAttribute('rowSpan', rowspanNumber);\n\n                if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {\n                  baseCell.innerHTML = '';\n                }\n              } else if (rowspanNumber === 2) {\n                baseCell.removeAttribute('rowSpan');\n\n                if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {\n                  baseCell.innerHTML = '';\n                }\n              }\n            }\n\n            continue;\n\n          case TableResultAction.resultAction.RemoveCell:\n            // Do not need remove cell because row will be deleted.\n            continue;\n        }\n      }\n\n      row.remove();\n    }\n    /**\n     * Delete current col\n     *\n     * @param {WrappedRange} rng\n     * @return {Node}\n     */\n\n  }, {\n    key: \"deleteCol\",\n    value: function deleteCol(rng) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var row = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(cell).closest('tr');\n      var cellPos = row.children('td, th').index(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(cell));\n      var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Delete, external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(row).closest('table')[0]);\n      var actions = vTable.getActionList();\n\n      for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {\n        if (!actions[actionIndex]) {\n          continue;\n        }\n\n        switch (actions[actionIndex].action) {\n          case TableResultAction.resultAction.Ignore:\n            continue;\n\n          case TableResultAction.resultAction.SubtractSpanCount:\n            {\n              var baseCell = actions[actionIndex].baseCell;\n              var hasColspan = baseCell.colSpan && baseCell.colSpan > 1;\n\n              if (hasColspan) {\n                var colspanNumber = baseCell.colSpan ? parseInt(baseCell.colSpan, 10) : 0;\n\n                if (colspanNumber > 2) {\n                  colspanNumber--;\n                  baseCell.setAttribute('colSpan', colspanNumber);\n\n                  if (baseCell.cellIndex === cellPos) {\n                    baseCell.innerHTML = '';\n                  }\n                } else if (colspanNumber === 2) {\n                  baseCell.removeAttribute('colSpan');\n\n                  if (baseCell.cellIndex === cellPos) {\n                    baseCell.innerHTML = '';\n                  }\n                }\n              }\n            }\n            continue;\n\n          case TableResultAction.resultAction.RemoveCell:\n            dom.remove(actions[actionIndex].baseCell, true);\n            continue;\n        }\n      }\n    }\n    /**\n     * create empty table element\n     *\n     * @param {Number} rowCount\n     * @param {Number} colCount\n     * @return {Node}\n     */\n\n  }, {\n    key: \"createTable\",\n    value: function createTable(colCount, rowCount, options) {\n      var tds = [];\n      var tdHTML;\n\n      for (var idxCol = 0; idxCol < colCount; idxCol++) {\n        tds.push('<td>' + dom.blank + '</td>');\n      }\n\n      tdHTML = tds.join('');\n      var trs = [];\n      var trHTML;\n\n      for (var idxRow = 0; idxRow < rowCount; idxRow++) {\n        trs.push('<tr>' + tdHTML + '</tr>');\n      }\n\n      trHTML = trs.join('');\n      var $table = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<table>' + trHTML + '</table>');\n\n      if (options && options.tableClassName) {\n        $table.addClass(options.tableClassName);\n      }\n\n      return $table[0];\n    }\n    /**\n     * Delete current table\n     *\n     * @param {WrappedRange} rng\n     * @return {Node}\n     */\n\n  }, {\n    key: \"deleteTable\",\n    value: function deleteTable(rng) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(cell).closest('table').remove();\n    }\n  }]);\n\n  return Table;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Editor.js\nfunction Editor_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Editor_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Editor_createClass(Constructor, protoProps, staticProps) { if (protoProps) Editor_defineProperties(Constructor.prototype, protoProps); if (staticProps) Editor_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nvar KEY_BOGUS = 'bogus';\n/**\n * @class Editor\n */\n\nvar Editor_Editor = /*#__PURE__*/function () {\n  function Editor(context) {\n    var _this = this;\n\n    Editor_classCallCheck(this, Editor);\n\n    this.context = context;\n    this.$note = context.layoutInfo.note;\n    this.$editor = context.layoutInfo.editor;\n    this.$editable = context.layoutInfo.editable;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n    this.editable = this.$editable[0];\n    this.lastRange = null;\n    this.snapshot = null;\n    this.style = new Style_Style();\n    this.table = new Table_Table();\n    this.typing = new Typing_Typing(context);\n    this.bullet = new Bullet_Bullet();\n    this.history = new History_History(context);\n    this.context.memo('help.escape', this.lang.help.escape);\n    this.context.memo('help.undo', this.lang.help.undo);\n    this.context.memo('help.redo', this.lang.help.redo);\n    this.context.memo('help.tab', this.lang.help.tab);\n    this.context.memo('help.untab', this.lang.help.untab);\n    this.context.memo('help.insertParagraph', this.lang.help.insertParagraph);\n    this.context.memo('help.insertOrderedList', this.lang.help.insertOrderedList);\n    this.context.memo('help.insertUnorderedList', this.lang.help.insertUnorderedList);\n    this.context.memo('help.indent', this.lang.help.indent);\n    this.context.memo('help.outdent', this.lang.help.outdent);\n    this.context.memo('help.formatPara', this.lang.help.formatPara);\n    this.context.memo('help.insertHorizontalRule', this.lang.help.insertHorizontalRule);\n    this.context.memo('help.fontName', this.lang.help.fontName); // native commands(with execCommand), generate function for execCommand\n\n    var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', 'formatBlock', 'removeFormat', 'backColor'];\n\n    for (var idx = 0, len = commands.length; idx < len; idx++) {\n      this[commands[idx]] = function (sCmd) {\n        return function (value) {\n          _this.beforeCommand();\n\n          document.execCommand(sCmd, false, value);\n\n          _this.afterCommand(true);\n        };\n      }(commands[idx]);\n\n      this.context.memo('help.' + commands[idx], this.lang.help[commands[idx]]);\n    }\n\n    this.fontName = this.wrapCommand(function (value) {\n      return _this.fontStyling('font-family', env.validFontName(value));\n    });\n    this.fontSize = this.wrapCommand(function (value) {\n      var unit = _this.currentStyle()['font-size-unit'];\n\n      return _this.fontStyling('font-size', value + unit);\n    });\n    this.fontSizeUnit = this.wrapCommand(function (value) {\n      var size = _this.currentStyle()['font-size'];\n\n      return _this.fontStyling('font-size', size + value);\n    });\n\n    for (var _idx = 1; _idx <= 6; _idx++) {\n      this['formatH' + _idx] = function (idx) {\n        return function () {\n          _this.formatBlock('H' + idx);\n        };\n      }(_idx);\n\n      this.context.memo('help.formatH' + _idx, this.lang.help['formatH' + _idx]);\n    }\n\n    this.insertParagraph = this.wrapCommand(function () {\n      _this.typing.insertParagraph(_this.editable);\n    });\n    this.insertOrderedList = this.wrapCommand(function () {\n      _this.bullet.insertOrderedList(_this.editable);\n    });\n    this.insertUnorderedList = this.wrapCommand(function () {\n      _this.bullet.insertUnorderedList(_this.editable);\n    });\n    this.indent = this.wrapCommand(function () {\n      _this.bullet.indent(_this.editable);\n    });\n    this.outdent = this.wrapCommand(function () {\n      _this.bullet.outdent(_this.editable);\n    });\n    /**\n     * insertNode\n     * insert node\n     * @param {Node} node\n     */\n\n    this.insertNode = this.wrapCommand(function (node) {\n      if (_this.isLimited(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(node).text().length)) {\n        return;\n      }\n\n      var rng = _this.getLastRange();\n\n      rng.insertNode(node);\n\n      _this.setLastRange(range.createFromNodeAfter(node).select());\n    });\n    /**\n     * insert text\n     * @param {String} text\n     */\n\n    this.insertText = this.wrapCommand(function (text) {\n      if (_this.isLimited(text.length)) {\n        return;\n      }\n\n      var rng = _this.getLastRange();\n\n      var textNode = rng.insertNode(dom.createText(text));\n\n      _this.setLastRange(range.create(textNode, dom.nodeLength(textNode)).select());\n    });\n    /**\n     * paste HTML\n     * @param {String} markup\n     */\n\n    this.pasteHTML = this.wrapCommand(function (markup) {\n      if (_this.isLimited(markup.length)) {\n        return;\n      }\n\n      markup = _this.context.invoke('codeview.purify', markup);\n\n      var contents = _this.getLastRange().pasteHTML(markup);\n\n      _this.setLastRange(range.createFromNodeAfter(lists.last(contents)).select());\n    });\n    /**\n     * formatBlock\n     *\n     * @param {String} tagName\n     */\n\n    this.formatBlock = this.wrapCommand(function (tagName, $target) {\n      var onApplyCustomStyle = _this.options.callbacks.onApplyCustomStyle;\n\n      if (onApplyCustomStyle) {\n        onApplyCustomStyle.call(_this, $target, _this.context, _this.onFormatBlock);\n      } else {\n        _this.onFormatBlock(tagName, $target);\n      }\n    });\n    /**\n     * insert horizontal rule\n     */\n\n    this.insertHorizontalRule = this.wrapCommand(function () {\n      var hrNode = _this.getLastRange().insertNode(dom.create('HR'));\n\n      if (hrNode.nextSibling) {\n        _this.setLastRange(range.create(hrNode.nextSibling, 0).normalize().select());\n      }\n    });\n    /**\n     * lineHeight\n     * @param {String} value\n     */\n\n    this.lineHeight = this.wrapCommand(function (value) {\n      _this.style.stylePara(_this.getLastRange(), {\n        lineHeight: value\n      });\n    });\n    /**\n     * create link (command)\n     *\n     * @param {Object} linkInfo\n     */\n\n    this.createLink = this.wrapCommand(function (linkInfo) {\n      var linkUrl = linkInfo.url;\n      var linkText = linkInfo.text;\n      var isNewWindow = linkInfo.isNewWindow;\n      var checkProtocol = linkInfo.checkProtocol;\n\n      var rng = linkInfo.range || _this.getLastRange();\n\n      var additionalTextLength = linkText.length - rng.toString().length;\n\n      if (additionalTextLength > 0 && _this.isLimited(additionalTextLength)) {\n        return;\n      }\n\n      var isTextChanged = rng.toString() !== linkText; // handle spaced urls from input\n\n      if (typeof linkUrl === 'string') {\n        linkUrl = linkUrl.trim();\n      }\n\n      if (_this.options.onCreateLink) {\n        linkUrl = _this.options.onCreateLink(linkUrl);\n      } else if (checkProtocol) {\n        // if url doesn't have any protocol and not even a relative or a label, use http:// as default\n        linkUrl = /^([A-Za-z][A-Za-z0-9+-.]*\\:|#|\\/)/.test(linkUrl) ? linkUrl : _this.options.defaultProtocol + linkUrl;\n      }\n\n      var anchors = [];\n\n      if (isTextChanged) {\n        rng = rng.deleteContents();\n        var anchor = rng.insertNode(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<A>' + linkText + '</A>')[0]);\n        anchors.push(anchor);\n      } else {\n        anchors = _this.style.styleNodes(rng, {\n          nodeName: 'A',\n          expandClosestSibling: true,\n          onlyPartialContains: true\n        });\n      }\n\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(anchors, function (idx, anchor) {\n        external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(anchor).attr('href', linkUrl);\n\n        if (isNewWindow) {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(anchor).attr('target', '_blank');\n        } else {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(anchor).removeAttr('target');\n        }\n      });\n\n      _this.setLastRange(_this.createRangeFromList(anchors).select());\n    });\n    /**\n     * setting color\n     *\n     * @param {Object} sObjColor  color code\n     * @param {String} sObjColor.foreColor foreground color\n     * @param {String} sObjColor.backColor background color\n     */\n\n    this.color = this.wrapCommand(function (colorInfo) {\n      var foreColor = colorInfo.foreColor;\n      var backColor = colorInfo.backColor;\n\n      if (foreColor) {\n        document.execCommand('foreColor', false, foreColor);\n      }\n\n      if (backColor) {\n        document.execCommand('backColor', false, backColor);\n      }\n    });\n    /**\n     * Set foreground color\n     *\n     * @param {String} colorCode foreground color code\n     */\n\n    this.foreColor = this.wrapCommand(function (colorInfo) {\n      document.execCommand('foreColor', false, colorInfo);\n    });\n    /**\n     * insert Table\n     *\n     * @param {String} dimension of table (ex : \"5x5\")\n     */\n\n    this.insertTable = this.wrapCommand(function (dim) {\n      var dimension = dim.split('x');\n\n      var rng = _this.getLastRange().deleteContents();\n\n      rng.insertNode(_this.table.createTable(dimension[0], dimension[1], _this.options));\n    });\n    /**\n     * remove media object and Figure Elements if media object is img with Figure.\n     */\n\n    this.removeMedia = this.wrapCommand(function () {\n      var $target = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(_this.restoreTarget()).parent();\n\n      if ($target.closest('figure').length) {\n        $target.closest('figure').remove();\n      } else {\n        $target = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(_this.restoreTarget()).detach();\n      }\n\n      _this.context.triggerEvent('media.delete', $target, _this.$editable);\n    });\n    /**\n     * float me\n     *\n     * @param {String} value\n     */\n\n    this.floatMe = this.wrapCommand(function (value) {\n      var $target = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(_this.restoreTarget());\n      $target.toggleClass('note-float-left', value === 'left');\n      $target.toggleClass('note-float-right', value === 'right');\n      $target.css('float', value === 'none' ? '' : value);\n    });\n    /**\n     * resize overlay element\n     * @param {String} value\n     */\n\n    this.resize = this.wrapCommand(function (value) {\n      var $target = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(_this.restoreTarget());\n      value = parseFloat(value);\n\n      if (value === 0) {\n        $target.css('width', '');\n      } else {\n        $target.css({\n          width: value * 100 + '%',\n          height: ''\n        });\n      }\n    });\n  }\n\n  Editor_createClass(Editor, [{\n    key: \"initialize\",\n    value: function initialize() {\n      var _this2 = this;\n\n      // bind custom events\n      this.$editable.on('keydown', function (event) {\n        if (event.keyCode === core_key.code.ENTER) {\n          _this2.context.triggerEvent('enter', event);\n        }\n\n        _this2.context.triggerEvent('keydown', event); // keep a snapshot to limit text on input event\n\n\n        _this2.snapshot = _this2.history.makeSnapshot();\n        _this2.hasKeyShortCut = false;\n\n        if (!event.isDefaultPrevented()) {\n          if (_this2.options.shortcuts) {\n            _this2.hasKeyShortCut = _this2.handleKeyMap(event);\n          } else {\n            _this2.preventDefaultEditableShortCuts(event);\n          }\n        }\n\n        if (_this2.isLimited(1, event)) {\n          var lastRange = _this2.getLastRange();\n\n          if (lastRange.eo - lastRange.so === 0) {\n            return false;\n          }\n        }\n\n        _this2.setLastRange(); // record undo in the key event except keyMap.\n\n\n        if (_this2.options.recordEveryKeystroke) {\n          if (_this2.hasKeyShortCut === false) {\n            _this2.history.recordUndo();\n          }\n        }\n      }).on('keyup', function (event) {\n        _this2.setLastRange();\n\n        _this2.context.triggerEvent('keyup', event);\n      }).on('focus', function (event) {\n        _this2.setLastRange();\n\n        _this2.context.triggerEvent('focus', event);\n      }).on('blur', function (event) {\n        _this2.context.triggerEvent('blur', event);\n      }).on('mousedown', function (event) {\n        _this2.context.triggerEvent('mousedown', event);\n      }).on('mouseup', function (event) {\n        _this2.setLastRange();\n\n        _this2.history.recordUndo();\n\n        _this2.context.triggerEvent('mouseup', event);\n      }).on('scroll', function (event) {\n        _this2.context.triggerEvent('scroll', event);\n      }).on('paste', function (event) {\n        _this2.setLastRange();\n\n        _this2.context.triggerEvent('paste', event);\n      }).on('input', function () {\n        // To limit composition characters (e.g. Korean)\n        if (_this2.isLimited(0) && _this2.snapshot) {\n          _this2.history.applySnapshot(_this2.snapshot);\n        }\n      });\n      this.$editable.attr('spellcheck', this.options.spellCheck);\n      this.$editable.attr('autocorrect', this.options.spellCheck);\n\n      if (this.options.disableGrammar) {\n        this.$editable.attr('data-gramm', false);\n      } // init content before set event\n\n\n      this.$editable.html(dom.html(this.$note) || dom.emptyPara);\n      this.$editable.on(env.inputEventName, func.debounce(function () {\n        _this2.context.triggerEvent('change', _this2.$editable.html(), _this2.$editable);\n      }, 10));\n      this.$editable.on('focusin', function (event) {\n        _this2.context.triggerEvent('focusin', event);\n      }).on('focusout', function (event) {\n        _this2.context.triggerEvent('focusout', event);\n      });\n\n      if (this.options.airMode) {\n        if (this.options.overrideContextMenu) {\n          this.$editor.on('contextmenu', function (event) {\n            _this2.context.triggerEvent('contextmenu', event);\n\n            return false;\n          });\n        }\n      } else {\n        if (this.options.width) {\n          this.$editor.outerWidth(this.options.width);\n        }\n\n        if (this.options.height) {\n          this.$editable.outerHeight(this.options.height);\n        }\n\n        if (this.options.maxHeight) {\n          this.$editable.css('max-height', this.options.maxHeight);\n        }\n\n        if (this.options.minHeight) {\n          this.$editable.css('min-height', this.options.minHeight);\n        }\n      }\n\n      this.history.recordUndo();\n      this.setLastRange();\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$editable.off();\n    }\n  }, {\n    key: \"handleKeyMap\",\n    value: function handleKeyMap(event) {\n      var keyMap = this.options.keyMap[env.isMac ? 'mac' : 'pc'];\n      var keys = [];\n\n      if (event.metaKey) {\n        keys.push('CMD');\n      }\n\n      if (event.ctrlKey && !event.altKey) {\n        keys.push('CTRL');\n      }\n\n      if (event.shiftKey) {\n        keys.push('SHIFT');\n      }\n\n      var keyName = core_key.nameFromCode[event.keyCode];\n\n      if (keyName) {\n        keys.push(keyName);\n      }\n\n      var eventName = keyMap[keys.join('+')];\n\n      if (keyName === 'TAB' && !this.options.tabDisable) {\n        this.afterCommand();\n      } else if (eventName) {\n        if (this.context.invoke(eventName) !== false) {\n          event.preventDefault(); // if keyMap action was invoked\n\n          return true;\n        }\n      } else if (core_key.isEdit(event.keyCode)) {\n        this.afterCommand();\n      }\n\n      return false;\n    }\n  }, {\n    key: \"preventDefaultEditableShortCuts\",\n    value: function preventDefaultEditableShortCuts(event) {\n      // B(Bold, 66) / I(Italic, 73) / U(Underline, 85)\n      if ((event.ctrlKey || event.metaKey) && lists.contains([66, 73, 85], event.keyCode)) {\n        event.preventDefault();\n      }\n    }\n  }, {\n    key: \"isLimited\",\n    value: function isLimited(pad, event) {\n      pad = pad || 0;\n\n      if (typeof event !== 'undefined') {\n        if (core_key.isMove(event.keyCode) || core_key.isNavigation(event.keyCode) || event.ctrlKey || event.metaKey || lists.contains([core_key.code.BACKSPACE, core_key.code.DELETE], event.keyCode)) {\n          return false;\n        }\n      }\n\n      if (this.options.maxTextLength > 0) {\n        if (this.$editable.text().length + pad > this.options.maxTextLength) {\n          return true;\n        }\n      }\n\n      return false;\n    }\n    /**\n     * create range\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"createRange\",\n    value: function createRange() {\n      this.focus();\n      this.setLastRange();\n      return this.getLastRange();\n    }\n    /**\n     * create a new range from the list of elements\n     *\n     * @param {list} dom element list\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"createRangeFromList\",\n    value: function createRangeFromList(lst) {\n      var startRange = range.createFromNodeBefore(lists.head(lst));\n      var startPoint = startRange.getStartPoint();\n      var endRange = range.createFromNodeAfter(lists.last(lst));\n      var endPoint = endRange.getEndPoint();\n      return range.create(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);\n    }\n    /**\n     * set the last range\n     *\n     * if given rng is exist, set rng as the last range\n     * or create a new range at the end of the document\n     *\n     * @param {WrappedRange} rng\n     */\n\n  }, {\n    key: \"setLastRange\",\n    value: function setLastRange(rng) {\n      if (rng) {\n        this.lastRange = rng;\n      } else {\n        this.lastRange = range.create(this.editable);\n\n        if (external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this.lastRange.sc).closest('.note-editable').length === 0) {\n          this.lastRange = range.createFromBodyElement(this.editable);\n        }\n      }\n    }\n    /**\n     * get the last range\n     *\n     * if there is a saved last range, return it\n     * or create a new range and return it\n     *\n     * @return {WrappedRange}\n     */\n\n  }, {\n    key: \"getLastRange\",\n    value: function getLastRange() {\n      if (!this.lastRange) {\n        this.setLastRange();\n      }\n\n      return this.lastRange;\n    }\n    /**\n     * saveRange\n     *\n     * save current range\n     *\n     * @param {Boolean} [thenCollapse=false]\n     */\n\n  }, {\n    key: \"saveRange\",\n    value: function saveRange(thenCollapse) {\n      if (thenCollapse) {\n        this.getLastRange().collapse().select();\n      }\n    }\n    /**\n     * restoreRange\n     *\n     * restore lately range\n     */\n\n  }, {\n    key: \"restoreRange\",\n    value: function restoreRange() {\n      if (this.lastRange) {\n        this.lastRange.select();\n        this.focus();\n      }\n    }\n  }, {\n    key: \"saveTarget\",\n    value: function saveTarget(node) {\n      this.$editable.data('target', node);\n    }\n  }, {\n    key: \"clearTarget\",\n    value: function clearTarget() {\n      this.$editable.removeData('target');\n    }\n  }, {\n    key: \"restoreTarget\",\n    value: function restoreTarget() {\n      return this.$editable.data('target');\n    }\n    /**\n     * currentStyle\n     *\n     * current style\n     * @return {Object|Boolean} unfocus\n     */\n\n  }, {\n    key: \"currentStyle\",\n    value: function currentStyle() {\n      var rng = range.create();\n\n      if (rng) {\n        rng = rng.normalize();\n      }\n\n      return rng ? this.style.current(rng) : this.style.fromNode(this.$editable);\n    }\n    /**\n     * style from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n\n  }, {\n    key: \"styleFromNode\",\n    value: function styleFromNode($node) {\n      return this.style.fromNode($node);\n    }\n    /**\n     * undo\n     */\n\n  }, {\n    key: \"undo\",\n    value: function undo() {\n      this.context.triggerEvent('before.command', this.$editable.html());\n      this.history.undo();\n      this.context.triggerEvent('change', this.$editable.html(), this.$editable);\n    }\n    /*\n    * commit\n    */\n\n  }, {\n    key: \"commit\",\n    value: function commit() {\n      this.context.triggerEvent('before.command', this.$editable.html());\n      this.history.commit();\n      this.context.triggerEvent('change', this.$editable.html(), this.$editable);\n    }\n    /**\n     * redo\n     */\n\n  }, {\n    key: \"redo\",\n    value: function redo() {\n      this.context.triggerEvent('before.command', this.$editable.html());\n      this.history.redo();\n      this.context.triggerEvent('change', this.$editable.html(), this.$editable);\n    }\n    /**\n     * before command\n     */\n\n  }, {\n    key: \"beforeCommand\",\n    value: function beforeCommand() {\n      this.context.triggerEvent('before.command', this.$editable.html()); // Set styleWithCSS before run a command\n\n      document.execCommand('styleWithCSS', false, this.options.styleWithCSS); // keep focus on editable before command execution\n\n      this.focus();\n    }\n    /**\n     * after command\n     * @param {Boolean} isPreventTrigger\n     */\n\n  }, {\n    key: \"afterCommand\",\n    value: function afterCommand(isPreventTrigger) {\n      this.normalizeContent();\n      this.history.recordUndo();\n\n      if (!isPreventTrigger) {\n        this.context.triggerEvent('change', this.$editable.html(), this.$editable);\n      }\n    }\n    /**\n     * handle tab key\n     */\n\n  }, {\n    key: \"tab\",\n    value: function tab() {\n      var rng = this.getLastRange();\n\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        this.table.tab(rng);\n      } else {\n        if (this.options.tabSize === 0) {\n          return false;\n        }\n\n        if (!this.isLimited(this.options.tabSize)) {\n          this.beforeCommand();\n          this.typing.insertTab(rng, this.options.tabSize);\n          this.afterCommand();\n        }\n      }\n    }\n    /**\n     * handle shift+tab key\n     */\n\n  }, {\n    key: \"untab\",\n    value: function untab() {\n      var rng = this.getLastRange();\n\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        this.table.tab(rng, true);\n      } else {\n        if (this.options.tabSize === 0) {\n          return false;\n        }\n      }\n    }\n    /**\n     * run given function between beforeCommand and afterCommand\n     */\n\n  }, {\n    key: \"wrapCommand\",\n    value: function wrapCommand(fn) {\n      return function () {\n        this.beforeCommand();\n        fn.apply(this, arguments);\n        this.afterCommand();\n      };\n    }\n    /**\n     * insert image\n     *\n     * @param {String} src\n     * @param {String|Function} param\n     * @return {Promise}\n     */\n\n  }, {\n    key: \"insertImage\",\n    value: function insertImage(src, param) {\n      var _this3 = this;\n\n      return createImage(src, param).then(function ($image) {\n        _this3.beforeCommand();\n\n        if (typeof param === 'function') {\n          param($image);\n        } else {\n          if (typeof param === 'string') {\n            $image.attr('data-filename', param);\n          }\n\n          $image.css('width', Math.min(_this3.$editable.width(), $image.width()));\n        }\n\n        $image.show();\n\n        _this3.getLastRange().insertNode($image[0]);\n\n        _this3.setLastRange(range.createFromNodeAfter($image[0]).select());\n\n        _this3.afterCommand();\n      }).fail(function (e) {\n        _this3.context.triggerEvent('image.upload.error', e);\n      });\n    }\n    /**\n     * insertImages\n     * @param {File[]} files\n     */\n\n  }, {\n    key: \"insertImagesAsDataURL\",\n    value: function insertImagesAsDataURL(files) {\n      var _this4 = this;\n\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(files, function (idx, file) {\n        var filename = file.name;\n\n        if (_this4.options.maximumImageFileSize && _this4.options.maximumImageFileSize < file.size) {\n          _this4.context.triggerEvent('image.upload.error', _this4.lang.image.maximumFileSizeError);\n        } else {\n          readFileAsDataURL(file).then(function (dataURL) {\n            return _this4.insertImage(dataURL, filename);\n          }).fail(function () {\n            _this4.context.triggerEvent('image.upload.error');\n          });\n        }\n      });\n    }\n    /**\n     * insertImagesOrCallback\n     * @param {File[]} files\n     */\n\n  }, {\n    key: \"insertImagesOrCallback\",\n    value: function insertImagesOrCallback(files) {\n      var callbacks = this.options.callbacks; // If onImageUpload set,\n\n      if (callbacks.onImageUpload) {\n        this.context.triggerEvent('image.upload', files); // else insert Image as dataURL\n      } else {\n        this.insertImagesAsDataURL(files);\n      }\n    }\n    /**\n     * return selected plain text\n     * @return {String} text\n     */\n\n  }, {\n    key: \"getSelectedText\",\n    value: function getSelectedText() {\n      var rng = this.getLastRange(); // if range on anchor, expand range with anchor\n\n      if (rng.isOnAnchor()) {\n        rng = range.createFromNode(dom.ancestor(rng.sc, dom.isAnchor));\n      }\n\n      return rng.toString();\n    }\n  }, {\n    key: \"onFormatBlock\",\n    value: function onFormatBlock(tagName, $target) {\n      // [workaround] for MSIE, IE need `<`\n      document.execCommand('FormatBlock', false, env.isMSIE ? '<' + tagName + '>' : tagName); // support custom class\n\n      if ($target && $target.length) {\n        // find the exact element has given tagName\n        if ($target[0].tagName.toUpperCase() !== tagName.toUpperCase()) {\n          $target = $target.find(tagName);\n        }\n\n        if ($target && $target.length) {\n          var className = $target[0].className || '';\n\n          if (className) {\n            var currentRange = this.createRange();\n            var $parent = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()([currentRange.sc, currentRange.ec]).closest(tagName);\n            $parent.addClass(className);\n          }\n        }\n      }\n    }\n  }, {\n    key: \"formatPara\",\n    value: function formatPara() {\n      this.formatBlock('P');\n    }\n  }, {\n    key: \"fontStyling\",\n    value: function fontStyling(target, value) {\n      var rng = this.getLastRange();\n\n      if (rng !== '') {\n        var spans = this.style.styleNodes(rng);\n        this.$editor.find('.note-status-output').html('');\n        external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(spans).css(target, value); // [workaround] added styled bogus span for style\n        //  - also bogus character needed for cursor position\n\n        if (rng.isCollapsed()) {\n          var firstSpan = lists.head(spans);\n\n          if (firstSpan && !dom.nodeLength(firstSpan)) {\n            firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR;\n            range.createFromNode(firstSpan.firstChild).select();\n            this.setLastRange();\n            this.$editable.data(KEY_BOGUS, firstSpan);\n          }\n        } else {\n          this.setLastRange(this.createRangeFromList(spans).select());\n        }\n      } else {\n        var noteStatusOutput = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.now();\n        this.$editor.find('.note-status-output').html('<div id=\"note-status-output-' + noteStatusOutput + '\" class=\"alert alert-info\">' + this.lang.output.noSelection + '</div>');\n        setTimeout(function () {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('#note-status-output-' + noteStatusOutput).remove();\n        }, 5000);\n      }\n    }\n    /**\n     * unlink\n     *\n     * @type command\n     */\n\n  }, {\n    key: \"unlink\",\n    value: function unlink() {\n      var rng = this.getLastRange();\n\n      if (rng.isOnAnchor()) {\n        var anchor = dom.ancestor(rng.sc, dom.isAnchor);\n        rng = range.createFromNode(anchor);\n        rng.select();\n        this.setLastRange();\n        this.beforeCommand();\n        document.execCommand('unlink');\n        this.afterCommand();\n      }\n    }\n    /**\n     * returns link info\n     *\n     * @return {Object}\n     * @return {WrappedRange} return.range\n     * @return {String} return.text\n     * @return {Boolean} [return.isNewWindow=true]\n     * @return {String} [return.url=\"\"]\n     */\n\n  }, {\n    key: \"getLinkInfo\",\n    value: function getLinkInfo() {\n      var rng = this.getLastRange().expand(dom.isAnchor); // Get the first anchor on range(for edit).\n\n      var $anchor = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(lists.head(rng.nodes(dom.isAnchor)));\n      var linkInfo = {\n        range: rng,\n        text: rng.toString(),\n        url: $anchor.length ? $anchor.attr('href') : ''\n      }; // When anchor exists,\n\n      if ($anchor.length) {\n        // Set isNewWindow by checking its target.\n        linkInfo.isNewWindow = $anchor.attr('target') === '_blank';\n      }\n\n      return linkInfo;\n    }\n  }, {\n    key: \"addRow\",\n    value: function addRow(position) {\n      var rng = this.getLastRange(this.$editable);\n\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        this.beforeCommand();\n        this.table.addRow(rng, position);\n        this.afterCommand();\n      }\n    }\n  }, {\n    key: \"addCol\",\n    value: function addCol(position) {\n      var rng = this.getLastRange(this.$editable);\n\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        this.beforeCommand();\n        this.table.addCol(rng, position);\n        this.afterCommand();\n      }\n    }\n  }, {\n    key: \"deleteRow\",\n    value: function deleteRow() {\n      var rng = this.getLastRange(this.$editable);\n\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        this.beforeCommand();\n        this.table.deleteRow(rng);\n        this.afterCommand();\n      }\n    }\n  }, {\n    key: \"deleteCol\",\n    value: function deleteCol() {\n      var rng = this.getLastRange(this.$editable);\n\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        this.beforeCommand();\n        this.table.deleteCol(rng);\n        this.afterCommand();\n      }\n    }\n  }, {\n    key: \"deleteTable\",\n    value: function deleteTable() {\n      var rng = this.getLastRange(this.$editable);\n\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        this.beforeCommand();\n        this.table.deleteTable(rng);\n        this.afterCommand();\n      }\n    }\n    /**\n     * @param {Position} pos\n     * @param {jQuery} $target - target element\n     * @param {Boolean} [bKeepRatio] - keep ratio\n     */\n\n  }, {\n    key: \"resizeTo\",\n    value: function resizeTo(pos, $target, bKeepRatio) {\n      var imageSize;\n\n      if (bKeepRatio) {\n        var newRatio = pos.y / pos.x;\n        var ratio = $target.data('ratio');\n        imageSize = {\n          width: ratio > newRatio ? pos.x : pos.y / ratio,\n          height: ratio > newRatio ? pos.x * ratio : pos.y\n        };\n      } else {\n        imageSize = {\n          width: pos.x,\n          height: pos.y\n        };\n      }\n\n      $target.css(imageSize);\n    }\n    /**\n     * returns whether editable area has focus or not.\n     */\n\n  }, {\n    key: \"hasFocus\",\n    value: function hasFocus() {\n      return this.$editable.is(':focus');\n    }\n    /**\n     * set focus\n     */\n\n  }, {\n    key: \"focus\",\n    value: function focus() {\n      // [workaround] Screen will move when page is scolled in IE.\n      //  - do focus when not focused\n      if (!this.hasFocus()) {\n        this.$editable.focus();\n      }\n    }\n    /**\n     * returns whether contents is empty or not.\n     * @return {Boolean}\n     */\n\n  }, {\n    key: \"isEmpty\",\n    value: function isEmpty() {\n      return dom.isEmpty(this.$editable[0]) || dom.emptyPara === this.$editable.html();\n    }\n    /**\n     * Removes all contents and restores the editable instance to an _emptyPara_.\n     */\n\n  }, {\n    key: \"empty\",\n    value: function empty() {\n      this.context.invoke('code', dom.emptyPara);\n    }\n    /**\n     * normalize content\n     */\n\n  }, {\n    key: \"normalizeContent\",\n    value: function normalizeContent() {\n      this.$editable[0].normalize();\n    }\n  }]);\n\n  return Editor;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Clipboard.js\nfunction Clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Clipboard_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Clipboard_createClass(Constructor, protoProps, staticProps) { if (protoProps) Clipboard_defineProperties(Constructor.prototype, protoProps); if (staticProps) Clipboard_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar Clipboard_Clipboard = /*#__PURE__*/function () {\n  function Clipboard(context) {\n    Clipboard_classCallCheck(this, Clipboard);\n\n    this.context = context;\n    this.$editable = context.layoutInfo.editable;\n  }\n\n  Clipboard_createClass(Clipboard, [{\n    key: \"initialize\",\n    value: function initialize() {\n      this.$editable.on('paste', this.pasteByEvent.bind(this));\n    }\n    /**\n     * paste by clipboard event\n     *\n     * @param {Event} event\n     */\n\n  }, {\n    key: \"pasteByEvent\",\n    value: function pasteByEvent(event) {\n      var _this = this;\n\n      var clipboardData = event.originalEvent.clipboardData;\n\n      if (clipboardData && clipboardData.items && clipboardData.items.length) {\n        var item = clipboardData.items.length > 1 ? clipboardData.items[1] : lists.head(clipboardData.items);\n\n        if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {\n          // paste img file\n          this.context.invoke('editor.insertImagesOrCallback', [item.getAsFile()]);\n          event.preventDefault();\n        } else if (item.kind === 'string') {\n          // paste text with maxTextLength check\n          if (this.context.invoke('editor.isLimited', clipboardData.getData('Text').length)) {\n            event.preventDefault();\n          }\n        }\n      } else if (window.clipboardData) {\n        // for IE\n        var text = window.clipboardData.getData('text');\n\n        if (this.context.invoke('editor.isLimited', text.length)) {\n          event.preventDefault();\n        }\n      } // Call editor.afterCommand after proceeding default event handler\n\n\n      setTimeout(function () {\n        _this.context.invoke('editor.afterCommand');\n      }, 10);\n    }\n  }]);\n\n  return Clipboard;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Dropzone.js\nfunction Dropzone_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Dropzone_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Dropzone_createClass(Constructor, protoProps, staticProps) { if (protoProps) Dropzone_defineProperties(Constructor.prototype, protoProps); if (staticProps) Dropzone_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar Dropzone_Dropzone = /*#__PURE__*/function () {\n  function Dropzone(context) {\n    Dropzone_classCallCheck(this, Dropzone);\n\n    this.context = context;\n    this.$eventListener = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document);\n    this.$editor = context.layoutInfo.editor;\n    this.$editable = context.layoutInfo.editable;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n    this.documentEventHandlers = {};\n    this.$dropzone = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(['<div class=\"note-dropzone\">', '<div class=\"note-dropzone-message\"></div>', '</div>'].join('')).prependTo(this.$editor);\n  }\n  /**\n   * attach Drag and Drop Events\n   */\n\n\n  Dropzone_createClass(Dropzone, [{\n    key: \"initialize\",\n    value: function initialize() {\n      if (this.options.disableDragAndDrop) {\n        // prevent default drop event\n        this.documentEventHandlers.onDrop = function (e) {\n          e.preventDefault();\n        }; // do not consider outside of dropzone\n\n\n        this.$eventListener = this.$dropzone;\n        this.$eventListener.on('drop', this.documentEventHandlers.onDrop);\n      } else {\n        this.attachDragAndDropEvent();\n      }\n    }\n    /**\n     * attach Drag and Drop Events\n     */\n\n  }, {\n    key: \"attachDragAndDropEvent\",\n    value: function attachDragAndDropEvent() {\n      var _this = this;\n\n      var collection = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()();\n      var $dropzoneMessage = this.$dropzone.find('.note-dropzone-message');\n\n      this.documentEventHandlers.onDragenter = function (e) {\n        var isCodeview = _this.context.invoke('codeview.isActivated');\n\n        var hasEditorSize = _this.$editor.width() > 0 && _this.$editor.height() > 0;\n\n        if (!isCodeview && !collection.length && hasEditorSize) {\n          _this.$editor.addClass('dragover');\n\n          _this.$dropzone.width(_this.$editor.width());\n\n          _this.$dropzone.height(_this.$editor.height());\n\n          $dropzoneMessage.text(_this.lang.image.dragImageHere);\n        }\n\n        collection = collection.add(e.target);\n      };\n\n      this.documentEventHandlers.onDragleave = function (e) {\n        collection = collection.not(e.target); // If nodeName is BODY, then just make it over (fix for IE)\n\n        if (!collection.length || e.target.nodeName === 'BODY') {\n          collection = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()();\n\n          _this.$editor.removeClass('dragover');\n        }\n      };\n\n      this.documentEventHandlers.onDrop = function () {\n        collection = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()();\n\n        _this.$editor.removeClass('dragover');\n      }; // show dropzone on dragenter when dragging a object to document\n      // -but only if the editor is visible, i.e. has a positive width and height\n\n\n      this.$eventListener.on('dragenter', this.documentEventHandlers.onDragenter).on('dragleave', this.documentEventHandlers.onDragleave).on('drop', this.documentEventHandlers.onDrop); // change dropzone's message on hover.\n\n      this.$dropzone.on('dragenter', function () {\n        _this.$dropzone.addClass('hover');\n\n        $dropzoneMessage.text(_this.lang.image.dropImage);\n      }).on('dragleave', function () {\n        _this.$dropzone.removeClass('hover');\n\n        $dropzoneMessage.text(_this.lang.image.dragImageHere);\n      }); // attach dropImage\n\n      this.$dropzone.on('drop', function (event) {\n        var dataTransfer = event.originalEvent.dataTransfer; // stop the browser from opening the dropped content\n\n        event.preventDefault();\n\n        if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {\n          _this.$editable.focus();\n\n          _this.context.invoke('editor.insertImagesOrCallback', dataTransfer.files);\n        } else {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(dataTransfer.types, function (idx, type) {\n            // skip moz-specific types\n            if (type.toLowerCase().indexOf('_moz_') > -1) {\n              return;\n            }\n\n            var content = dataTransfer.getData(type);\n\n            if (type.toLowerCase().indexOf('text') > -1) {\n              _this.context.invoke('editor.pasteHTML', content);\n            } else {\n              external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(content).each(function (idx, item) {\n                _this.context.invoke('editor.insertNode', item);\n              });\n            }\n          });\n        }\n      }).on('dragover', false); // prevent default dragover event\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      var _this2 = this;\n\n      Object.keys(this.documentEventHandlers).forEach(function (key) {\n        _this2.$eventListener.off(key.substr(2).toLowerCase(), _this2.documentEventHandlers[key]);\n      });\n      this.documentEventHandlers = {};\n    }\n  }]);\n\n  return Dropzone;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Codeview.js\nfunction _createForOfIteratorHelper(o) { if (typeof Symbol === \"undefined\" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) { var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); } var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it[\"return\"] != null) it[\"return\"](); } finally { if (didErr) throw err; } } }; }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(n); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction Codeview_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Codeview_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Codeview_createClass(Constructor, protoProps, staticProps) { if (protoProps) Codeview_defineProperties(Constructor.prototype, protoProps); if (staticProps) Codeview_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n/**\n * @class Codeview\n */\n\nvar Codeview_CodeView = /*#__PURE__*/function () {\n  function CodeView(context) {\n    Codeview_classCallCheck(this, CodeView);\n\n    this.context = context;\n    this.$editor = context.layoutInfo.editor;\n    this.$editable = context.layoutInfo.editable;\n    this.$codable = context.layoutInfo.codable;\n    this.options = context.options;\n    this.CodeMirrorConstructor = window.CodeMirror;\n\n    if (this.options.codemirror.CodeMirrorConstructor) {\n      this.CodeMirrorConstructor = this.options.codemirror.CodeMirrorConstructor;\n    }\n  }\n\n  Codeview_createClass(CodeView, [{\n    key: \"sync\",\n    value: function sync(html) {\n      var isCodeview = this.isActivated();\n      var CodeMirror = this.CodeMirrorConstructor;\n\n      if (isCodeview) {\n        if (html) {\n          if (CodeMirror) {\n            this.$codable.data('cmEditor').getDoc().setValue(html);\n          } else {\n            this.$codable.val(html);\n          }\n        } else {\n          if (CodeMirror) {\n            this.$codable.data('cmEditor').save();\n          }\n        }\n      }\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      var _this = this;\n\n      this.$codable.on('keyup', function (event) {\n        if (event.keyCode === core_key.code.ESCAPE) {\n          _this.deactivate();\n        }\n      });\n    }\n    /**\n     * @return {Boolean}\n     */\n\n  }, {\n    key: \"isActivated\",\n    value: function isActivated() {\n      return this.$editor.hasClass('codeview');\n    }\n    /**\n     * toggle codeview\n     */\n\n  }, {\n    key: \"toggle\",\n    value: function toggle() {\n      if (this.isActivated()) {\n        this.deactivate();\n      } else {\n        this.activate();\n      }\n\n      this.context.triggerEvent('codeview.toggled');\n    }\n    /**\n     * purify input value\n     * @param value\n     * @returns {*}\n     */\n\n  }, {\n    key: \"purify\",\n    value: function purify(value) {\n      if (this.options.codeviewFilter) {\n        // filter code view regex\n        value = value.replace(this.options.codeviewFilterRegex, ''); // allow specific iframe tag\n\n        if (this.options.codeviewIframeFilter) {\n          var whitelist = this.options.codeviewIframeWhitelistSrc.concat(this.options.codeviewIframeWhitelistSrcBase);\n          value = value.replace(/(<iframe.*?>.*?(?:<\\/iframe>)?)/gi, function (tag) {\n            // remove if src attribute is duplicated\n            if (/<.+src(?==?('|\"|\\s)?)[\\s\\S]+src(?=('|\"|\\s)?)[^>]*?>/i.test(tag)) {\n              return '';\n            }\n\n            var _iterator = _createForOfIteratorHelper(whitelist),\n                _step;\n\n            try {\n              for (_iterator.s(); !(_step = _iterator.n()).done;) {\n                var src = _step.value;\n\n                // pass if src is trusted\n                if (new RegExp('src=\"(https?:)?\\/\\/' + src.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&') + '\\/(.+)\"').test(tag)) {\n                  return tag;\n                }\n              }\n            } catch (err) {\n              _iterator.e(err);\n            } finally {\n              _iterator.f();\n            }\n\n            return '';\n          });\n        }\n      }\n\n      return value;\n    }\n    /**\n     * activate code view\n     */\n\n  }, {\n    key: \"activate\",\n    value: function activate() {\n      var _this2 = this;\n\n      var CodeMirror = this.CodeMirrorConstructor;\n      this.$codable.val(dom.html(this.$editable, this.options.prettifyHtml));\n      this.$codable.height(this.$editable.height());\n      this.context.invoke('toolbar.updateCodeview', true);\n      this.context.invoke('airPopover.updateCodeview', true);\n      this.$editor.addClass('codeview');\n      this.$codable.focus(); // activate CodeMirror as codable\n\n      if (CodeMirror) {\n        var cmEditor = CodeMirror.fromTextArea(this.$codable[0], this.options.codemirror); // CodeMirror TernServer\n\n        if (this.options.codemirror.tern) {\n          var server = new CodeMirror.TernServer(this.options.codemirror.tern);\n          cmEditor.ternServer = server;\n          cmEditor.on('cursorActivity', function (cm) {\n            server.updateArgHints(cm);\n          });\n        }\n\n        cmEditor.on('blur', function (event) {\n          _this2.context.triggerEvent('blur.codeview', cmEditor.getValue(), event);\n        });\n        cmEditor.on('change', function () {\n          _this2.context.triggerEvent('change.codeview', cmEditor.getValue(), cmEditor);\n        }); // CodeMirror hasn't Padding.\n\n        cmEditor.setSize(null, this.$editable.outerHeight());\n        this.$codable.data('cmEditor', cmEditor);\n      } else {\n        this.$codable.on('blur', function (event) {\n          _this2.context.triggerEvent('blur.codeview', _this2.$codable.val(), event);\n        });\n        this.$codable.on('input', function () {\n          _this2.context.triggerEvent('change.codeview', _this2.$codable.val(), _this2.$codable);\n        });\n      }\n    }\n    /**\n     * deactivate code view\n     */\n\n  }, {\n    key: \"deactivate\",\n    value: function deactivate() {\n      var CodeMirror = this.CodeMirrorConstructor; // deactivate CodeMirror as codable\n\n      if (CodeMirror) {\n        var cmEditor = this.$codable.data('cmEditor');\n        this.$codable.val(cmEditor.getValue());\n        cmEditor.toTextArea();\n      }\n\n      var value = this.purify(dom.value(this.$codable, this.options.prettifyHtml) || dom.emptyPara);\n      var isChange = this.$editable.html() !== value;\n      this.$editable.html(value);\n      this.$editable.height(this.options.height ? this.$codable.height() : 'auto');\n      this.$editor.removeClass('codeview');\n\n      if (isChange) {\n        this.context.triggerEvent('change', this.$editable.html(), this.$editable);\n      }\n\n      this.$editable.focus();\n      this.context.invoke('toolbar.updateCodeview', false);\n      this.context.invoke('airPopover.updateCodeview', false);\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      if (this.isActivated()) {\n        this.deactivate();\n      }\n    }\n  }]);\n\n  return CodeView;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Statusbar.js\nfunction Statusbar_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Statusbar_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Statusbar_createClass(Constructor, protoProps, staticProps) { if (protoProps) Statusbar_defineProperties(Constructor.prototype, protoProps); if (staticProps) Statusbar_defineProperties(Constructor, staticProps); return Constructor; }\n\n\nvar EDITABLE_PADDING = 24;\n\nvar Statusbar_Statusbar = /*#__PURE__*/function () {\n  function Statusbar(context) {\n    Statusbar_classCallCheck(this, Statusbar);\n\n    this.$document = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document);\n    this.$statusbar = context.layoutInfo.statusbar;\n    this.$editable = context.layoutInfo.editable;\n    this.options = context.options;\n  }\n\n  Statusbar_createClass(Statusbar, [{\n    key: \"initialize\",\n    value: function initialize() {\n      var _this = this;\n\n      if (this.options.airMode || this.options.disableResizeEditor) {\n        this.destroy();\n        return;\n      }\n\n      this.$statusbar.on('mousedown', function (event) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        var editableTop = _this.$editable.offset().top - _this.$document.scrollTop();\n\n        var onMouseMove = function onMouseMove(event) {\n          var height = event.clientY - (editableTop + EDITABLE_PADDING);\n          height = _this.options.minheight > 0 ? Math.max(height, _this.options.minheight) : height;\n          height = _this.options.maxHeight > 0 ? Math.min(height, _this.options.maxHeight) : height;\n\n          _this.$editable.height(height);\n        };\n\n        _this.$document.on('mousemove', onMouseMove).one('mouseup', function () {\n          _this.$document.off('mousemove', onMouseMove);\n        });\n      });\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$statusbar.off();\n      this.$statusbar.addClass('locked');\n    }\n  }]);\n\n  return Statusbar;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Fullscreen.js\nfunction Fullscreen_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Fullscreen_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Fullscreen_createClass(Constructor, protoProps, staticProps) { if (protoProps) Fullscreen_defineProperties(Constructor.prototype, protoProps); if (staticProps) Fullscreen_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar Fullscreen_Fullscreen = /*#__PURE__*/function () {\n  function Fullscreen(context) {\n    var _this = this;\n\n    Fullscreen_classCallCheck(this, Fullscreen);\n\n    this.context = context;\n    this.$editor = context.layoutInfo.editor;\n    this.$toolbar = context.layoutInfo.toolbar;\n    this.$editable = context.layoutInfo.editable;\n    this.$codable = context.layoutInfo.codable;\n    this.$window = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(window);\n    this.$scrollbar = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('html, body');\n\n    this.onResize = function () {\n      _this.resizeTo({\n        h: _this.$window.height() - _this.$toolbar.outerHeight()\n      });\n    };\n  }\n\n  Fullscreen_createClass(Fullscreen, [{\n    key: \"resizeTo\",\n    value: function resizeTo(size) {\n      this.$editable.css('height', size.h);\n      this.$codable.css('height', size.h);\n\n      if (this.$codable.data('cmeditor')) {\n        this.$codable.data('cmeditor').setsize(null, size.h);\n      }\n    }\n    /**\n     * toggle fullscreen\n     */\n\n  }, {\n    key: \"toggle\",\n    value: function toggle() {\n      this.$editor.toggleClass('fullscreen');\n\n      if (this.isFullscreen()) {\n        this.$editable.data('orgHeight', this.$editable.css('height'));\n        this.$editable.data('orgMaxHeight', this.$editable.css('maxHeight'));\n        this.$editable.css('maxHeight', '');\n        this.$window.on('resize', this.onResize).trigger('resize');\n        this.$scrollbar.css('overflow', 'hidden');\n      } else {\n        this.$window.off('resize', this.onResize);\n        this.resizeTo({\n          h: this.$editable.data('orgHeight')\n        });\n        this.$editable.css('maxHeight', this.$editable.css('orgMaxHeight'));\n        this.$scrollbar.css('overflow', 'visible');\n      }\n\n      this.context.invoke('toolbar.updateFullscreen', this.isFullscreen());\n    }\n  }, {\n    key: \"isFullscreen\",\n    value: function isFullscreen() {\n      return this.$editor.hasClass('fullscreen');\n    }\n  }]);\n\n  return Fullscreen;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Handle.js\nfunction Handle_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Handle_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Handle_createClass(Constructor, protoProps, staticProps) { if (protoProps) Handle_defineProperties(Constructor.prototype, protoProps); if (staticProps) Handle_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\nvar Handle_Handle = /*#__PURE__*/function () {\n  function Handle(context) {\n    var _this = this;\n\n    Handle_classCallCheck(this, Handle);\n\n    this.context = context;\n    this.$document = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document);\n    this.$editingArea = context.layoutInfo.editingArea;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n    this.events = {\n      'summernote.mousedown': function summernoteMousedown(we, e) {\n        if (_this.update(e.target, e)) {\n          e.preventDefault();\n        }\n      },\n      'summernote.keyup summernote.scroll summernote.change summernote.dialog.shown': function summernoteKeyupSummernoteScrollSummernoteChangeSummernoteDialogShown() {\n        _this.update();\n      },\n      'summernote.disable summernote.blur': function summernoteDisableSummernoteBlur() {\n        _this.hide();\n      },\n      'summernote.codeview.toggled': function summernoteCodeviewToggled() {\n        _this.update();\n      }\n    };\n  }\n\n  Handle_createClass(Handle, [{\n    key: \"initialize\",\n    value: function initialize() {\n      var _this2 = this;\n\n      this.$handle = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(['<div class=\"note-handle\">', '<div class=\"note-control-selection\">', '<div class=\"note-control-selection-bg\"></div>', '<div class=\"note-control-holder note-control-nw\"></div>', '<div class=\"note-control-holder note-control-ne\"></div>', '<div class=\"note-control-holder note-control-sw\"></div>', '<div class=\"', this.options.disableResizeImage ? 'note-control-holder' : 'note-control-sizing', ' note-control-se\"></div>', this.options.disableResizeImage ? '' : '<div class=\"note-control-selection-info\"></div>', '</div>', '</div>'].join('')).prependTo(this.$editingArea);\n      this.$handle.on('mousedown', function (event) {\n        if (dom.isControlSizing(event.target)) {\n          event.preventDefault();\n          event.stopPropagation();\n\n          var $target = _this2.$handle.find('.note-control-selection').data('target');\n\n          var posStart = $target.offset();\n\n          var scrollTop = _this2.$document.scrollTop();\n\n          var onMouseMove = function onMouseMove(event) {\n            _this2.context.invoke('editor.resizeTo', {\n              x: event.clientX - posStart.left,\n              y: event.clientY - (posStart.top - scrollTop)\n            }, $target, !event.shiftKey);\n\n            _this2.update($target[0], event);\n          };\n\n          _this2.$document.on('mousemove', onMouseMove).one('mouseup', function (e) {\n            e.preventDefault();\n\n            _this2.$document.off('mousemove', onMouseMove);\n\n            _this2.context.invoke('editor.afterCommand');\n          });\n\n          if (!$target.data('ratio')) {\n            // original ratio.\n            $target.data('ratio', $target.height() / $target.width());\n          }\n        }\n      }); // Listen for scrolling on the handle overlay.\n\n      this.$handle.on('wheel', function (e) {\n        e.preventDefault();\n\n        _this2.update();\n      });\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$handle.remove();\n    }\n  }, {\n    key: \"update\",\n    value: function update(target, event) {\n      if (this.context.isDisabled()) {\n        return false;\n      }\n\n      var isImage = dom.isImg(target);\n      var $selection = this.$handle.find('.note-control-selection');\n      this.context.invoke('imagePopover.update', target, event);\n\n      if (isImage) {\n        var $image = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(target);\n        var position = $image.position();\n        var pos = {\n          left: position.left + parseInt($image.css('marginLeft'), 10),\n          top: position.top + parseInt($image.css('marginTop'), 10)\n        }; // exclude margin\n\n        var imageSize = {\n          w: $image.outerWidth(false),\n          h: $image.outerHeight(false)\n        };\n        $selection.css({\n          display: 'block',\n          left: pos.left,\n          top: pos.top,\n          width: imageSize.w,\n          height: imageSize.h\n        }).data('target', $image); // save current image element.\n\n        var origImageObj = new Image();\n        origImageObj.src = $image.attr('src');\n        var sizingText = imageSize.w + 'x' + imageSize.h + ' (' + this.lang.image.original + ': ' + origImageObj.width + 'x' + origImageObj.height + ')';\n        $selection.find('.note-control-selection-info').text(sizingText);\n        this.context.invoke('editor.saveTarget', target);\n      } else {\n        this.hide();\n      }\n\n      return isImage;\n    }\n    /**\n     * hide\n     *\n     * @param {jQuery} $handle\n     */\n\n  }, {\n    key: \"hide\",\n    value: function hide() {\n      this.context.invoke('editor.clearTarget');\n      this.$handle.children().hide();\n    }\n  }]);\n\n  return Handle;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/AutoLink.js\nfunction AutoLink_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction AutoLink_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction AutoLink_createClass(Constructor, protoProps, staticProps) { if (protoProps) AutoLink_defineProperties(Constructor.prototype, protoProps); if (staticProps) AutoLink_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\nvar defaultScheme = 'http://';\nvar linkPattern = /^([A-Za-z][A-Za-z0-9+-.]*\\:[\\/]{2}|tel:|mailto:[A-Z0-9._%+-]+@)?(www\\.)?(.+)$/i;\n\nvar AutoLink_AutoLink = /*#__PURE__*/function () {\n  function AutoLink(context) {\n    var _this = this;\n\n    AutoLink_classCallCheck(this, AutoLink);\n\n    this.context = context;\n    this.options = context.options;\n    this.events = {\n      'summernote.keyup': function summernoteKeyup(we, e) {\n        if (!e.isDefaultPrevented()) {\n          _this.handleKeyup(e);\n        }\n      },\n      'summernote.keydown': function summernoteKeydown(we, e) {\n        _this.handleKeydown(e);\n      }\n    };\n  }\n\n  AutoLink_createClass(AutoLink, [{\n    key: \"initialize\",\n    value: function initialize() {\n      this.lastWordRange = null;\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.lastWordRange = null;\n    }\n  }, {\n    key: \"replace\",\n    value: function replace() {\n      if (!this.lastWordRange) {\n        return;\n      }\n\n      var keyword = this.lastWordRange.toString();\n      var match = keyword.match(linkPattern);\n\n      if (match && (match[1] || match[2])) {\n        var link = match[1] ? keyword : defaultScheme + keyword;\n        var urlText = this.options.showDomainOnlyForAutolink ? keyword.replace(/^(?:https?:\\/\\/)?(?:tel?:?)?(?:mailto?:?)?(?:www\\.)?/i, '').split('/')[0] : keyword;\n        var node = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<a />').html(urlText).attr('href', link)[0];\n\n        if (this.context.options.linkTargetBlank) {\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(node).attr('target', '_blank');\n        }\n\n        this.lastWordRange.insertNode(node);\n        this.lastWordRange = null;\n        this.context.invoke('editor.focus');\n      }\n    }\n  }, {\n    key: \"handleKeydown\",\n    value: function handleKeydown(e) {\n      if (lists.contains([core_key.code.ENTER, core_key.code.SPACE], e.keyCode)) {\n        var wordRange = this.context.invoke('editor.createRange').getWordRange();\n        this.lastWordRange = wordRange;\n      }\n    }\n  }, {\n    key: \"handleKeyup\",\n    value: function handleKeyup(e) {\n      if (lists.contains([core_key.code.ENTER, core_key.code.SPACE], e.keyCode)) {\n        this.replace();\n      }\n    }\n  }]);\n\n  return AutoLink;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/AutoSync.js\nfunction AutoSync_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction AutoSync_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction AutoSync_createClass(Constructor, protoProps, staticProps) { if (protoProps) AutoSync_defineProperties(Constructor.prototype, protoProps); if (staticProps) AutoSync_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n/**\n * textarea auto sync.\n */\n\nvar AutoSync_AutoSync = /*#__PURE__*/function () {\n  function AutoSync(context) {\n    var _this = this;\n\n    AutoSync_classCallCheck(this, AutoSync);\n\n    this.$note = context.layoutInfo.note;\n    this.events = {\n      'summernote.change': function summernoteChange() {\n        _this.$note.val(context.invoke('code'));\n      }\n    };\n  }\n\n  AutoSync_createClass(AutoSync, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return dom.isTextarea(this.$note[0]);\n    }\n  }]);\n\n  return AutoSync;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/AutoReplace.js\nfunction AutoReplace_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction AutoReplace_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction AutoReplace_createClass(Constructor, protoProps, staticProps) { if (protoProps) AutoReplace_defineProperties(Constructor.prototype, protoProps); if (staticProps) AutoReplace_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\nvar AutoReplace_AutoReplace = /*#__PURE__*/function () {\n  function AutoReplace(context) {\n    var _this = this;\n\n    AutoReplace_classCallCheck(this, AutoReplace);\n\n    this.context = context;\n    this.options = context.options.replace || {};\n    this.keys = [core_key.code.ENTER, core_key.code.SPACE, core_key.code.PERIOD, core_key.code.COMMA, core_key.code.SEMICOLON, core_key.code.SLASH];\n    this.previousKeydownCode = null;\n    this.events = {\n      'summernote.keyup': function summernoteKeyup(we, e) {\n        if (!e.isDefaultPrevented()) {\n          _this.handleKeyup(e);\n        }\n      },\n      'summernote.keydown': function summernoteKeydown(we, e) {\n        _this.handleKeydown(e);\n      }\n    };\n  }\n\n  AutoReplace_createClass(AutoReplace, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return !!this.options.match;\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      this.lastWord = null;\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.lastWord = null;\n    }\n  }, {\n    key: \"replace\",\n    value: function replace() {\n      if (!this.lastWord) {\n        return;\n      }\n\n      var self = this;\n      var keyword = this.lastWord.toString();\n      this.options.match(keyword, function (match) {\n        if (match) {\n          var node = '';\n\n          if (typeof match === 'string') {\n            node = dom.createText(match);\n          } else if (match instanceof jQuery) {\n            node = match[0];\n          } else if (match instanceof Node) {\n            node = match;\n          }\n\n          if (!node) return;\n          self.lastWord.insertNode(node);\n          self.lastWord = null;\n          self.context.invoke('editor.focus');\n        }\n      });\n    }\n  }, {\n    key: \"handleKeydown\",\n    value: function handleKeydown(e) {\n      // this forces it to remember the last whole word, even if multiple termination keys are pressed\n      // before the previous key is let go.\n      if (this.previousKeydownCode && lists.contains(this.keys, this.previousKeydownCode)) {\n        this.previousKeydownCode = e.keyCode;\n        return;\n      }\n\n      if (lists.contains(this.keys, e.keyCode)) {\n        var wordRange = this.context.invoke('editor.createRange').getWordRange();\n        this.lastWord = wordRange;\n      }\n\n      this.previousKeydownCode = e.keyCode;\n    }\n  }, {\n    key: \"handleKeyup\",\n    value: function handleKeyup(e) {\n      if (lists.contains(this.keys, e.keyCode)) {\n        this.replace();\n      }\n    }\n  }]);\n\n  return AutoReplace;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Placeholder.js\nfunction Placeholder_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Placeholder_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Placeholder_createClass(Constructor, protoProps, staticProps) { if (protoProps) Placeholder_defineProperties(Constructor.prototype, protoProps); if (staticProps) Placeholder_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar Placeholder_Placeholder = /*#__PURE__*/function () {\n  function Placeholder(context) {\n    var _this = this;\n\n    Placeholder_classCallCheck(this, Placeholder);\n\n    this.context = context;\n    this.$editingArea = context.layoutInfo.editingArea;\n    this.options = context.options;\n\n    if (this.options.inheritPlaceholder === true) {\n      // get placeholder value from the original element\n      this.options.placeholder = this.context.$note.attr('placeholder') || this.options.placeholder;\n    }\n\n    this.events = {\n      'summernote.init summernote.change': function summernoteInitSummernoteChange() {\n        _this.update();\n      },\n      'summernote.codeview.toggled': function summernoteCodeviewToggled() {\n        _this.update();\n      }\n    };\n  }\n\n  Placeholder_createClass(Placeholder, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return !!this.options.placeholder;\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      var _this2 = this;\n\n      this.$placeholder = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div class=\"note-placeholder\">');\n      this.$placeholder.on('click', function () {\n        _this2.context.invoke('focus');\n      }).html(this.options.placeholder).prependTo(this.$editingArea);\n      this.update();\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$placeholder.remove();\n    }\n  }, {\n    key: \"update\",\n    value: function update() {\n      var isShow = !this.context.invoke('codeview.isActivated') && this.context.invoke('editor.isEmpty');\n      this.$placeholder.toggle(isShow);\n    }\n  }]);\n\n  return Placeholder;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Buttons.js\nfunction Buttons_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Buttons_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Buttons_createClass(Constructor, protoProps, staticProps) { if (protoProps) Buttons_defineProperties(Constructor.prototype, protoProps); if (staticProps) Buttons_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\nvar Buttons_Buttons = /*#__PURE__*/function () {\n  function Buttons(context) {\n    Buttons_classCallCheck(this, Buttons);\n\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.context = context;\n    this.$toolbar = context.layoutInfo.toolbar;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n    this.invertedKeyMap = func.invertObject(this.options.keyMap[env.isMac ? 'mac' : 'pc']);\n  }\n\n  Buttons_createClass(Buttons, [{\n    key: \"representShortcut\",\n    value: function representShortcut(editorMethod) {\n      var shortcut = this.invertedKeyMap[editorMethod];\n\n      if (!this.options.shortcuts || !shortcut) {\n        return '';\n      }\n\n      if (env.isMac) {\n        shortcut = shortcut.replace('CMD', '⌘').replace('SHIFT', '⇧');\n      }\n\n      shortcut = shortcut.replace('BACKSLASH', '\\\\').replace('SLASH', '/').replace('LEFTBRACKET', '[').replace('RIGHTBRACKET', ']');\n      return ' (' + shortcut + ')';\n    }\n  }, {\n    key: \"button\",\n    value: function button(o) {\n      if (!this.options.tooltip && o.tooltip) {\n        delete o.tooltip;\n      }\n\n      o.container = this.options.container;\n      return this.ui.button(o);\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      this.addToolbarButtons();\n      this.addImagePopoverButtons();\n      this.addLinkPopoverButtons();\n      this.addTablePopoverButtons();\n      this.fontInstalledMap = {};\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      delete this.fontInstalledMap;\n    }\n  }, {\n    key: \"isFontInstalled\",\n    value: function isFontInstalled(name) {\n      if (!Object.prototype.hasOwnProperty.call(this.fontInstalledMap, name)) {\n        this.fontInstalledMap[name] = env.isFontInstalled(name) || lists.contains(this.options.fontNamesIgnoreCheck, name);\n      }\n\n      return this.fontInstalledMap[name];\n    }\n  }, {\n    key: \"isFontDeservedToAdd\",\n    value: function isFontDeservedToAdd(name) {\n      name = name.toLowerCase();\n      return name !== '' && this.isFontInstalled(name) && env.genericFontFamilies.indexOf(name) === -1;\n    }\n  }, {\n    key: \"colorPalette\",\n    value: function colorPalette(className, tooltip, backColor, foreColor) {\n      var _this = this;\n\n      return this.ui.buttonGroup({\n        className: 'note-color ' + className,\n        children: [this.button({\n          className: 'note-current-color-button',\n          contents: this.ui.icon(this.options.icons.font + ' note-recent-color'),\n          tooltip: tooltip,\n          click: function click(e) {\n            var $button = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(e.currentTarget);\n\n            if (backColor && foreColor) {\n              _this.context.invoke('editor.color', {\n                backColor: $button.attr('data-backColor'),\n                foreColor: $button.attr('data-foreColor')\n              });\n            } else if (backColor) {\n              _this.context.invoke('editor.color', {\n                backColor: $button.attr('data-backColor')\n              });\n            } else if (foreColor) {\n              _this.context.invoke('editor.color', {\n                foreColor: $button.attr('data-foreColor')\n              });\n            }\n          },\n          callback: function callback($button) {\n            var $recentColor = $button.find('.note-recent-color');\n\n            if (backColor) {\n              $recentColor.css('background-color', _this.options.colorButton.backColor);\n              $button.attr('data-backColor', _this.options.colorButton.backColor);\n            }\n\n            if (foreColor) {\n              $recentColor.css('color', _this.options.colorButton.foreColor);\n              $button.attr('data-foreColor', _this.options.colorButton.foreColor);\n            } else {\n              $recentColor.css('color', 'transparent');\n            }\n          }\n        }), this.button({\n          className: 'dropdown-toggle',\n          contents: this.ui.dropdownButtonContents('', this.options),\n          tooltip: this.lang.color.more,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), this.ui.dropdown({\n          items: (backColor ? ['<div class=\"note-palette\">', '<div class=\"note-palette-title\">' + this.lang.color.background + '</div>', '<div>', '<button type=\"button\" class=\"note-color-reset btn btn-light btn-default\" data-event=\"backColor\" data-value=\"transparent\">', this.lang.color.transparent, '</button>', '</div>', '<div class=\"note-holder\" data-event=\"backColor\"><!-- back colors --></div>', '<div>', '<button type=\"button\" class=\"note-color-select btn btn-light btn-default\" data-event=\"openPalette\" data-value=\"backColorPicker\">', this.lang.color.cpSelect, '</button>', '<input type=\"color\" id=\"backColorPicker\" class=\"note-btn note-color-select-btn\" value=\"' + this.options.colorButton.backColor + '\" data-event=\"backColorPalette\">', '</div>', '<div class=\"note-holder-custom\" id=\"backColorPalette\" data-event=\"backColor\"></div>', '</div>'].join('') : '') + (foreColor ? ['<div class=\"note-palette\">', '<div class=\"note-palette-title\">' + this.lang.color.foreground + '</div>', '<div>', '<button type=\"button\" class=\"note-color-reset btn btn-light btn-default\" data-event=\"removeFormat\" data-value=\"foreColor\">', this.lang.color.resetToDefault, '</button>', '</div>', '<div class=\"note-holder\" data-event=\"foreColor\"><!-- fore colors --></div>', '<div>', '<button type=\"button\" class=\"note-color-select btn btn-light btn-default\" data-event=\"openPalette\" data-value=\"foreColorPicker\">', this.lang.color.cpSelect, '</button>', '<input type=\"color\" id=\"foreColorPicker\" class=\"note-btn note-color-select-btn\" value=\"' + this.options.colorButton.foreColor + '\" data-event=\"foreColorPalette\">', '</div>', // Fix missing Div, Commented to find easily if it's wrong\n          '<div class=\"note-holder-custom\" id=\"foreColorPalette\" data-event=\"foreColor\"></div>', '</div>'].join('') : ''),\n          callback: function callback($dropdown) {\n            $dropdown.find('.note-holder').each(function (idx, item) {\n              var $holder = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(item);\n              $holder.append(_this.ui.palette({\n                colors: _this.options.colors,\n                colorsName: _this.options.colorsName,\n                eventName: $holder.data('event'),\n                container: _this.options.container,\n                tooltip: _this.options.tooltip\n              }).render());\n            });\n            /* TODO: do we have to record recent custom colors within cookies? */\n\n            var customColors = [['#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF']];\n            $dropdown.find('.note-holder-custom').each(function (idx, item) {\n              var $holder = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(item);\n              $holder.append(_this.ui.palette({\n                colors: customColors,\n                colorsName: customColors,\n                eventName: $holder.data('event'),\n                container: _this.options.container,\n                tooltip: _this.options.tooltip\n              }).render());\n            });\n            $dropdown.find('input[type=color]').each(function (idx, item) {\n              external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(item).change(function () {\n                var $chip = $dropdown.find('#' + external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this).data('event')).find('.note-color-btn').first();\n                var color = this.value.toUpperCase();\n                $chip.css('background-color', color).attr('aria-label', color).attr('data-value', color).attr('data-original-title', color);\n                $chip.click();\n              });\n            });\n          },\n          click: function click(event) {\n            event.stopPropagation();\n            var $parent = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('.' + className).find('.note-dropdown-menu');\n            var $button = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(event.target);\n            var eventName = $button.data('event');\n            var value = $button.attr('data-value');\n\n            if (eventName === 'openPalette') {\n              var $picker = $parent.find('#' + value);\n              var $palette = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()($parent.find('#' + $picker.data('event')).find('.note-color-row')[0]); // Shift palette chips\n\n              var $chip = $palette.find('.note-color-btn').last().detach(); // Set chip attributes\n\n              var color = $picker.val();\n              $chip.css('background-color', color).attr('aria-label', color).attr('data-value', color).attr('data-original-title', color);\n              $palette.prepend($chip);\n              $picker.click();\n            } else {\n              if (lists.contains(['backColor', 'foreColor'], eventName)) {\n                var key = eventName === 'backColor' ? 'background-color' : 'color';\n                var $color = $button.closest('.note-color').find('.note-recent-color');\n                var $currentButton = $button.closest('.note-color').find('.note-current-color-button');\n                $color.css(key, value);\n                $currentButton.attr('data-' + eventName, value);\n              }\n\n              _this.context.invoke('editor.' + eventName, value);\n            }\n          }\n        })]\n      }).render();\n    }\n  }, {\n    key: \"addToolbarButtons\",\n    value: function addToolbarButtons() {\n      var _this2 = this;\n\n      this.context.memo('button.style', function () {\n        return _this2.ui.buttonGroup([_this2.button({\n          className: 'dropdown-toggle',\n          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.magic), _this2.options),\n          tooltip: _this2.lang.style.style,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), _this2.ui.dropdown({\n          className: 'dropdown-style',\n          items: _this2.options.styleTags,\n          title: _this2.lang.style.style,\n          template: function template(item) {\n            // TBD: need to be simplified\n            if (typeof item === 'string') {\n              item = {\n                tag: item,\n                title: Object.prototype.hasOwnProperty.call(_this2.lang.style, item) ? _this2.lang.style[item] : item\n              };\n            }\n\n            var tag = item.tag;\n            var title = item.title;\n            var style = item.style ? ' style=\"' + item.style + '\" ' : '';\n            var className = item.className ? ' class=\"' + item.className + '\"' : '';\n            return '<' + tag + style + className + '>' + title + '</' + tag + '>';\n          },\n          click: _this2.context.createInvokeHandler('editor.formatBlock')\n        })]).render();\n      });\n\n      var _loop = function _loop(styleIdx, styleLen) {\n        var item = _this2.options.styleTags[styleIdx];\n\n        _this2.context.memo('button.style.' + item, function () {\n          return _this2.button({\n            className: 'note-btn-style-' + item,\n            contents: '<div data-value=\"' + item + '\">' + item.toUpperCase() + '</div>',\n            tooltip: _this2.lang.style[item],\n            click: _this2.context.createInvokeHandler('editor.formatBlock')\n          }).render();\n        });\n      };\n\n      for (var styleIdx = 0, styleLen = this.options.styleTags.length; styleIdx < styleLen; styleIdx++) {\n        _loop(styleIdx, styleLen);\n      }\n\n      this.context.memo('button.bold', function () {\n        return _this2.button({\n          className: 'note-btn-bold',\n          contents: _this2.ui.icon(_this2.options.icons.bold),\n          tooltip: _this2.lang.font.bold + _this2.representShortcut('bold'),\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.bold')\n        }).render();\n      });\n      this.context.memo('button.italic', function () {\n        return _this2.button({\n          className: 'note-btn-italic',\n          contents: _this2.ui.icon(_this2.options.icons.italic),\n          tooltip: _this2.lang.font.italic + _this2.representShortcut('italic'),\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.italic')\n        }).render();\n      });\n      this.context.memo('button.underline', function () {\n        return _this2.button({\n          className: 'note-btn-underline',\n          contents: _this2.ui.icon(_this2.options.icons.underline),\n          tooltip: _this2.lang.font.underline + _this2.representShortcut('underline'),\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.underline')\n        }).render();\n      });\n      this.context.memo('button.clear', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.eraser),\n          tooltip: _this2.lang.font.clear + _this2.representShortcut('removeFormat'),\n          click: _this2.context.createInvokeHandler('editor.removeFormat')\n        }).render();\n      });\n      this.context.memo('button.strikethrough', function () {\n        return _this2.button({\n          className: 'note-btn-strikethrough',\n          contents: _this2.ui.icon(_this2.options.icons.strikethrough),\n          tooltip: _this2.lang.font.strikethrough + _this2.representShortcut('strikethrough'),\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.strikethrough')\n        }).render();\n      });\n      this.context.memo('button.superscript', function () {\n        return _this2.button({\n          className: 'note-btn-superscript',\n          contents: _this2.ui.icon(_this2.options.icons.superscript),\n          tooltip: _this2.lang.font.superscript,\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.superscript')\n        }).render();\n      });\n      this.context.memo('button.subscript', function () {\n        return _this2.button({\n          className: 'note-btn-subscript',\n          contents: _this2.ui.icon(_this2.options.icons.subscript),\n          tooltip: _this2.lang.font.subscript,\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.subscript')\n        }).render();\n      });\n      this.context.memo('button.fontname', function () {\n        var styleInfo = _this2.context.invoke('editor.currentStyle');\n\n        if (_this2.options.addDefaultFonts) {\n          // Add 'default' fonts into the fontnames array if not exist\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(styleInfo['font-family'].split(','), function (idx, fontname) {\n            fontname = fontname.trim().replace(/['\"]+/g, '');\n\n            if (_this2.isFontDeservedToAdd(fontname)) {\n              if (_this2.options.fontNames.indexOf(fontname) === -1) {\n                _this2.options.fontNames.push(fontname);\n              }\n            }\n          });\n        }\n\n        return _this2.ui.buttonGroup([_this2.button({\n          className: 'dropdown-toggle',\n          contents: _this2.ui.dropdownButtonContents('<span class=\"note-current-fontname\"></span>', _this2.options),\n          tooltip: _this2.lang.font.name,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), _this2.ui.dropdownCheck({\n          className: 'dropdown-fontname',\n          checkClassName: _this2.options.icons.menuCheck,\n          items: _this2.options.fontNames.filter(_this2.isFontInstalled.bind(_this2)),\n          title: _this2.lang.font.name,\n          template: function template(item) {\n            return '<span style=\"font-family: ' + env.validFontName(item) + '\">' + item + '</span>';\n          },\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.fontName')\n        })]).render();\n      });\n      this.context.memo('button.fontsize', function () {\n        return _this2.ui.buttonGroup([_this2.button({\n          className: 'dropdown-toggle',\n          contents: _this2.ui.dropdownButtonContents('<span class=\"note-current-fontsize\"></span>', _this2.options),\n          tooltip: _this2.lang.font.size,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), _this2.ui.dropdownCheck({\n          className: 'dropdown-fontsize',\n          checkClassName: _this2.options.icons.menuCheck,\n          items: _this2.options.fontSizes,\n          title: _this2.lang.font.size,\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.fontSize')\n        })]).render();\n      });\n      this.context.memo('button.fontsizeunit', function () {\n        return _this2.ui.buttonGroup([_this2.button({\n          className: 'dropdown-toggle',\n          contents: _this2.ui.dropdownButtonContents('<span class=\"note-current-fontsizeunit\"></span>', _this2.options),\n          tooltip: _this2.lang.font.sizeunit,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), _this2.ui.dropdownCheck({\n          className: 'dropdown-fontsizeunit',\n          checkClassName: _this2.options.icons.menuCheck,\n          items: _this2.options.fontSizeUnits,\n          title: _this2.lang.font.sizeunit,\n          click: _this2.context.createInvokeHandlerAndUpdateState('editor.fontSizeUnit')\n        })]).render();\n      });\n      this.context.memo('button.color', function () {\n        return _this2.colorPalette('note-color-all', _this2.lang.color.recent, true, true);\n      });\n      this.context.memo('button.forecolor', function () {\n        return _this2.colorPalette('note-color-fore', _this2.lang.color.foreground, false, true);\n      });\n      this.context.memo('button.backcolor', function () {\n        return _this2.colorPalette('note-color-back', _this2.lang.color.background, true, false);\n      });\n      this.context.memo('button.ul', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.unorderedlist),\n          tooltip: _this2.lang.lists.unordered + _this2.representShortcut('insertUnorderedList'),\n          click: _this2.context.createInvokeHandler('editor.insertUnorderedList')\n        }).render();\n      });\n      this.context.memo('button.ol', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.orderedlist),\n          tooltip: _this2.lang.lists.ordered + _this2.representShortcut('insertOrderedList'),\n          click: _this2.context.createInvokeHandler('editor.insertOrderedList')\n        }).render();\n      });\n      var justifyLeft = this.button({\n        contents: this.ui.icon(this.options.icons.alignLeft),\n        tooltip: this.lang.paragraph.left + this.representShortcut('justifyLeft'),\n        click: this.context.createInvokeHandler('editor.justifyLeft')\n      });\n      var justifyCenter = this.button({\n        contents: this.ui.icon(this.options.icons.alignCenter),\n        tooltip: this.lang.paragraph.center + this.representShortcut('justifyCenter'),\n        click: this.context.createInvokeHandler('editor.justifyCenter')\n      });\n      var justifyRight = this.button({\n        contents: this.ui.icon(this.options.icons.alignRight),\n        tooltip: this.lang.paragraph.right + this.representShortcut('justifyRight'),\n        click: this.context.createInvokeHandler('editor.justifyRight')\n      });\n      var justifyFull = this.button({\n        contents: this.ui.icon(this.options.icons.alignJustify),\n        tooltip: this.lang.paragraph.justify + this.representShortcut('justifyFull'),\n        click: this.context.createInvokeHandler('editor.justifyFull')\n      });\n      var outdent = this.button({\n        contents: this.ui.icon(this.options.icons.outdent),\n        tooltip: this.lang.paragraph.outdent + this.representShortcut('outdent'),\n        click: this.context.createInvokeHandler('editor.outdent')\n      });\n      var indent = this.button({\n        contents: this.ui.icon(this.options.icons.indent),\n        tooltip: this.lang.paragraph.indent + this.representShortcut('indent'),\n        click: this.context.createInvokeHandler('editor.indent')\n      });\n      this.context.memo('button.justifyLeft', func.invoke(justifyLeft, 'render'));\n      this.context.memo('button.justifyCenter', func.invoke(justifyCenter, 'render'));\n      this.context.memo('button.justifyRight', func.invoke(justifyRight, 'render'));\n      this.context.memo('button.justifyFull', func.invoke(justifyFull, 'render'));\n      this.context.memo('button.outdent', func.invoke(outdent, 'render'));\n      this.context.memo('button.indent', func.invoke(indent, 'render'));\n      this.context.memo('button.paragraph', function () {\n        return _this2.ui.buttonGroup([_this2.button({\n          className: 'dropdown-toggle',\n          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.alignLeft), _this2.options),\n          tooltip: _this2.lang.paragraph.paragraph,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), _this2.ui.dropdown([_this2.ui.buttonGroup({\n          className: 'note-align',\n          children: [justifyLeft, justifyCenter, justifyRight, justifyFull]\n        }), _this2.ui.buttonGroup({\n          className: 'note-list',\n          children: [outdent, indent]\n        })])]).render();\n      });\n      this.context.memo('button.height', function () {\n        return _this2.ui.buttonGroup([_this2.button({\n          className: 'dropdown-toggle',\n          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.textHeight), _this2.options),\n          tooltip: _this2.lang.font.height,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), _this2.ui.dropdownCheck({\n          items: _this2.options.lineHeights,\n          checkClassName: _this2.options.icons.menuCheck,\n          className: 'dropdown-line-height',\n          title: _this2.lang.font.height,\n          click: _this2.context.createInvokeHandler('editor.lineHeight')\n        })]).render();\n      });\n      this.context.memo('button.table', function () {\n        return _this2.ui.buttonGroup([_this2.button({\n          className: 'dropdown-toggle',\n          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.table), _this2.options),\n          tooltip: _this2.lang.table.table,\n          data: {\n            toggle: 'dropdown'\n          }\n        }), _this2.ui.dropdown({\n          title: _this2.lang.table.table,\n          className: 'note-table',\n          items: ['<div class=\"note-dimension-picker\">', '<div class=\"note-dimension-picker-mousecatcher\" data-event=\"insertTable\" data-value=\"1x1\"></div>', '<div class=\"note-dimension-picker-highlighted\"></div>', '<div class=\"note-dimension-picker-unhighlighted\"></div>', '</div>', '<div class=\"note-dimension-display\">1 x 1</div>'].join('')\n        })], {\n          callback: function callback($node) {\n            var $catcher = $node.find('.note-dimension-picker-mousecatcher');\n            $catcher.css({\n              width: _this2.options.insertTableMaxSize.col + 'em',\n              height: _this2.options.insertTableMaxSize.row + 'em'\n            }).mousedown(_this2.context.createInvokeHandler('editor.insertTable')).on('mousemove', _this2.tableMoveHandler.bind(_this2));\n          }\n        }).render();\n      });\n      this.context.memo('button.link', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.link),\n          tooltip: _this2.lang.link.link + _this2.representShortcut('linkDialog.show'),\n          click: _this2.context.createInvokeHandler('linkDialog.show')\n        }).render();\n      });\n      this.context.memo('button.picture', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.picture),\n          tooltip: _this2.lang.image.image,\n          click: _this2.context.createInvokeHandler('imageDialog.show')\n        }).render();\n      });\n      this.context.memo('button.video', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.video),\n          tooltip: _this2.lang.video.video,\n          click: _this2.context.createInvokeHandler('videoDialog.show')\n        }).render();\n      });\n      this.context.memo('button.hr', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.minus),\n          tooltip: _this2.lang.hr.insert + _this2.representShortcut('insertHorizontalRule'),\n          click: _this2.context.createInvokeHandler('editor.insertHorizontalRule')\n        }).render();\n      });\n      this.context.memo('button.fullscreen', function () {\n        return _this2.button({\n          className: 'btn-fullscreen note-codeview-keep',\n          contents: _this2.ui.icon(_this2.options.icons.arrowsAlt),\n          tooltip: _this2.lang.options.fullscreen,\n          click: _this2.context.createInvokeHandler('fullscreen.toggle')\n        }).render();\n      });\n      this.context.memo('button.codeview', function () {\n        return _this2.button({\n          className: 'btn-codeview note-codeview-keep',\n          contents: _this2.ui.icon(_this2.options.icons.code),\n          tooltip: _this2.lang.options.codeview,\n          click: _this2.context.createInvokeHandler('codeview.toggle')\n        }).render();\n      });\n      this.context.memo('button.redo', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.redo),\n          tooltip: _this2.lang.history.redo + _this2.representShortcut('redo'),\n          click: _this2.context.createInvokeHandler('editor.redo')\n        }).render();\n      });\n      this.context.memo('button.undo', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.undo),\n          tooltip: _this2.lang.history.undo + _this2.representShortcut('undo'),\n          click: _this2.context.createInvokeHandler('editor.undo')\n        }).render();\n      });\n      this.context.memo('button.help', function () {\n        return _this2.button({\n          contents: _this2.ui.icon(_this2.options.icons.question),\n          tooltip: _this2.lang.options.help,\n          click: _this2.context.createInvokeHandler('helpDialog.show')\n        }).render();\n      });\n    }\n    /**\n     * image: [\n     *   ['imageResize', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']],\n     *   ['float', ['floatLeft', 'floatRight', 'floatNone']],\n     *   ['remove', ['removeMedia']],\n     * ],\n     */\n\n  }, {\n    key: \"addImagePopoverButtons\",\n    value: function addImagePopoverButtons() {\n      var _this3 = this;\n\n      // Image Size Buttons\n      this.context.memo('button.resizeFull', function () {\n        return _this3.button({\n          contents: '<span class=\"note-fontsize-10\">100%</span>',\n          tooltip: _this3.lang.image.resizeFull,\n          click: _this3.context.createInvokeHandler('editor.resize', '1')\n        }).render();\n      });\n      this.context.memo('button.resizeHalf', function () {\n        return _this3.button({\n          contents: '<span class=\"note-fontsize-10\">50%</span>',\n          tooltip: _this3.lang.image.resizeHalf,\n          click: _this3.context.createInvokeHandler('editor.resize', '0.5')\n        }).render();\n      });\n      this.context.memo('button.resizeQuarter', function () {\n        return _this3.button({\n          contents: '<span class=\"note-fontsize-10\">25%</span>',\n          tooltip: _this3.lang.image.resizeQuarter,\n          click: _this3.context.createInvokeHandler('editor.resize', '0.25')\n        }).render();\n      });\n      this.context.memo('button.resizeNone', function () {\n        return _this3.button({\n          contents: _this3.ui.icon(_this3.options.icons.rollback),\n          tooltip: _this3.lang.image.resizeNone,\n          click: _this3.context.createInvokeHandler('editor.resize', '0')\n        }).render();\n      }); // Float Buttons\n\n      this.context.memo('button.floatLeft', function () {\n        return _this3.button({\n          contents: _this3.ui.icon(_this3.options.icons.floatLeft),\n          tooltip: _this3.lang.image.floatLeft,\n          click: _this3.context.createInvokeHandler('editor.floatMe', 'left')\n        }).render();\n      });\n      this.context.memo('button.floatRight', function () {\n        return _this3.button({\n          contents: _this3.ui.icon(_this3.options.icons.floatRight),\n          tooltip: _this3.lang.image.floatRight,\n          click: _this3.context.createInvokeHandler('editor.floatMe', 'right')\n        }).render();\n      });\n      this.context.memo('button.floatNone', function () {\n        return _this3.button({\n          contents: _this3.ui.icon(_this3.options.icons.rollback),\n          tooltip: _this3.lang.image.floatNone,\n          click: _this3.context.createInvokeHandler('editor.floatMe', 'none')\n        }).render();\n      }); // Remove Buttons\n\n      this.context.memo('button.removeMedia', function () {\n        return _this3.button({\n          contents: _this3.ui.icon(_this3.options.icons.trash),\n          tooltip: _this3.lang.image.remove,\n          click: _this3.context.createInvokeHandler('editor.removeMedia')\n        }).render();\n      });\n    }\n  }, {\n    key: \"addLinkPopoverButtons\",\n    value: function addLinkPopoverButtons() {\n      var _this4 = this;\n\n      this.context.memo('button.linkDialogShow', function () {\n        return _this4.button({\n          contents: _this4.ui.icon(_this4.options.icons.link),\n          tooltip: _this4.lang.link.edit,\n          click: _this4.context.createInvokeHandler('linkDialog.show')\n        }).render();\n      });\n      this.context.memo('button.unlink', function () {\n        return _this4.button({\n          contents: _this4.ui.icon(_this4.options.icons.unlink),\n          tooltip: _this4.lang.link.unlink,\n          click: _this4.context.createInvokeHandler('editor.unlink')\n        }).render();\n      });\n    }\n    /**\n     * table : [\n     *  ['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']],\n     *  ['delete', ['deleteRow', 'deleteCol', 'deleteTable']]\n     * ],\n     */\n\n  }, {\n    key: \"addTablePopoverButtons\",\n    value: function addTablePopoverButtons() {\n      var _this5 = this;\n\n      this.context.memo('button.addRowUp', function () {\n        return _this5.button({\n          className: 'btn-md',\n          contents: _this5.ui.icon(_this5.options.icons.rowAbove),\n          tooltip: _this5.lang.table.addRowAbove,\n          click: _this5.context.createInvokeHandler('editor.addRow', 'top')\n        }).render();\n      });\n      this.context.memo('button.addRowDown', function () {\n        return _this5.button({\n          className: 'btn-md',\n          contents: _this5.ui.icon(_this5.options.icons.rowBelow),\n          tooltip: _this5.lang.table.addRowBelow,\n          click: _this5.context.createInvokeHandler('editor.addRow', 'bottom')\n        }).render();\n      });\n      this.context.memo('button.addColLeft', function () {\n        return _this5.button({\n          className: 'btn-md',\n          contents: _this5.ui.icon(_this5.options.icons.colBefore),\n          tooltip: _this5.lang.table.addColLeft,\n          click: _this5.context.createInvokeHandler('editor.addCol', 'left')\n        }).render();\n      });\n      this.context.memo('button.addColRight', function () {\n        return _this5.button({\n          className: 'btn-md',\n          contents: _this5.ui.icon(_this5.options.icons.colAfter),\n          tooltip: _this5.lang.table.addColRight,\n          click: _this5.context.createInvokeHandler('editor.addCol', 'right')\n        }).render();\n      });\n      this.context.memo('button.deleteRow', function () {\n        return _this5.button({\n          className: 'btn-md',\n          contents: _this5.ui.icon(_this5.options.icons.rowRemove),\n          tooltip: _this5.lang.table.delRow,\n          click: _this5.context.createInvokeHandler('editor.deleteRow')\n        }).render();\n      });\n      this.context.memo('button.deleteCol', function () {\n        return _this5.button({\n          className: 'btn-md',\n          contents: _this5.ui.icon(_this5.options.icons.colRemove),\n          tooltip: _this5.lang.table.delCol,\n          click: _this5.context.createInvokeHandler('editor.deleteCol')\n        }).render();\n      });\n      this.context.memo('button.deleteTable', function () {\n        return _this5.button({\n          className: 'btn-md',\n          contents: _this5.ui.icon(_this5.options.icons.trash),\n          tooltip: _this5.lang.table.delTable,\n          click: _this5.context.createInvokeHandler('editor.deleteTable')\n        }).render();\n      });\n    }\n  }, {\n    key: \"build\",\n    value: function build($container, groups) {\n      for (var groupIdx = 0, groupLen = groups.length; groupIdx < groupLen; groupIdx++) {\n        var group = groups[groupIdx];\n        var groupName = Array.isArray(group) ? group[0] : group;\n        var buttons = Array.isArray(group) ? group.length === 1 ? [group[0]] : group[1] : [group];\n        var $group = this.ui.buttonGroup({\n          className: 'note-' + groupName\n        }).render();\n\n        for (var idx = 0, len = buttons.length; idx < len; idx++) {\n          var btn = this.context.memo('button.' + buttons[idx]);\n\n          if (btn) {\n            $group.append(typeof btn === 'function' ? btn(this.context) : btn);\n          }\n        }\n\n        $group.appendTo($container);\n      }\n    }\n    /**\n     * @param {jQuery} [$container]\n     */\n\n  }, {\n    key: \"updateCurrentStyle\",\n    value: function updateCurrentStyle($container) {\n      var _this6 = this;\n\n      var $cont = $container || this.$toolbar;\n      var styleInfo = this.context.invoke('editor.currentStyle');\n      this.updateBtnStates($cont, {\n        '.note-btn-bold': function noteBtnBold() {\n          return styleInfo['font-bold'] === 'bold';\n        },\n        '.note-btn-italic': function noteBtnItalic() {\n          return styleInfo['font-italic'] === 'italic';\n        },\n        '.note-btn-underline': function noteBtnUnderline() {\n          return styleInfo['font-underline'] === 'underline';\n        },\n        '.note-btn-subscript': function noteBtnSubscript() {\n          return styleInfo['font-subscript'] === 'subscript';\n        },\n        '.note-btn-superscript': function noteBtnSuperscript() {\n          return styleInfo['font-superscript'] === 'superscript';\n        },\n        '.note-btn-strikethrough': function noteBtnStrikethrough() {\n          return styleInfo['font-strikethrough'] === 'strikethrough';\n        }\n      });\n\n      if (styleInfo['font-family']) {\n        var fontNames = styleInfo['font-family'].split(',').map(function (name) {\n          return name.replace(/[\\'\\\"]/g, '').replace(/\\s+$/, '').replace(/^\\s+/, '');\n        });\n        var fontName = lists.find(fontNames, this.isFontInstalled.bind(this));\n        $cont.find('.dropdown-fontname a').each(function (idx, item) {\n          var $item = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(item); // always compare string to avoid creating another func.\n\n          var isChecked = $item.data('value') + '' === fontName + '';\n          $item.toggleClass('checked', isChecked);\n        });\n        $cont.find('.note-current-fontname').text(fontName).css('font-family', fontName);\n      }\n\n      if (styleInfo['font-size']) {\n        var fontSize = styleInfo['font-size'];\n        $cont.find('.dropdown-fontsize a').each(function (idx, item) {\n          var $item = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(item); // always compare with string to avoid creating another func.\n\n          var isChecked = $item.data('value') + '' === fontSize + '';\n          $item.toggleClass('checked', isChecked);\n        });\n        $cont.find('.note-current-fontsize').text(fontSize);\n        var fontSizeUnit = styleInfo['font-size-unit'];\n        $cont.find('.dropdown-fontsizeunit a').each(function (idx, item) {\n          var $item = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(item);\n          var isChecked = $item.data('value') + '' === fontSizeUnit + '';\n          $item.toggleClass('checked', isChecked);\n        });\n        $cont.find('.note-current-fontsizeunit').text(fontSizeUnit);\n      }\n\n      if (styleInfo['line-height']) {\n        var lineHeight = styleInfo['line-height'];\n        $cont.find('.dropdown-line-height li a').each(function (idx, item) {\n          // always compare with string to avoid creating another func.\n          var isChecked = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(item).data('value') + '' === lineHeight + '';\n          _this6.className = isChecked ? 'checked' : '';\n        });\n      }\n    }\n  }, {\n    key: \"updateBtnStates\",\n    value: function updateBtnStates($container, infos) {\n      var _this7 = this;\n\n      external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.each(infos, function (selector, pred) {\n        _this7.ui.toggleBtnActive($container.find(selector), pred());\n      });\n    }\n  }, {\n    key: \"tableMoveHandler\",\n    value: function tableMoveHandler(event) {\n      var PX_PER_EM = 18;\n      var $picker = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(event.target.parentNode); // target is mousecatcher\n\n      var $dimensionDisplay = $picker.next();\n      var $catcher = $picker.find('.note-dimension-picker-mousecatcher');\n      var $highlighted = $picker.find('.note-dimension-picker-highlighted');\n      var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');\n      var posOffset; // HTML5 with jQuery - e.offsetX is undefined in Firefox\n\n      if (event.offsetX === undefined) {\n        var posCatcher = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(event.target).offset();\n        posOffset = {\n          x: event.pageX - posCatcher.left,\n          y: event.pageY - posCatcher.top\n        };\n      } else {\n        posOffset = {\n          x: event.offsetX,\n          y: event.offsetY\n        };\n      }\n\n      var dim = {\n        c: Math.ceil(posOffset.x / PX_PER_EM) || 1,\n        r: Math.ceil(posOffset.y / PX_PER_EM) || 1\n      };\n      $highlighted.css({\n        width: dim.c + 'em',\n        height: dim.r + 'em'\n      });\n      $catcher.data('value', dim.c + 'x' + dim.r);\n\n      if (dim.c > 3 && dim.c < this.options.insertTableMaxSize.col) {\n        $unhighlighted.css({\n          width: dim.c + 1 + 'em'\n        });\n      }\n\n      if (dim.r > 3 && dim.r < this.options.insertTableMaxSize.row) {\n        $unhighlighted.css({\n          height: dim.r + 1 + 'em'\n        });\n      }\n\n      $dimensionDisplay.html(dim.c + ' x ' + dim.r);\n    }\n  }]);\n\n  return Buttons;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/Toolbar.js\nfunction Toolbar_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction Toolbar_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction Toolbar_createClass(Constructor, protoProps, staticProps) { if (protoProps) Toolbar_defineProperties(Constructor.prototype, protoProps); if (staticProps) Toolbar_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar Toolbar_Toolbar = /*#__PURE__*/function () {\n  function Toolbar(context) {\n    Toolbar_classCallCheck(this, Toolbar);\n\n    this.context = context;\n    this.$window = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(window);\n    this.$document = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document);\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.$note = context.layoutInfo.note;\n    this.$editor = context.layoutInfo.editor;\n    this.$toolbar = context.layoutInfo.toolbar;\n    this.$editable = context.layoutInfo.editable;\n    this.$statusbar = context.layoutInfo.statusbar;\n    this.options = context.options;\n    this.isFollowing = false;\n    this.followScroll = this.followScroll.bind(this);\n  }\n\n  Toolbar_createClass(Toolbar, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return !this.options.airMode;\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      var _this = this;\n\n      this.options.toolbar = this.options.toolbar || [];\n\n      if (!this.options.toolbar.length) {\n        this.$toolbar.hide();\n      } else {\n        this.context.invoke('buttons.build', this.$toolbar, this.options.toolbar);\n      }\n\n      if (this.options.toolbarContainer) {\n        this.$toolbar.appendTo(this.options.toolbarContainer);\n      }\n\n      this.changeContainer(false);\n      this.$note.on('summernote.keyup summernote.mouseup summernote.change', function () {\n        _this.context.invoke('buttons.updateCurrentStyle');\n      });\n      this.context.invoke('buttons.updateCurrentStyle');\n\n      if (this.options.followingToolbar) {\n        this.$window.on('scroll resize', this.followScroll);\n      }\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$toolbar.children().remove();\n\n      if (this.options.followingToolbar) {\n        this.$window.off('scroll resize', this.followScroll);\n      }\n    }\n  }, {\n    key: \"followScroll\",\n    value: function followScroll() {\n      if (this.$editor.hasClass('fullscreen')) {\n        return false;\n      }\n\n      var editorHeight = this.$editor.outerHeight();\n      var editorWidth = this.$editor.width();\n      var toolbarHeight = this.$toolbar.height();\n      var statusbarHeight = this.$statusbar.height(); // check if the web app is currently using another static bar\n\n      var otherBarHeight = 0;\n\n      if (this.options.otherStaticBar) {\n        otherBarHeight = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this.options.otherStaticBar).outerHeight();\n      }\n\n      var currentOffset = this.$document.scrollTop();\n      var editorOffsetTop = this.$editor.offset().top;\n      var editorOffsetBottom = editorOffsetTop + editorHeight;\n      var activateOffset = editorOffsetTop - otherBarHeight;\n      var deactivateOffsetBottom = editorOffsetBottom - otherBarHeight - toolbarHeight - statusbarHeight;\n\n      if (!this.isFollowing && currentOffset > activateOffset && currentOffset < deactivateOffsetBottom - toolbarHeight) {\n        this.isFollowing = true;\n        this.$editable.css({\n          marginTop: this.$toolbar.outerHeight()\n        });\n        this.$toolbar.css({\n          position: 'fixed',\n          top: otherBarHeight,\n          width: editorWidth,\n          zIndex: 1000\n        });\n      } else if (this.isFollowing && (currentOffset < activateOffset || currentOffset > deactivateOffsetBottom)) {\n        this.isFollowing = false;\n        this.$toolbar.css({\n          position: 'relative',\n          top: 0,\n          width: '100%',\n          zIndex: 'auto'\n        });\n        this.$editable.css({\n          marginTop: ''\n        });\n      }\n    }\n  }, {\n    key: \"changeContainer\",\n    value: function changeContainer(isFullscreen) {\n      if (isFullscreen) {\n        this.$toolbar.prependTo(this.$editor);\n      } else {\n        if (this.options.toolbarContainer) {\n          this.$toolbar.appendTo(this.options.toolbarContainer);\n        }\n      }\n\n      if (this.options.followingToolbar) {\n        this.followScroll();\n      }\n    }\n  }, {\n    key: \"updateFullscreen\",\n    value: function updateFullscreen(isFullscreen) {\n      this.ui.toggleBtnActive(this.$toolbar.find('.btn-fullscreen'), isFullscreen);\n      this.changeContainer(isFullscreen);\n    }\n  }, {\n    key: \"updateCodeview\",\n    value: function updateCodeview(isCodeview) {\n      this.ui.toggleBtnActive(this.$toolbar.find('.btn-codeview'), isCodeview);\n\n      if (isCodeview) {\n        this.deactivate();\n      } else {\n        this.activate();\n      }\n    }\n  }, {\n    key: \"activate\",\n    value: function activate(isIncludeCodeview) {\n      var $btn = this.$toolbar.find('button');\n\n      if (!isIncludeCodeview) {\n        $btn = $btn.not('.note-codeview-keep');\n      }\n\n      this.ui.toggleBtn($btn, true);\n    }\n  }, {\n    key: \"deactivate\",\n    value: function deactivate(isIncludeCodeview) {\n      var $btn = this.$toolbar.find('button');\n\n      if (!isIncludeCodeview) {\n        $btn = $btn.not('.note-codeview-keep');\n      }\n\n      this.ui.toggleBtn($btn, false);\n    }\n  }]);\n\n  return Toolbar;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/LinkDialog.js\nfunction LinkDialog_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction LinkDialog_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction LinkDialog_createClass(Constructor, protoProps, staticProps) { if (protoProps) LinkDialog_defineProperties(Constructor.prototype, protoProps); if (staticProps) LinkDialog_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\nvar LinkDialog_LinkDialog = /*#__PURE__*/function () {\n  function LinkDialog(context) {\n    LinkDialog_classCallCheck(this, LinkDialog);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.$body = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document.body);\n    this.$editor = context.layoutInfo.editor;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n    context.memo('help.linkDialog.show', this.options.langInfo.help['linkDialog.show']);\n  }\n\n  LinkDialog_createClass(LinkDialog, [{\n    key: \"initialize\",\n    value: function initialize() {\n      var $container = this.options.dialogsInBody ? this.$body : this.options.container;\n      var body = ['<div class=\"form-group note-form-group\">', \"<label for=\\\"note-dialog-link-txt-\".concat(this.options.id, \"\\\" class=\\\"note-form-label\\\">\").concat(this.lang.link.textToDisplay, \"</label>\"), \"<input id=\\\"note-dialog-link-txt-\".concat(this.options.id, \"\\\" class=\\\"note-link-text form-control note-form-control note-input\\\" type=\\\"text\\\"/>\"), '</div>', '<div class=\"form-group note-form-group\">', \"<label for=\\\"note-dialog-link-url-\".concat(this.options.id, \"\\\" class=\\\"note-form-label\\\">\").concat(this.lang.link.url, \"</label>\"), \"<input id=\\\"note-dialog-link-url-\".concat(this.options.id, \"\\\" class=\\\"note-link-url form-control note-form-control note-input\\\" type=\\\"text\\\" value=\\\"http://\\\"/>\"), '</div>', !this.options.disableLinkTarget ? external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div/>').append(this.ui.checkbox({\n        className: 'sn-checkbox-open-in-new-window',\n        text: this.lang.link.openInNewWindow,\n        checked: true\n      }).render()).html() : '', external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div/>').append(this.ui.checkbox({\n        className: 'sn-checkbox-use-protocol',\n        text: this.lang.link.useProtocol,\n        checked: true\n      }).render()).html()].join('');\n      var buttonClass = 'btn btn-primary note-btn note-btn-primary note-link-btn';\n      var footer = \"<input type=\\\"button\\\" href=\\\"#\\\" class=\\\"\".concat(buttonClass, \"\\\" value=\\\"\").concat(this.lang.link.insert, \"\\\" disabled>\");\n      this.$dialog = this.ui.dialog({\n        className: 'link-dialog',\n        title: this.lang.link.insert,\n        fade: this.options.dialogsFade,\n        body: body,\n        footer: footer\n      }).render().appendTo($container);\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.ui.hideDialog(this.$dialog);\n      this.$dialog.remove();\n    }\n  }, {\n    key: \"bindEnterKey\",\n    value: function bindEnterKey($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === core_key.code.ENTER) {\n          event.preventDefault();\n          $btn.trigger('click');\n        }\n      });\n    }\n    /**\n     * toggle update button\n     */\n\n  }, {\n    key: \"toggleLinkBtn\",\n    value: function toggleLinkBtn($linkBtn, $linkText, $linkUrl) {\n      this.ui.toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());\n    }\n    /**\n     * Show link dialog and set event handlers on dialog controls.\n     *\n     * @param {Object} linkInfo\n     * @return {Promise}\n     */\n\n  }, {\n    key: \"showLinkDialog\",\n    value: function showLinkDialog(linkInfo) {\n      var _this = this;\n\n      return external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.Deferred(function (deferred) {\n        var $linkText = _this.$dialog.find('.note-link-text');\n\n        var $linkUrl = _this.$dialog.find('.note-link-url');\n\n        var $linkBtn = _this.$dialog.find('.note-link-btn');\n\n        var $openInNewWindow = _this.$dialog.find('.sn-checkbox-open-in-new-window input[type=checkbox]');\n\n        var $useProtocol = _this.$dialog.find('.sn-checkbox-use-protocol input[type=checkbox]');\n\n        _this.ui.onDialogShown(_this.$dialog, function () {\n          _this.context.triggerEvent('dialog.shown'); // If no url was given and given text is valid URL then copy that into URL Field\n\n\n          if (!linkInfo.url && func.isValidUrl(linkInfo.text)) {\n            linkInfo.url = linkInfo.text;\n          }\n\n          $linkText.on('input paste propertychange', function () {\n            // If linktext was modified by input events,\n            // cloning text from linkUrl will be stopped.\n            linkInfo.text = $linkText.val();\n\n            _this.toggleLinkBtn($linkBtn, $linkText, $linkUrl);\n          }).val(linkInfo.text);\n          $linkUrl.on('input paste propertychange', function () {\n            // Display same text on `Text to display` as default\n            // when linktext has no text\n            if (!linkInfo.text) {\n              $linkText.val($linkUrl.val());\n            }\n\n            _this.toggleLinkBtn($linkBtn, $linkText, $linkUrl);\n          }).val(linkInfo.url);\n\n          if (!env.isSupportTouch) {\n            $linkUrl.trigger('focus');\n          }\n\n          _this.toggleLinkBtn($linkBtn, $linkText, $linkUrl);\n\n          _this.bindEnterKey($linkUrl, $linkBtn);\n\n          _this.bindEnterKey($linkText, $linkBtn);\n\n          var isNewWindowChecked = linkInfo.isNewWindow !== undefined ? linkInfo.isNewWindow : _this.context.options.linkTargetBlank;\n          $openInNewWindow.prop('checked', isNewWindowChecked);\n          var useProtocolChecked = linkInfo.url ? false : _this.context.options.useProtocol;\n          $useProtocol.prop('checked', useProtocolChecked);\n          $linkBtn.one('click', function (event) {\n            event.preventDefault();\n            deferred.resolve({\n              range: linkInfo.range,\n              url: $linkUrl.val(),\n              text: $linkText.val(),\n              isNewWindow: $openInNewWindow.is(':checked'),\n              checkProtocol: $useProtocol.is(':checked')\n            });\n\n            _this.ui.hideDialog(_this.$dialog);\n          });\n        });\n\n        _this.ui.onDialogHidden(_this.$dialog, function () {\n          // detach events\n          $linkText.off();\n          $linkUrl.off();\n          $linkBtn.off();\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        });\n\n        _this.ui.showDialog(_this.$dialog);\n      }).promise();\n    }\n    /**\n     * @param {Object} layoutInfo\n     */\n\n  }, {\n    key: \"show\",\n    value: function show() {\n      var _this2 = this;\n\n      var linkInfo = this.context.invoke('editor.getLinkInfo');\n      this.context.invoke('editor.saveRange');\n      this.showLinkDialog(linkInfo).then(function (linkInfo) {\n        _this2.context.invoke('editor.restoreRange');\n\n        _this2.context.invoke('editor.createLink', linkInfo);\n      }).fail(function () {\n        _this2.context.invoke('editor.restoreRange');\n      });\n    }\n  }]);\n\n  return LinkDialog;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/LinkPopover.js\nfunction LinkPopover_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction LinkPopover_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction LinkPopover_createClass(Constructor, protoProps, staticProps) { if (protoProps) LinkPopover_defineProperties(Constructor.prototype, protoProps); if (staticProps) LinkPopover_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\nvar LinkPopover_LinkPopover = /*#__PURE__*/function () {\n  function LinkPopover(context) {\n    var _this = this;\n\n    LinkPopover_classCallCheck(this, LinkPopover);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.options = context.options;\n    this.events = {\n      'summernote.keyup summernote.mouseup summernote.change summernote.scroll': function summernoteKeyupSummernoteMouseupSummernoteChangeSummernoteScroll() {\n        _this.update();\n      },\n      'summernote.disable summernote.dialog.shown summernote.blur': function summernoteDisableSummernoteDialogShownSummernoteBlur() {\n        _this.hide();\n      }\n    };\n  }\n\n  LinkPopover_createClass(LinkPopover, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return !lists.isEmpty(this.options.popover.link);\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      this.$popover = this.ui.popover({\n        className: 'note-link-popover',\n        callback: function callback($node) {\n          var $content = $node.find('.popover-content,.note-popover-content');\n          $content.prepend('<span><a target=\"_blank\"></a>&nbsp;</span>');\n        }\n      }).render().appendTo(this.options.container);\n      var $content = this.$popover.find('.popover-content,.note-popover-content');\n      this.context.invoke('buttons.build', $content, this.options.popover.link);\n      this.$popover.on('mousedown', function (e) {\n        e.preventDefault();\n      });\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$popover.remove();\n    }\n  }, {\n    key: \"update\",\n    value: function update() {\n      // Prevent focusing on editable when invoke('code') is executed\n      if (!this.context.invoke('editor.hasFocus')) {\n        this.hide();\n        return;\n      }\n\n      var rng = this.context.invoke('editor.getLastRange');\n\n      if (rng.isCollapsed() && rng.isOnAnchor()) {\n        var anchor = dom.ancestor(rng.sc, dom.isAnchor);\n        var href = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(anchor).attr('href');\n        this.$popover.find('a').attr('href', href).text(href);\n        var pos = dom.posFromPlaceholder(anchor);\n        var containerOffset = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this.options.container).offset();\n        pos.top -= containerOffset.top;\n        pos.left -= containerOffset.left;\n        this.$popover.css({\n          display: 'block',\n          left: pos.left,\n          top: pos.top\n        });\n      } else {\n        this.hide();\n      }\n    }\n  }, {\n    key: \"hide\",\n    value: function hide() {\n      this.$popover.hide();\n    }\n  }]);\n\n  return LinkPopover;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/ImageDialog.js\nfunction ImageDialog_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction ImageDialog_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction ImageDialog_createClass(Constructor, protoProps, staticProps) { if (protoProps) ImageDialog_defineProperties(Constructor.prototype, protoProps); if (staticProps) ImageDialog_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\nvar ImageDialog_ImageDialog = /*#__PURE__*/function () {\n  function ImageDialog(context) {\n    ImageDialog_classCallCheck(this, ImageDialog);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.$body = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document.body);\n    this.$editor = context.layoutInfo.editor;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n  }\n\n  ImageDialog_createClass(ImageDialog, [{\n    key: \"initialize\",\n    value: function initialize() {\n      var imageLimitation = '';\n\n      if (this.options.maximumImageFileSize) {\n        var unit = Math.floor(Math.log(this.options.maximumImageFileSize) / Math.log(1024));\n        var readableSize = (this.options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 + ' ' + ' KMGTP'[unit] + 'B';\n        imageLimitation = \"<small>\".concat(this.lang.image.maximumFileSize + ' : ' + readableSize, \"</small>\");\n      }\n\n      var $container = this.options.dialogsInBody ? this.$body : this.options.container;\n      var body = ['<div class=\"form-group note-form-group note-group-select-from-files\">', '<label for=\"note-dialog-image-file-' + this.options.id + '\" class=\"note-form-label\">' + this.lang.image.selectFromFiles + '</label>', '<input id=\"note-dialog-image-file-' + this.options.id + '\" class=\"note-image-input form-control-file note-form-control note-input\" ', ' type=\"file\" name=\"files\" accept=\"image/*\" multiple=\"multiple\"/>', imageLimitation, '</div>', '<div class=\"form-group note-group-image-url\">', '<label for=\"note-dialog-image-url-' + this.options.id + '\" class=\"note-form-label\">' + this.lang.image.url + '</label>', '<input id=\"note-dialog-image-url-' + this.options.id + '\" class=\"note-image-url form-control note-form-control note-input\" type=\"text\"/>', '</div>'].join('');\n      var buttonClass = 'btn btn-primary note-btn note-btn-primary note-image-btn';\n      var footer = \"<input type=\\\"button\\\" href=\\\"#\\\" class=\\\"\".concat(buttonClass, \"\\\" value=\\\"\").concat(this.lang.image.insert, \"\\\" disabled>\");\n      this.$dialog = this.ui.dialog({\n        title: this.lang.image.insert,\n        fade: this.options.dialogsFade,\n        body: body,\n        footer: footer\n      }).render().appendTo($container);\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.ui.hideDialog(this.$dialog);\n      this.$dialog.remove();\n    }\n  }, {\n    key: \"bindEnterKey\",\n    value: function bindEnterKey($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === core_key.code.ENTER) {\n          event.preventDefault();\n          $btn.trigger('click');\n        }\n      });\n    }\n  }, {\n    key: \"show\",\n    value: function show() {\n      var _this = this;\n\n      this.context.invoke('editor.saveRange');\n      this.showImageDialog().then(function (data) {\n        // [workaround] hide dialog before restore range for IE range focus\n        _this.ui.hideDialog(_this.$dialog);\n\n        _this.context.invoke('editor.restoreRange');\n\n        if (typeof data === 'string') {\n          // image url\n          // If onImageLinkInsert set,\n          if (_this.options.callbacks.onImageLinkInsert) {\n            _this.context.triggerEvent('image.link.insert', data);\n          } else {\n            _this.context.invoke('editor.insertImage', data);\n          }\n        } else {\n          // array of files\n          _this.context.invoke('editor.insertImagesOrCallback', data);\n        }\n      }).fail(function () {\n        _this.context.invoke('editor.restoreRange');\n      });\n    }\n    /**\n     * show image dialog\n     *\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n\n  }, {\n    key: \"showImageDialog\",\n    value: function showImageDialog() {\n      var _this2 = this;\n\n      return external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.Deferred(function (deferred) {\n        var $imageInput = _this2.$dialog.find('.note-image-input');\n\n        var $imageUrl = _this2.$dialog.find('.note-image-url');\n\n        var $imageBtn = _this2.$dialog.find('.note-image-btn');\n\n        _this2.ui.onDialogShown(_this2.$dialog, function () {\n          _this2.context.triggerEvent('dialog.shown'); // Cloning imageInput to clear element.\n\n\n          $imageInput.replaceWith($imageInput.clone().on('change', function (event) {\n            deferred.resolve(event.target.files || event.target.value);\n          }).val(''));\n          $imageUrl.on('input paste propertychange', function () {\n            _this2.ui.toggleBtn($imageBtn, $imageUrl.val());\n          }).val('');\n\n          if (!env.isSupportTouch) {\n            $imageUrl.trigger('focus');\n          }\n\n          $imageBtn.click(function (event) {\n            event.preventDefault();\n            deferred.resolve($imageUrl.val());\n          });\n\n          _this2.bindEnterKey($imageUrl, $imageBtn);\n        });\n\n        _this2.ui.onDialogHidden(_this2.$dialog, function () {\n          $imageInput.off();\n          $imageUrl.off();\n          $imageBtn.off();\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        });\n\n        _this2.ui.showDialog(_this2.$dialog);\n      });\n    }\n  }]);\n\n  return ImageDialog;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/ImagePopover.js\nfunction ImagePopover_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction ImagePopover_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction ImagePopover_createClass(Constructor, protoProps, staticProps) { if (protoProps) ImagePopover_defineProperties(Constructor.prototype, protoProps); if (staticProps) ImagePopover_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n/**\n * Image popover module\n *  mouse events that show/hide popover will be handled by Handle.js.\n *  Handle.js will receive the events and invoke 'imagePopover.update'.\n */\n\nvar ImagePopover_ImagePopover = /*#__PURE__*/function () {\n  function ImagePopover(context) {\n    var _this = this;\n\n    ImagePopover_classCallCheck(this, ImagePopover);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.editable = context.layoutInfo.editable[0];\n    this.options = context.options;\n    this.events = {\n      'summernote.disable summernote.blur': function summernoteDisableSummernoteBlur() {\n        _this.hide();\n      }\n    };\n  }\n\n  ImagePopover_createClass(ImagePopover, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return !lists.isEmpty(this.options.popover.image);\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      this.$popover = this.ui.popover({\n        className: 'note-image-popover'\n      }).render().appendTo(this.options.container);\n      var $content = this.$popover.find('.popover-content,.note-popover-content');\n      this.context.invoke('buttons.build', $content, this.options.popover.image);\n      this.$popover.on('mousedown', function (e) {\n        e.preventDefault();\n      });\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$popover.remove();\n    }\n  }, {\n    key: \"update\",\n    value: function update(target, event) {\n      if (dom.isImg(target)) {\n        var position = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(target).offset();\n        var containerOffset = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this.options.container).offset();\n        var pos = {};\n\n        if (this.options.popatmouse) {\n          pos.left = event.pageX - 20;\n          pos.top = event.pageY;\n        } else {\n          pos = position;\n        }\n\n        pos.top -= containerOffset.top;\n        pos.left -= containerOffset.left;\n        this.$popover.css({\n          display: 'block',\n          left: pos.left,\n          top: pos.top\n        });\n      } else {\n        this.hide();\n      }\n    }\n  }, {\n    key: \"hide\",\n    value: function hide() {\n      this.$popover.hide();\n    }\n  }]);\n\n  return ImagePopover;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/TablePopover.js\nfunction TablePopover_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction TablePopover_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction TablePopover_createClass(Constructor, protoProps, staticProps) { if (protoProps) TablePopover_defineProperties(Constructor.prototype, protoProps); if (staticProps) TablePopover_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\nvar TablePopover_TablePopover = /*#__PURE__*/function () {\n  function TablePopover(context) {\n    var _this = this;\n\n    TablePopover_classCallCheck(this, TablePopover);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.options = context.options;\n    this.events = {\n      'summernote.mousedown': function summernoteMousedown(we, e) {\n        _this.update(e.target);\n      },\n      'summernote.keyup summernote.scroll summernote.change': function summernoteKeyupSummernoteScrollSummernoteChange() {\n        _this.update();\n      },\n      'summernote.disable summernote.blur': function summernoteDisableSummernoteBlur() {\n        _this.hide();\n      }\n    };\n  }\n\n  TablePopover_createClass(TablePopover, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return !lists.isEmpty(this.options.popover.table);\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      this.$popover = this.ui.popover({\n        className: 'note-table-popover'\n      }).render().appendTo(this.options.container);\n      var $content = this.$popover.find('.popover-content,.note-popover-content');\n      this.context.invoke('buttons.build', $content, this.options.popover.table); // [workaround] Disable Firefox's default table editor\n\n      if (env.isFF) {\n        document.execCommand('enableInlineTableEditing', false, false);\n      }\n\n      this.$popover.on('mousedown', function (e) {\n        e.preventDefault();\n      });\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$popover.remove();\n    }\n  }, {\n    key: \"update\",\n    value: function update(target) {\n      if (this.context.isDisabled()) {\n        return false;\n      }\n\n      var isCell = dom.isCell(target);\n\n      if (isCell) {\n        var pos = dom.posFromPlaceholder(target);\n        var containerOffset = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this.options.container).offset();\n        pos.top -= containerOffset.top;\n        pos.left -= containerOffset.left;\n        this.$popover.css({\n          display: 'block',\n          left: pos.left,\n          top: pos.top\n        });\n      } else {\n        this.hide();\n      }\n\n      return isCell;\n    }\n  }, {\n    key: \"hide\",\n    value: function hide() {\n      this.$popover.hide();\n    }\n  }]);\n\n  return TablePopover;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/VideoDialog.js\nfunction VideoDialog_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction VideoDialog_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction VideoDialog_createClass(Constructor, protoProps, staticProps) { if (protoProps) VideoDialog_defineProperties(Constructor.prototype, protoProps); if (staticProps) VideoDialog_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\nvar VideoDialog_VideoDialog = /*#__PURE__*/function () {\n  function VideoDialog(context) {\n    VideoDialog_classCallCheck(this, VideoDialog);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.$body = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document.body);\n    this.$editor = context.layoutInfo.editor;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n  }\n\n  VideoDialog_createClass(VideoDialog, [{\n    key: \"initialize\",\n    value: function initialize() {\n      var $container = this.options.dialogsInBody ? this.$body : this.options.container;\n      var body = ['<div class=\"form-group note-form-group row-fluid\">', \"<label for=\\\"note-dialog-video-url-\".concat(this.options.id, \"\\\" class=\\\"note-form-label\\\">\").concat(this.lang.video.url, \" <small class=\\\"text-muted\\\">\").concat(this.lang.video.providers, \"</small></label>\"), \"<input id=\\\"note-dialog-video-url-\".concat(this.options.id, \"\\\" class=\\\"note-video-url form-control note-form-control note-input\\\" type=\\\"text\\\"/>\"), '</div>'].join('');\n      var buttonClass = 'btn btn-primary note-btn note-btn-primary note-video-btn';\n      var footer = \"<input type=\\\"button\\\" href=\\\"#\\\" class=\\\"\".concat(buttonClass, \"\\\" value=\\\"\").concat(this.lang.video.insert, \"\\\" disabled>\");\n      this.$dialog = this.ui.dialog({\n        title: this.lang.video.insert,\n        fade: this.options.dialogsFade,\n        body: body,\n        footer: footer\n      }).render().appendTo($container);\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.ui.hideDialog(this.$dialog);\n      this.$dialog.remove();\n    }\n  }, {\n    key: \"bindEnterKey\",\n    value: function bindEnterKey($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === core_key.code.ENTER) {\n          event.preventDefault();\n          $btn.trigger('click');\n        }\n      });\n    }\n  }, {\n    key: \"createVideoNode\",\n    value: function createVideoNode(url) {\n      // video url patterns(youtube, instagram, vimeo, dailymotion, youku, mp4, ogg, webm)\n      var ytRegExp = /\\/\\/(?:(?:www|m)\\.)?(?:youtu\\.be\\/|youtube\\.com\\/(?:embed\\/|v\\/|watch\\?v=|watch\\?.+&v=))([\\w|-]{11})(?:(?:[\\?&]t=)(\\S+))?$/;\n      var ytRegExpForStart = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/;\n      var ytMatch = url.match(ytRegExp);\n      var igRegExp = /(?:www\\.|\\/\\/)instagram\\.com\\/p\\/(.[a-zA-Z0-9_-]*)/;\n      var igMatch = url.match(igRegExp);\n      var vRegExp = /\\/\\/vine\\.co\\/v\\/([a-zA-Z0-9]+)/;\n      var vMatch = url.match(vRegExp);\n      var vimRegExp = /\\/\\/(player\\.)?vimeo\\.com\\/([a-z]*\\/)*(\\d+)[?]?.*/;\n      var vimMatch = url.match(vimRegExp);\n      var dmRegExp = /.+dailymotion.com\\/(video|hub)\\/([^_]+)[^#]*(#video=([^_&]+))?/;\n      var dmMatch = url.match(dmRegExp);\n      var youkuRegExp = /\\/\\/v\\.youku\\.com\\/v_show\\/id_(\\w+)=*\\.html/;\n      var youkuMatch = url.match(youkuRegExp);\n      var qqRegExp = /\\/\\/v\\.qq\\.com.*?vid=(.+)/;\n      var qqMatch = url.match(qqRegExp);\n      var qqRegExp2 = /\\/\\/v\\.qq\\.com\\/x?\\/?(page|cover).*?\\/([^\\/]+)\\.html\\??.*/;\n      var qqMatch2 = url.match(qqRegExp2);\n      var mp4RegExp = /^.+.(mp4|m4v)$/;\n      var mp4Match = url.match(mp4RegExp);\n      var oggRegExp = /^.+.(ogg|ogv)$/;\n      var oggMatch = url.match(oggRegExp);\n      var webmRegExp = /^.+.(webm)$/;\n      var webmMatch = url.match(webmRegExp);\n      var fbRegExp = /(?:www\\.|\\/\\/)facebook\\.com\\/([^\\/]+)\\/videos\\/([0-9]+)/;\n      var fbMatch = url.match(fbRegExp);\n      var $video;\n\n      if (ytMatch && ytMatch[1].length === 11) {\n        var youtubeId = ytMatch[1];\n        var start = 0;\n\n        if (typeof ytMatch[2] !== 'undefined') {\n          var ytMatchForStart = ytMatch[2].match(ytRegExpForStart);\n\n          if (ytMatchForStart) {\n            for (var n = [3600, 60, 1], i = 0, r = n.length; i < r; i++) {\n              start += typeof ytMatchForStart[i + 1] !== 'undefined' ? n[i] * parseInt(ytMatchForStart[i + 1], 10) : 0;\n            }\n          }\n        }\n\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', '//www.youtube.com/embed/' + youtubeId + (start > 0 ? '?start=' + start : '')).attr('width', '640').attr('height', '360');\n      } else if (igMatch && igMatch[0].length) {\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', 'https://instagram.com/p/' + igMatch[1] + '/embed/').attr('width', '612').attr('height', '710').attr('scrolling', 'no').attr('allowtransparency', 'true');\n      } else if (vMatch && vMatch[0].length) {\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', vMatch[0] + '/embed/simple').attr('width', '600').attr('height', '600').attr('class', 'vine-embed');\n      } else if (vimMatch && vimMatch[3].length) {\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>').attr('frameborder', 0).attr('src', '//player.vimeo.com/video/' + vimMatch[3]).attr('width', '640').attr('height', '360');\n      } else if (dmMatch && dmMatch[2].length) {\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', '//www.dailymotion.com/embed/video/' + dmMatch[2]).attr('width', '640').attr('height', '360');\n      } else if (youkuMatch && youkuMatch[1].length) {\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>').attr('frameborder', 0).attr('height', '498').attr('width', '510').attr('src', '//player.youku.com/embed/' + youkuMatch[1]);\n      } else if (qqMatch && qqMatch[1].length || qqMatch2 && qqMatch2[2].length) {\n        var vid = qqMatch && qqMatch[1].length ? qqMatch[1] : qqMatch2[2];\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>').attr('frameborder', 0).attr('height', '310').attr('width', '500').attr('src', 'https://v.qq.com/txp/iframe/player.html?vid=' + vid + '&amp;auto=0');\n      } else if (mp4Match || oggMatch || webmMatch) {\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<video controls>').attr('src', url).attr('width', '640').attr('height', '360');\n      } else if (fbMatch && fbMatch[0].length) {\n        $video = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', 'https://www.facebook.com/plugins/video.php?href=' + encodeURIComponent(fbMatch[0]) + '&show_text=0&width=560').attr('width', '560').attr('height', '301').attr('scrolling', 'no').attr('allowtransparency', 'true');\n      } else {\n        // this is not a known video link. Now what, Cat? Now what?\n        return false;\n      }\n\n      $video.addClass('note-video-clip');\n      return $video[0];\n    }\n  }, {\n    key: \"show\",\n    value: function show() {\n      var _this = this;\n\n      var text = this.context.invoke('editor.getSelectedText');\n      this.context.invoke('editor.saveRange');\n      this.showVideoDialog(text).then(function (url) {\n        // [workaround] hide dialog before restore range for IE range focus\n        _this.ui.hideDialog(_this.$dialog);\n\n        _this.context.invoke('editor.restoreRange'); // build node\n\n\n        var $node = _this.createVideoNode(url);\n\n        if ($node) {\n          // insert video node\n          _this.context.invoke('editor.insertNode', $node);\n        }\n      }).fail(function () {\n        _this.context.invoke('editor.restoreRange');\n      });\n    }\n    /**\n     * show video dialog\n     *\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n\n  }, {\n    key: \"showVideoDialog\",\n    value: function showVideoDialog()\n    /* text */\n    {\n      var _this2 = this;\n\n      return external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.Deferred(function (deferred) {\n        var $videoUrl = _this2.$dialog.find('.note-video-url');\n\n        var $videoBtn = _this2.$dialog.find('.note-video-btn');\n\n        _this2.ui.onDialogShown(_this2.$dialog, function () {\n          _this2.context.triggerEvent('dialog.shown');\n\n          $videoUrl.on('input paste propertychange', function () {\n            _this2.ui.toggleBtn($videoBtn, $videoUrl.val());\n          });\n\n          if (!env.isSupportTouch) {\n            $videoUrl.trigger('focus');\n          }\n\n          $videoBtn.click(function (event) {\n            event.preventDefault();\n            deferred.resolve($videoUrl.val());\n          });\n\n          _this2.bindEnterKey($videoUrl, $videoBtn);\n        });\n\n        _this2.ui.onDialogHidden(_this2.$dialog, function () {\n          $videoUrl.off();\n          $videoBtn.off();\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        });\n\n        _this2.ui.showDialog(_this2.$dialog);\n      });\n    }\n  }]);\n\n  return VideoDialog;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/HelpDialog.js\nfunction HelpDialog_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction HelpDialog_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction HelpDialog_createClass(Constructor, protoProps, staticProps) { if (protoProps) HelpDialog_defineProperties(Constructor.prototype, protoProps); if (staticProps) HelpDialog_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\nvar HelpDialog_HelpDialog = /*#__PURE__*/function () {\n  function HelpDialog(context) {\n    HelpDialog_classCallCheck(this, HelpDialog);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.$body = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(document.body);\n    this.$editor = context.layoutInfo.editor;\n    this.options = context.options;\n    this.lang = this.options.langInfo;\n  }\n\n  HelpDialog_createClass(HelpDialog, [{\n    key: \"initialize\",\n    value: function initialize() {\n      var $container = this.options.dialogsInBody ? this.$body : this.options.container;\n      var body = ['<p class=\"text-center\">', '<a href=\"http://summernote.org/\" target=\"_blank\">Summernote 0.8.18</a> · ', '<a href=\"https://github.com/summernote/summernote\" target=\"_blank\">Project</a> · ', '<a href=\"https://github.com/summernote/summernote/issues\" target=\"_blank\">Issues</a>', '</p>'].join('');\n      this.$dialog = this.ui.dialog({\n        title: this.lang.options.help,\n        fade: this.options.dialogsFade,\n        body: this.createShortcutList(),\n        footer: body,\n        callback: function callback($node) {\n          $node.find('.modal-body,.note-modal-body').css({\n            'max-height': 300,\n            'overflow': 'scroll'\n          });\n        }\n      }).render().appendTo($container);\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.ui.hideDialog(this.$dialog);\n      this.$dialog.remove();\n    }\n  }, {\n    key: \"createShortcutList\",\n    value: function createShortcutList() {\n      var _this = this;\n\n      var keyMap = this.options.keyMap[env.isMac ? 'mac' : 'pc'];\n      return Object.keys(keyMap).map(function (key) {\n        var command = keyMap[key];\n        var $row = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div><div class=\"help-list-item\"></div></div>');\n        $row.append(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<label><kbd>' + key + '</kdb></label>').css({\n          'width': 180,\n          'margin-right': 10\n        })).append(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<span/>').html(_this.context.memo('help.' + command) || command));\n        return $row.html();\n      }).join('');\n    }\n    /**\n     * show help dialog\n     *\n     * @return {Promise}\n     */\n\n  }, {\n    key: \"showHelpDialog\",\n    value: function showHelpDialog() {\n      var _this2 = this;\n\n      return external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.Deferred(function (deferred) {\n        _this2.ui.onDialogShown(_this2.$dialog, function () {\n          _this2.context.triggerEvent('dialog.shown');\n\n          deferred.resolve();\n        });\n\n        _this2.ui.showDialog(_this2.$dialog);\n      }).promise();\n    }\n  }, {\n    key: \"show\",\n    value: function show() {\n      var _this3 = this;\n\n      this.context.invoke('editor.saveRange');\n      this.showHelpDialog().then(function () {\n        _this3.context.invoke('editor.restoreRange');\n      });\n    }\n  }]);\n\n  return HelpDialog;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/AirPopover.js\nfunction AirPopover_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction AirPopover_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction AirPopover_createClass(Constructor, protoProps, staticProps) { if (protoProps) AirPopover_defineProperties(Constructor.prototype, protoProps); if (staticProps) AirPopover_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar AIRMODE_POPOVER_X_OFFSET = -5;\nvar AIRMODE_POPOVER_Y_OFFSET = 5;\n\nvar AirPopover_AirPopover = /*#__PURE__*/function () {\n  function AirPopover(context) {\n    var _this = this;\n\n    AirPopover_classCallCheck(this, AirPopover);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.options = context.options;\n    this.hidable = true;\n    this.onContextmenu = false;\n    this.pageX = null;\n    this.pageY = null;\n    this.events = {\n      'summernote.contextmenu': function summernoteContextmenu(e) {\n        if (_this.options.editing) {\n          e.preventDefault();\n          e.stopPropagation();\n          _this.onContextmenu = true;\n\n          _this.update(true);\n        }\n      },\n      'summernote.mousedown': function summernoteMousedown(we, e) {\n        _this.pageX = e.pageX;\n        _this.pageY = e.pageY;\n      },\n      'summernote.keyup summernote.mouseup summernote.scroll': function summernoteKeyupSummernoteMouseupSummernoteScroll(we, e) {\n        if (_this.options.editing && !_this.onContextmenu) {\n          _this.pageX = e.pageX;\n          _this.pageY = e.pageY;\n\n          _this.update();\n        }\n\n        _this.onContextmenu = false;\n      },\n      'summernote.disable summernote.change summernote.dialog.shown summernote.blur': function summernoteDisableSummernoteChangeSummernoteDialogShownSummernoteBlur() {\n        _this.hide();\n      },\n      'summernote.focusout': function summernoteFocusout() {\n        if (!_this.$popover.is(':active,:focus')) {\n          _this.hide();\n        }\n      }\n    };\n  }\n\n  AirPopover_createClass(AirPopover, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return this.options.airMode && !lists.isEmpty(this.options.popover.air);\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      var _this2 = this;\n\n      this.$popover = this.ui.popover({\n        className: 'note-air-popover'\n      }).render().appendTo(this.options.container);\n      var $content = this.$popover.find('.popover-content');\n      this.context.invoke('buttons.build', $content, this.options.popover.air); // disable hiding this popover preemptively by 'summernote.blur' event.\n\n      this.$popover.on('mousedown', function () {\n        _this2.hidable = false;\n      }); // (re-)enable hiding after 'summernote.blur' has been handled (aka. ignored).\n\n      this.$popover.on('mouseup', function () {\n        _this2.hidable = true;\n      });\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$popover.remove();\n    }\n  }, {\n    key: \"update\",\n    value: function update(forcelyOpen) {\n      var styleInfo = this.context.invoke('editor.currentStyle');\n\n      if (styleInfo.range && (!styleInfo.range.isCollapsed() || forcelyOpen)) {\n        var rect = {\n          left: this.pageX,\n          top: this.pageY\n        };\n        var containerOffset = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this.options.container).offset();\n        rect.top -= containerOffset.top;\n        rect.left -= containerOffset.left;\n        this.$popover.css({\n          display: 'block',\n          left: Math.max(rect.left, 0) + AIRMODE_POPOVER_X_OFFSET,\n          top: rect.top + AIRMODE_POPOVER_Y_OFFSET\n        });\n        this.context.invoke('buttons.updateCurrentStyle', this.$popover);\n      } else {\n        this.hide();\n      }\n    }\n  }, {\n    key: \"updateCodeview\",\n    value: function updateCodeview(isCodeview) {\n      this.ui.toggleBtnActive(this.$popover.find('.btn-codeview'), isCodeview);\n\n      if (isCodeview) {\n        this.hide();\n      }\n    }\n  }, {\n    key: \"hide\",\n    value: function hide() {\n      if (this.hidable) {\n        this.$popover.hide();\n      }\n    }\n  }]);\n\n  return AirPopover;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/module/HintPopover.js\nfunction HintPopover_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction HintPopover_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction HintPopover_createClass(Constructor, protoProps, staticProps) { if (protoProps) HintPopover_defineProperties(Constructor.prototype, protoProps); if (staticProps) HintPopover_defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\n\n\n\n\nvar POPOVER_DIST = 5;\n\nvar HintPopover_HintPopover = /*#__PURE__*/function () {\n  function HintPopover(context) {\n    var _this = this;\n\n    HintPopover_classCallCheck(this, HintPopover);\n\n    this.context = context;\n    this.ui = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.ui;\n    this.$editable = context.layoutInfo.editable;\n    this.options = context.options;\n    this.hint = this.options.hint || [];\n    this.direction = this.options.hintDirection || 'bottom';\n    this.hints = Array.isArray(this.hint) ? this.hint : [this.hint];\n    this.events = {\n      'summernote.keyup': function summernoteKeyup(we, e) {\n        if (!e.isDefaultPrevented()) {\n          _this.handleKeyup(e);\n        }\n      },\n      'summernote.keydown': function summernoteKeydown(we, e) {\n        _this.handleKeydown(e);\n      },\n      'summernote.disable summernote.dialog.shown summernote.blur': function summernoteDisableSummernoteDialogShownSummernoteBlur() {\n        _this.hide();\n      }\n    };\n  }\n\n  HintPopover_createClass(HintPopover, [{\n    key: \"shouldInitialize\",\n    value: function shouldInitialize() {\n      return this.hints.length > 0;\n    }\n  }, {\n    key: \"initialize\",\n    value: function initialize() {\n      var _this2 = this;\n\n      this.lastWordRange = null;\n      this.matchingWord = null;\n      this.$popover = this.ui.popover({\n        className: 'note-hint-popover',\n        hideArrow: true,\n        direction: ''\n      }).render().appendTo(this.options.container);\n      this.$popover.hide();\n      this.$content = this.$popover.find('.popover-content,.note-popover-content');\n      this.$content.on('click', '.note-hint-item', function (e) {\n        _this2.$content.find('.active').removeClass('active');\n\n        external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(e.currentTarget).addClass('active');\n\n        _this2.replace();\n      });\n      this.$popover.on('mousedown', function (e) {\n        e.preventDefault();\n      });\n    }\n  }, {\n    key: \"destroy\",\n    value: function destroy() {\n      this.$popover.remove();\n    }\n  }, {\n    key: \"selectItem\",\n    value: function selectItem($item) {\n      this.$content.find('.active').removeClass('active');\n      $item.addClass('active');\n      this.$content[0].scrollTop = $item[0].offsetTop - this.$content.innerHeight() / 2;\n    }\n  }, {\n    key: \"moveDown\",\n    value: function moveDown() {\n      var $current = this.$content.find('.note-hint-item.active');\n      var $next = $current.next();\n\n      if ($next.length) {\n        this.selectItem($next);\n      } else {\n        var $nextGroup = $current.parent().next();\n\n        if (!$nextGroup.length) {\n          $nextGroup = this.$content.find('.note-hint-group').first();\n        }\n\n        this.selectItem($nextGroup.find('.note-hint-item').first());\n      }\n    }\n  }, {\n    key: \"moveUp\",\n    value: function moveUp() {\n      var $current = this.$content.find('.note-hint-item.active');\n      var $prev = $current.prev();\n\n      if ($prev.length) {\n        this.selectItem($prev);\n      } else {\n        var $prevGroup = $current.parent().prev();\n\n        if (!$prevGroup.length) {\n          $prevGroup = this.$content.find('.note-hint-group').last();\n        }\n\n        this.selectItem($prevGroup.find('.note-hint-item').last());\n      }\n    }\n  }, {\n    key: \"replace\",\n    value: function replace() {\n      var $item = this.$content.find('.note-hint-item.active');\n\n      if ($item.length) {\n        var node = this.nodeFromItem($item); // If matchingWord length = 0 -> capture OK / open hint / but as mention capture \"\" (\\w*)\n\n        if (this.matchingWord !== null && this.matchingWord.length === 0) {\n          this.lastWordRange.so = this.lastWordRange.eo; // Else si > 0 and normal case -> adjust range \"before\" for correct position of insertion\n        } else if (this.matchingWord !== null && this.matchingWord.length > 0 && !this.lastWordRange.isCollapsed()) {\n          var rangeCompute = this.lastWordRange.eo - this.lastWordRange.so - this.matchingWord.length;\n\n          if (rangeCompute > 0) {\n            this.lastWordRange.so += rangeCompute;\n          }\n        }\n\n        this.lastWordRange.insertNode(node);\n\n        if (this.options.hintSelect === 'next') {\n          var blank = document.createTextNode('');\n          external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(node).after(blank);\n          range.createFromNodeBefore(blank).select();\n        } else {\n          range.createFromNodeAfter(node).select();\n        }\n\n        this.lastWordRange = null;\n        this.hide();\n        this.context.invoke('editor.focus');\n      }\n    }\n  }, {\n    key: \"nodeFromItem\",\n    value: function nodeFromItem($item) {\n      var hint = this.hints[$item.data('index')];\n      var item = $item.data('item');\n      var node = hint.content ? hint.content(item) : item;\n\n      if (typeof node === 'string') {\n        node = dom.createText(node);\n      }\n\n      return node;\n    }\n  }, {\n    key: \"createItemTemplates\",\n    value: function createItemTemplates(hintIdx, items) {\n      var hint = this.hints[hintIdx];\n      return items.map(function (item\n      /*, idx */\n      ) {\n        var $item = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div class=\"note-hint-item\"/>');\n        $item.append(hint.template ? hint.template(item) : item + '');\n        $item.data({\n          'index': hintIdx,\n          'item': item\n        });\n        return $item;\n      });\n    }\n  }, {\n    key: \"handleKeydown\",\n    value: function handleKeydown(e) {\n      if (!this.$popover.is(':visible')) {\n        return;\n      }\n\n      if (e.keyCode === core_key.code.ENTER) {\n        e.preventDefault();\n        this.replace();\n      } else if (e.keyCode === core_key.code.UP) {\n        e.preventDefault();\n        this.moveUp();\n      } else if (e.keyCode === core_key.code.DOWN) {\n        e.preventDefault();\n        this.moveDown();\n      }\n    }\n  }, {\n    key: \"searchKeyword\",\n    value: function searchKeyword(index, keyword, callback) {\n      var hint = this.hints[index];\n\n      if (hint && hint.match.test(keyword) && hint.search) {\n        var matches = hint.match.exec(keyword);\n        this.matchingWord = matches[0];\n        hint.search(matches[1], callback);\n      } else {\n        callback();\n      }\n    }\n  }, {\n    key: \"createGroup\",\n    value: function createGroup(idx, keyword) {\n      var _this3 = this;\n\n      var $group = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()('<div class=\"note-hint-group note-hint-group-' + idx + '\"></div>');\n      this.searchKeyword(idx, keyword, function (items) {\n        items = items || [];\n\n        if (items.length) {\n          $group.html(_this3.createItemTemplates(idx, items));\n\n          _this3.show();\n        }\n      });\n      return $group;\n    }\n  }, {\n    key: \"handleKeyup\",\n    value: function handleKeyup(e) {\n      var _this4 = this;\n\n      if (!lists.contains([core_key.code.ENTER, core_key.code.UP, core_key.code.DOWN], e.keyCode)) {\n        var _range = this.context.invoke('editor.getLastRange');\n\n        var wordRange, keyword;\n\n        if (this.options.hintMode === 'words') {\n          wordRange = _range.getWordsRange(_range);\n          keyword = wordRange.toString();\n          this.hints.forEach(function (hint) {\n            if (hint.match.test(keyword)) {\n              wordRange = _range.getWordsMatchRange(hint.match);\n              return false;\n            }\n          });\n\n          if (!wordRange) {\n            this.hide();\n            return;\n          }\n\n          keyword = wordRange.toString();\n        } else {\n          wordRange = _range.getWordRange();\n          keyword = wordRange.toString();\n        }\n\n        if (this.hints.length && keyword) {\n          this.$content.empty();\n          var bnd = func.rect2bnd(lists.last(wordRange.getClientRects()));\n          var containerOffset = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(this.options.container).offset();\n\n          if (bnd) {\n            bnd.top -= containerOffset.top;\n            bnd.left -= containerOffset.left;\n            this.$popover.hide();\n            this.lastWordRange = wordRange;\n            this.hints.forEach(function (hint, idx) {\n              if (hint.match.test(keyword)) {\n                _this4.createGroup(idx, keyword).appendTo(_this4.$content);\n              }\n            }); // select first .note-hint-item\n\n            this.$content.find('.note-hint-item:first').addClass('active'); // set position for popover after group is created\n\n            if (this.direction === 'top') {\n              this.$popover.css({\n                left: bnd.left,\n                top: bnd.top - this.$popover.outerHeight() - POPOVER_DIST\n              });\n            } else {\n              this.$popover.css({\n                left: bnd.left,\n                top: bnd.top + bnd.height + POPOVER_DIST\n              });\n            }\n          }\n        } else {\n          this.hide();\n        }\n      }\n    }\n  }, {\n    key: \"show\",\n    value: function show() {\n      this.$popover.show();\n    }\n  }, {\n    key: \"hide\",\n    value: function hide() {\n      this.$popover.hide();\n    }\n  }]);\n\n  return HintPopover;\n}();\n\n\n// CONCATENATED MODULE: ./src/js/base/settings.js\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexternal_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote, {\n  version: '0.8.18',\n  plugins: {},\n  dom: dom,\n  range: range,\n  lists: lists,\n  options: {\n    langInfo: external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote.lang['en-US'],\n    editing: true,\n    modules: {\n      'editor': Editor_Editor,\n      'clipboard': Clipboard_Clipboard,\n      'dropzone': Dropzone_Dropzone,\n      'codeview': Codeview_CodeView,\n      'statusbar': Statusbar_Statusbar,\n      'fullscreen': Fullscreen_Fullscreen,\n      'handle': Handle_Handle,\n      // FIXME: HintPopover must be front of autolink\n      //  - Script error about range when Enter key is pressed on hint popover\n      'hintPopover': HintPopover_HintPopover,\n      'autoLink': AutoLink_AutoLink,\n      'autoSync': AutoSync_AutoSync,\n      'autoReplace': AutoReplace_AutoReplace,\n      'placeholder': Placeholder_Placeholder,\n      'buttons': Buttons_Buttons,\n      'toolbar': Toolbar_Toolbar,\n      'linkDialog': LinkDialog_LinkDialog,\n      'linkPopover': LinkPopover_LinkPopover,\n      'imageDialog': ImageDialog_ImageDialog,\n      'imagePopover': ImagePopover_ImagePopover,\n      'tablePopover': TablePopover_TablePopover,\n      'videoDialog': VideoDialog_VideoDialog,\n      'helpDialog': HelpDialog_HelpDialog,\n      'airPopover': AirPopover_AirPopover\n    },\n    buttons: {},\n    lang: 'en-US',\n    followingToolbar: false,\n    toolbarPosition: 'top',\n    otherStaticBar: '',\n    // toolbar\n    codeviewKeepButton: false,\n    toolbar: [['style', ['style']], ['font', ['bold', 'underline', 'clear']], ['fontsize',['fontsize']], ['fontname', ['fontname']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph']], ['table', ['table']], ['insert', ['link', 'picture', 'video']], ['view', ['fullscreen', 'codeview', 'help']]],\n    // popover\n    popatmouse: true,\n    popover: {\n      image: [['resize', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']], ['float', ['floatLeft', 'floatRight', 'floatNone']], ['remove', ['removeMedia']]],\n      link: [['link', ['linkDialogShow', 'unlink']]],\n      table: [['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']], ['delete', ['deleteRow', 'deleteCol', 'deleteTable']]],\n      air: [['color', ['color']], ['font', ['bold', 'underline', 'clear']], ['para', ['ul', 'paragraph']], ['table', ['table']], ['insert', ['link', 'picture']], ['view', ['fullscreen', 'codeview']]]\n    },\n    // air mode: inline editor\n    airMode: false,\n    overrideContextMenu: false,\n    // TBD\n    width: null,\n    height: null,\n    linkTargetBlank: true,\n    useProtocol: true,\n    defaultProtocol: 'http://',\n    focus: false,\n    tabDisabled: false,\n    tabSize: 4,\n    styleWithCSS: false,\n    shortcuts: true,\n    textareaAutoSync: true,\n    tooltip: 'auto',\n    container: null,\n    maxTextLength: 0,\n    blockquoteBreakingLevel: 2,\n    spellCheck: true,\n    disableGrammar: false,\n    placeholder: null,\n    inheritPlaceholder: false,\n    // TODO: need to be documented\n    recordEveryKeystroke: false,\n    historyLimit: 200,\n    // TODO: need to be documented\n    showDomainOnlyForAutolink: false,\n    // TODO: need to be documented\n    hintMode: 'word',\n    hintSelect: 'after',\n    hintDirection: 'bottom',\n    styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n    fontNames: ['Arial', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande', 'Tahoma', 'Times New Roman', 'Verdana'],\n    fontNamesIgnoreCheck: [],\n    addDefaultFonts: true,\n    fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],\n    fontSizeUnits: ['px', 'pt'],\n    // pallete colors(n x n)\n    colors: [['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'], ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'], ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'], ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'], ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'], ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'], ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'], ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']],\n    // http://chir.ag/projects/name-that-color/\n    colorsName: [['Black', 'Tundora', 'Dove Gray', 'Star Dust', 'Pale Slate', 'Gallery', 'Alabaster', 'White'], ['Red', 'Orange Peel', 'Yellow', 'Green', 'Cyan', 'Blue', 'Electric Violet', 'Magenta'], ['Azalea', 'Karry', 'Egg White', 'Zanah', 'Botticelli', 'Tropical Blue', 'Mischka', 'Twilight'], ['Tonys Pink', 'Peach Orange', 'Cream Brulee', 'Sprout', 'Casper', 'Perano', 'Cold Purple', 'Careys Pink'], ['Mandy', 'Rajah', 'Dandelion', 'Olivine', 'Gulf Stream', 'Viking', 'Blue Marguerite', 'Puce'], ['Guardsman Red', 'Fire Bush', 'Golden Dream', 'Chelsea Cucumber', 'Smalt Blue', 'Boston Blue', 'Butterfly Bush', 'Cadillac'], ['Sangria', 'Mai Tai', 'Buddha Gold', 'Forest Green', 'Eden', 'Venice Blue', 'Meteorite', 'Claret'], ['Rosewood', 'Cinnamon', 'Olive', 'Parsley', 'Tiber', 'Midnight Blue', 'Valentino', 'Loulou']],\n    colorButton: {\n      foreColor: '#000000',\n      backColor: '#FFFF00'\n    },\n    lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],\n    tableClassName: 'table table-bordered',\n    insertTableMaxSize: {\n      col: 10,\n      row: 10\n    },\n    // By default, dialogs are attached in container.\n    dialogsInBody: false,\n    dialogsFade: false,\n    maximumImageFileSize: null,\n    callbacks: {\n      onBeforeCommand: null,\n      onBlur: null,\n      onBlurCodeview: null,\n      onChange: null,\n      onChangeCodeview: null,\n      onDialogShown: null,\n      onEnter: null,\n      onFocus: null,\n      onImageLinkInsert: null,\n      onImageUpload: null,\n      onImageUploadError: null,\n      onInit: null,\n      onKeydown: null,\n      onKeyup: null,\n      onMousedown: null,\n      onMouseup: null,\n      onPaste: null,\n      onScroll: null\n    },\n    codemirror: {\n      mode: 'text/html',\n      htmlMode: true,\n      lineNumbers: true\n    },\n    codeviewFilter: false,\n    codeviewFilterRegex: /<\\/*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|ilayer|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|t(?:itle|extarea)|xml)[^>]*?>/gi,\n    codeviewIframeFilter: true,\n    codeviewIframeWhitelistSrc: [],\n    codeviewIframeWhitelistSrcBase: ['www.youtube.com', 'www.youtube-nocookie.com', 'www.facebook.com', 'vine.co', 'instagram.com', 'player.vimeo.com', 'www.dailymotion.com', 'player.youku.com', 'v.qq.com'],\n    keyMap: {\n      pc: {\n        'ESC': 'escape',\n        'ENTER': 'insertParagraph',\n        'CTRL+Z': 'undo',\n        'CTRL+Y': 'redo',\n        'TAB': 'tab',\n        'SHIFT+TAB': 'untab',\n        'CTRL+B': 'bold',\n        'CTRL+I': 'italic',\n        'CTRL+U': 'underline',\n        'CTRL+SHIFT+S': 'strikethrough',\n        'CTRL+BACKSLASH': 'removeFormat',\n        'CTRL+SHIFT+L': 'justifyLeft',\n        'CTRL+SHIFT+E': 'justifyCenter',\n        'CTRL+SHIFT+R': 'justifyRight',\n        'CTRL+SHIFT+J': 'justifyFull',\n        'CTRL+SHIFT+NUM7': 'insertUnorderedList',\n        'CTRL+SHIFT+NUM8': 'insertOrderedList',\n        'CTRL+LEFTBRACKET': 'outdent',\n        'CTRL+RIGHTBRACKET': 'indent',\n        'CTRL+NUM0': 'formatPara',\n        'CTRL+NUM1': 'formatH1',\n        'CTRL+NUM2': 'formatH2',\n        'CTRL+NUM3': 'formatH3',\n        'CTRL+NUM4': 'formatH4',\n        'CTRL+NUM5': 'formatH5',\n        'CTRL+NUM6': 'formatH6',\n        'CTRL+ENTER': 'insertHorizontalRule',\n        'CTRL+K': 'linkDialog.show'\n      },\n      mac: {\n        'ESC': 'escape',\n        'ENTER': 'insertParagraph',\n        'CMD+Z': 'undo',\n        'CMD+SHIFT+Z': 'redo',\n        'TAB': 'tab',\n        'SHIFT+TAB': 'untab',\n        'CMD+B': 'bold',\n        'CMD+I': 'italic',\n        'CMD+U': 'underline',\n        'CMD+SHIFT+S': 'strikethrough',\n        'CMD+BACKSLASH': 'removeFormat',\n        'CMD+SHIFT+L': 'justifyLeft',\n        'CMD+SHIFT+E': 'justifyCenter',\n        'CMD+SHIFT+R': 'justifyRight',\n        'CMD+SHIFT+J': 'justifyFull',\n        'CMD+SHIFT+NUM7': 'insertUnorderedList',\n        'CMD+SHIFT+NUM8': 'insertOrderedList',\n        'CMD+LEFTBRACKET': 'outdent',\n        'CMD+RIGHTBRACKET': 'indent',\n        'CMD+NUM0': 'formatPara',\n        'CMD+NUM1': 'formatH1',\n        'CMD+NUM2': 'formatH2',\n        'CMD+NUM3': 'formatH3',\n        'CMD+NUM4': 'formatH4',\n        'CMD+NUM5': 'formatH5',\n        'CMD+NUM6': 'formatH6',\n        'CMD+ENTER': 'insertHorizontalRule',\n        'CMD+K': 'linkDialog.show'\n      }\n    },\n    icons: {\n      'align': 'note-icon-align',\n      'alignCenter': 'note-icon-align-center',\n      'alignJustify': 'note-icon-align-justify',\n      'alignLeft': 'note-icon-align-left',\n      'alignRight': 'note-icon-align-right',\n      'rowBelow': 'note-icon-row-below',\n      'colBefore': 'note-icon-col-before',\n      'colAfter': 'note-icon-col-after',\n      'rowAbove': 'note-icon-row-above',\n      'rowRemove': 'note-icon-row-remove',\n      'colRemove': 'note-icon-col-remove',\n      'indent': 'note-icon-align-indent',\n      'outdent': 'note-icon-align-outdent',\n      'arrowsAlt': 'note-icon-arrows-alt',\n      'bold': 'note-icon-bold',\n      'caret': 'note-icon-caret',\n      'circle': 'note-icon-circle',\n      'close': 'note-icon-close',\n      'code': 'note-icon-code',\n      'eraser': 'note-icon-eraser',\n      'floatLeft': 'note-icon-float-left',\n      'floatRight': 'note-icon-float-right',\n      'font': 'note-icon-font',\n      'frame': 'note-icon-frame',\n      'italic': 'note-icon-italic',\n      'link': 'note-icon-link',\n      'unlink': 'note-icon-chain-broken',\n      'magic': 'note-icon-magic',\n      'menuCheck': 'note-icon-menu-check',\n      'minus': 'note-icon-minus',\n      'orderedlist': 'note-icon-orderedlist',\n      'pencil': 'note-icon-pencil',\n      'picture': 'note-icon-picture',\n      'question': 'note-icon-question',\n      'redo': 'note-icon-redo',\n      'rollback': 'note-icon-rollback',\n      'square': 'note-icon-square',\n      'strikethrough': 'note-icon-strikethrough',\n      'subscript': 'note-icon-subscript',\n      'superscript': 'note-icon-superscript',\n      'table': 'note-icon-table',\n      'textHeight': 'note-icon-text-height',\n      'trash': 'note-icon-trash',\n      'underline': 'note-icon-underline',\n      'undo': 'note-icon-undo',\n      'unorderedlist': 'note-icon-unorderedlist',\n      'video': 'note-icon-video'\n    }\n  }\n});\n\n/***/ }),\n\n/***/ 4:\n/***/ (function(module, exports, __webpack_require__) {\n\n// extracted by mini-css-extract-plugin\n\n/***/ }),\n\n/***/ 52:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n// ESM COMPAT FLAG\n__webpack_require__.r(__webpack_exports__);\n\n// EXTERNAL MODULE: external {\"root\":\"jQuery\",\"commonjs2\":\"jquery\",\"commonjs\":\"jquery\",\"amd\":\"jquery\"}\nvar external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_ = __webpack_require__(0);\nvar external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default = /*#__PURE__*/__webpack_require__.n(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_);\n\n// EXTERNAL MODULE: ./src/js/base/renderer.js\nvar renderer = __webpack_require__(1);\n\n// CONCATENATED MODULE: ./src/js/bs3/ui.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\nvar editor = renderer[\"a\" /* default */].create('<div class=\"note-editor note-frame panel panel-default\"/>');\nvar toolbar = renderer[\"a\" /* default */].create('<div class=\"panel-heading note-toolbar\" role=\"toolbar\"/>');\nvar editingArea = renderer[\"a\" /* default */].create('<div class=\"note-editing-area\"/>');\nvar codable = renderer[\"a\" /* default */].create('<textarea class=\"note-codable\" aria-multiline=\"true\"/>');\nvar editable = renderer[\"a\" /* default */].create('<div class=\"note-editable\" contentEditable=\"true\" role=\"textbox\" aria-multiline=\"true\"/>');\nvar statusbar = renderer[\"a\" /* default */].create(['<output class=\"note-status-output\" role=\"status\" aria-live=\"polite\"></output>', '<div class=\"note-statusbar\" role=\"status\">', '<div class=\"note-resizebar\" aria-label=\"Resize\">', '<div class=\"note-icon-bar\"></div>', '<div class=\"note-icon-bar\"></div>', '<div class=\"note-icon-bar\"></div>', '</div>', '</div>'].join(''));\nvar airEditor = renderer[\"a\" /* default */].create('<div class=\"note-editor note-airframe\"/>');\nvar airEditable = renderer[\"a\" /* default */].create(['<div class=\"note-editable\" contentEditable=\"true\" role=\"textbox\" aria-multiline=\"true\"></div>', '<output class=\"note-status-output\" role=\"status\" aria-live=\"polite\"></output>'].join(''));\nvar buttonGroup = renderer[\"a\" /* default */].create('<div class=\"note-btn-group btn-group\">');\nvar dropdown = renderer[\"a\" /* default */].create('<ul class=\"note-dropdown-menu dropdown-menu\">', function ($node, options) {\n  var markup = Array.isArray(options.items) ? options.items.map(function (item) {\n    var value = typeof item === 'string' ? item : item.value || '';\n    var content = options.template ? options.template(item) : item;\n    var option = _typeof(item) === 'object' ? item.option : undefined;\n    var dataValue = 'data-value=\"' + value + '\"';\n    var dataOption = option !== undefined ? ' data-option=\"' + option + '\"' : '';\n    return '<li aria-label=\"' + value + '\"><a href=\"#\" ' + (dataValue + dataOption) + '>' + content + '</a></li>';\n  }).join('') : options.items;\n  $node.html(markup).attr({\n    'aria-label': options.title\n  });\n\n  if (options && options.codeviewKeepButton) {\n    $node.addClass('note-codeview-keep');\n  }\n});\n\nvar dropdownButtonContents = function dropdownButtonContents(contents, options) {\n  return contents + ' ' + icon(options.icons.caret, 'span');\n};\n\nvar dropdownCheck = renderer[\"a\" /* default */].create('<ul class=\"note-dropdown-menu dropdown-menu note-check\">', function ($node, options) {\n  var markup = Array.isArray(options.items) ? options.items.map(function (item) {\n    var value = typeof item === 'string' ? item : item.value || '';\n    var content = options.template ? options.template(item) : item;\n    return '<li aria-label=\"' + item + '\"><a href=\"#\" data-value=\"' + value + '\">' + icon(options.checkClassName) + ' ' + content + '</a></li>';\n  }).join('') : options.items;\n  $node.html(markup).attr({\n    'aria-label': options.title\n  });\n\n  if (options && options.codeviewKeepButton) {\n    $node.addClass('note-codeview-keep');\n  }\n});\nvar dialog = renderer[\"a\" /* default */].create('<div class=\"modal note-modal\" aria-hidden=\"false\" tabindex=\"-1\" role=\"dialog\"/>', function ($node, options) {\n  if (options.fade) {\n    $node.addClass('fade');\n  }\n\n  $node.attr({\n    'aria-label': options.title\n  });\n  $node.html(['<div class=\"modal-dialog\">', '<div class=\"modal-content\">', options.title ? '<div class=\"modal-header\">' + '<button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\" aria-hidden=\"true\">&times;</button>' + '<h4 class=\"modal-title\">' + options.title + '</h4>' + '</div>' : '', '<div class=\"modal-body\">' + options.body + '</div>', options.footer ? '<div class=\"modal-footer\">' + options.footer + '</div>' : '', '</div>', '</div>'].join(''));\n});\nvar popover = renderer[\"a\" /* default */].create(['<div class=\"note-popover popover in\">', '<div class=\"arrow\"></div>', '<div class=\"popover-content note-children-container\"></div>', '</div>'].join(''), function ($node, options) {\n  var direction = typeof options.direction !== 'undefined' ? options.direction : 'bottom';\n  $node.addClass(direction);\n\n  if (options.hideArrow) {\n    $node.find('.arrow').hide();\n  }\n});\nvar ui_checkbox = renderer[\"a\" /* default */].create('<div class=\"checkbox\"></div>', function ($node, options) {\n  $node.html(['<label' + (options.id ? ' for=\"note-' + options.id + '\"' : '') + '>', '<input type=\"checkbox\"' + (options.id ? ' id=\"note-' + options.id + '\"' : ''), options.checked ? ' checked' : '', ' aria-checked=\"' + (options.checked ? 'true' : 'false') + '\"/>', options.text ? options.text : '', '</label>'].join(''));\n});\n\nvar icon = function icon(iconClassName, tagName) {\n  tagName = tagName || 'i';\n  return '<' + tagName + ' class=\"' + iconClassName + '\"></' + tagName + '>';\n};\n\nvar ui_ui = function ui(editorOptions) {\n  return {\n    editor: editor,\n    toolbar: toolbar,\n    editingArea: editingArea,\n    codable: codable,\n    editable: editable,\n    statusbar: statusbar,\n    airEditor: airEditor,\n    airEditable: airEditable,\n    buttonGroup: buttonGroup,\n    dropdown: dropdown,\n    dropdownButtonContents: dropdownButtonContents,\n    dropdownCheck: dropdownCheck,\n    dialog: dialog,\n    popover: popover,\n    checkbox: ui_checkbox,\n    icon: icon,\n    options: editorOptions,\n    palette: function palette($node, options) {\n      return renderer[\"a\" /* default */].create('<div class=\"note-color-palette\"/>', function ($node, options) {\n        var contents = [];\n\n        for (var row = 0, rowSize = options.colors.length; row < rowSize; row++) {\n          var eventName = options.eventName;\n          var colors = options.colors[row];\n          var colorsName = options.colorsName[row];\n          var buttons = [];\n\n          for (var col = 0, colSize = colors.length; col < colSize; col++) {\n            var color = colors[col];\n            var colorName = colorsName[col];\n            buttons.push(['<button type=\"button\" class=\"note-color-btn\"', 'style=\"background-color:', color, '\" ', 'data-event=\"', eventName, '\" ', 'data-value=\"', color, '\" ', 'title=\"', colorName, '\" ', 'aria-label=\"', colorName, '\" ', 'data-toggle=\"button\" tabindex=\"-1\"></button>'].join(''));\n          }\n\n          contents.push('<div class=\"note-color-row\">' + buttons.join('') + '</div>');\n        }\n\n        $node.html(contents.join(''));\n\n        if (options.tooltip) {\n          $node.find('.note-color-btn').tooltip({\n            container: options.container || editorOptions.container,\n            trigger: 'hover',\n            placement: 'bottom'\n          });\n        }\n      })($node, options);\n    },\n    button: function button($node, options) {\n      return renderer[\"a\" /* default */].create('<button type=\"button\" class=\"note-btn btn btn-default btn-sm\" tabindex=\"-1\">', function ($node, options) {\n        if (options && options.tooltip) {\n          $node.attr({\n            title: options.tooltip,\n            'aria-label': options.tooltip\n          }).tooltip({\n            container: options.container || editorOptions.container,\n            trigger: 'hover',\n            placement: 'bottom'\n          }).on('click', function (e) {\n            external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default()(e.currentTarget).tooltip('hide');\n          });\n        }\n\n        if (options && options.codeviewButton) {\n          $node.addClass('note-codeview-keep');\n        }\n      })($node, options);\n    },\n    toggleBtn: function toggleBtn($btn, isEnable) {\n      $btn.toggleClass('disabled', !isEnable);\n      $btn.attr('disabled', !isEnable);\n    },\n    toggleBtnActive: function toggleBtnActive($btn, isActive) {\n      $btn.toggleClass('active', isActive);\n    },\n    onDialogShown: function onDialogShown($dialog, handler) {\n      $dialog.one('shown.bs.modal', handler);\n    },\n    onDialogHidden: function onDialogHidden($dialog, handler) {\n      $dialog.one('hidden.bs.modal', handler);\n    },\n    showDialog: function showDialog($dialog) {\n      $dialog.modal('show');\n    },\n    hideDialog: function hideDialog($dialog) {\n      $dialog.modal('hide');\n    },\n    createLayout: function createLayout($note) {\n      var $editor = (editorOptions.airMode ? airEditor([editingArea([codable(), airEditable()])]) : editorOptions.toolbarPosition === 'bottom' ? editor([editingArea([codable(), editable()]), toolbar(), statusbar()]) : editor([toolbar(), editingArea([codable(), editable()]), statusbar()])).render();\n      $editor.insertAfter($note);\n      return {\n        note: $note,\n        editor: $editor,\n        toolbar: $editor.find('.note-toolbar'),\n        editingArea: $editor.find('.note-editing-area'),\n        editable: $editor.find('.note-editable'),\n        codable: $editor.find('.note-codable'),\n        statusbar: $editor.find('.note-statusbar')\n      };\n    },\n    removeLayout: function removeLayout($note, layoutInfo) {\n      $note.html(layoutInfo.editable.html());\n      layoutInfo.editor.remove();\n      $note.show();\n    }\n  };\n};\n\n/* harmony default export */ var bs3_ui = (ui_ui);\n// EXTERNAL MODULE: ./src/js/base/settings.js + 37 modules\nvar settings = __webpack_require__(3);\n\n// EXTERNAL MODULE: ./src/styles/summernote-bs3.scss\nvar summernote_bs3 = __webpack_require__(4);\n\n// CONCATENATED MODULE: ./src/js/bs3/settings.js\n\n\n\n\nexternal_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote = external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.extend(external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summernote, {\n  ui_template: bs3_ui,\n  \"interface\": 'bs3'\n});\n\n/***/ })\n\n/******/ });\n});\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/typeahead/bootstrap-typeahead.js",
    "content": "/* =============================================================\r\n * bootstrap3-typeahead.js v4.0.2\r\n * https://github.com/bassjobsen/Bootstrap-3-Typeahead\r\n * =============================================================\r\n * Original written by @mdo and @fat\r\n * =============================================================\r\n * Copyright 2014 Bass Jobsen @bassjobsen\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the 'License');\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an 'AS IS' BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n * ============================================================ */\r\n\r\n\r\n(function (root, factory) {\r\n\r\n    'use strict';\r\n\r\n    // CommonJS module is defined\r\n    if (typeof module !== 'undefined' && module.exports) {\r\n        module.exports = factory(require('jquery'));\r\n    }\r\n    // AMD module is defined\r\n    else if (typeof define === 'function' && define.amd) {\r\n        define(['jquery'], function ($) {\r\n            return factory($);\r\n        });\r\n    } else {\r\n        factory(root.jQuery);\r\n    }\r\n\r\n}(this, function ($) {\r\n\r\n    'use strict';\r\n    // jshint laxcomma: true\r\n\r\n\r\n    /* TYPEAHEAD PUBLIC CLASS DEFINITION\r\n     * ================================= */\r\n\r\n    var Typeahead = function (element, options) {\r\n        this.$element = $(element);\r\n        this.options = $.extend({}, Typeahead.defaults, options);\r\n        this.matcher = this.options.matcher || this.matcher;\r\n        this.sorter = this.options.sorter || this.sorter;\r\n        this.select = this.options.select || this.select;\r\n        this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true;\r\n        this.highlighter = this.options.highlighter || this.highlighter;\r\n        this.render = this.options.render || this.render;\r\n        this.updater = this.options.updater || this.updater;\r\n        this.displayText = this.options.displayText || this.displayText;\r\n        this.itemLink = this.options.itemLink || this.itemLink;\r\n        this.itemTitle = this.options.itemTitle || this.itemTitle;\r\n        this.followLinkOnSelect = this.options.followLinkOnSelect || this.followLinkOnSelect;\r\n        this.source = this.options.source;\r\n        this.delay = this.options.delay;\r\n        this.theme = this.options.theme && this.options.themes && this.options.themes[this.options.theme] || Typeahead.defaults.themes[Typeahead.defaults.theme];\r\n        this.$menu = $(this.options.menu || this.theme.menu);\r\n        this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null;\r\n        this.fitToElement = typeof this.options.fitToElement == 'boolean' ? this.options.fitToElement : false;\r\n        this.shown = false;\r\n        this.listen();\r\n        this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' || this.options.showHintOnFocus === 'all' ? this.options.showHintOnFocus : false;\r\n        this.afterSelect = this.options.afterSelect;\r\n        this.afterEmptySelect = this.options.afterEmptySelect;\r\n        this.addItem = false;\r\n        this.value = this.$element.val() || this.$element.text();\r\n        this.keyPressed = false;\r\n        this.focused = this.$element.is(':focus');\r\n        this.changeInputOnSelect = this.options.changeInputOnSelect || this.changeInputOnSelect;\r\n        this.changeInputOnMove = this.options.changeInputOnMove || this.changeInputOnMove;\r\n        this.openLinkInNewTab = this.options.openLinkInNewTab || this.openLinkInNewTab;\r\n        this.selectOnBlur = this.options.selectOnBlur || this.selectOnBlur;\r\n        this.showCategoryHeader = this.options.showCategoryHeader || this.showCategoryHeader;\r\n    };\r\n\r\n    Typeahead.prototype = {\r\n\r\n        constructor: Typeahead,\r\n\r\n\r\n        setDefault: function (val) {\r\n            // var val = this.$menu.find('.active').data('value');\r\n            this.$element.data('active', val);\r\n            if (this.autoSelect || val) {\r\n                var newVal = this.updater(val);\r\n                // Updater can be set to any random functions via \"options\" parameter in constructor above.\r\n                // Add null check for cases when updater returns void or undefined.\r\n                if (!newVal) {\r\n                    newVal = '';\r\n                }\r\n                this.$element\r\n                    .val(this.displayText(newVal) || newVal)\r\n                    .text(this.displayText(newVal) || newVal)\r\n                    .change();\r\n                this.afterSelect(newVal);\r\n            }\r\n            return this.hide();\r\n        },\r\n\r\n        select: function () {\r\n            var val = this.$menu.find('.active').data('value');\r\n\r\n            this.$element.data('active', val);\r\n            if (this.autoSelect || val) {\r\n                var newVal = this.updater(val);\r\n                // Updater can be set to any random functions via \"options\" parameter in constructor above.\r\n                // Add null check for cases when updater returns void or undefined.\r\n                if (!newVal) {\r\n                    newVal = '';\r\n                }\r\n\r\n                if (this.changeInputOnSelect) {\r\n                    this.$element\r\n                        .val(this.displayText(newVal) || newVal)\r\n                        .text(this.displayText(newVal) || newVal)\r\n                        .change();\r\n                }\r\n\r\n                if (this.followLinkOnSelect && this.itemLink(val)) {\r\n                    if (this.openLinkInNewTab) {\r\n                        window.open(this.itemLink(val), '_blank');\r\n                    } else {\r\n                        document.location = this.itemLink(val);\r\n                    }\r\n                    this.afterSelect(newVal);\r\n                } else if (this.followLinkOnSelect && !this.itemLink(val)) {\r\n                    this.afterEmptySelect(newVal);\r\n                } else {\r\n                    this.afterSelect(newVal);\r\n                }\r\n            } else {\r\n                this.afterEmptySelect();\r\n            }\r\n\r\n            return this.hide();\r\n        },\r\n\r\n        updater: function (item) {\r\n            return item;\r\n        },\r\n\r\n        setSource: function (source) {\r\n            this.source = source;\r\n        },\r\n\r\n        show: function () {\r\n            var pos = $.extend({}, this.$element.position(), {\r\n                height: this.$element[0].offsetHeight\r\n            });\r\n\r\n            var scrollHeight = typeof this.options.scrollHeight == 'function' ?\r\n                this.options.scrollHeight.call() :\r\n                this.options.scrollHeight;\r\n\r\n            var element;\r\n            if (this.shown) {\r\n                element = this.$menu;\r\n            } else if (this.$appendTo) {\r\n                element = this.$menu.appendTo(this.$appendTo);\r\n                this.hasSameParent = this.$appendTo.is(this.$element.parent());\r\n            } else {\r\n                element = this.$menu.insertAfter(this.$element);\r\n                this.hasSameParent = true;\r\n            }\r\n\r\n            if (!this.hasSameParent) {\r\n                // We cannot rely on the element position, need to position relative to the window\r\n                element.css('position', 'fixed');\r\n                var offset = this.$element.offset();\r\n                pos.top = offset.top;\r\n                pos.left = offset.left;\r\n            }\r\n            // The rules for bootstrap are: 'dropup' in the parent and 'dropdown-menu-right' in the element.\r\n            // Note that to get right alignment, you'll need to specify `menu` in the options to be:\r\n            // '<ul class=\"typeahead dropdown-menu\" role=\"listbox\"></ul>'\r\n            var dropup = $(element).parent().hasClass('dropup');\r\n            var newTop = dropup ? 'auto' : (pos.top + pos.height + scrollHeight);\r\n            var right = $(element).hasClass('dropdown-menu-right');\r\n            var newLeft = right ? 'auto' : pos.left;\r\n            // it seems like setting the css is a bad idea (just let Bootstrap do it), but I'll keep the old\r\n            // logic in place except for the dropup/right-align cases.\r\n            element.css({ top: newTop, left: newLeft }).show();\r\n\r\n            if (this.options.fitToElement === true) {\r\n                element.css('width', this.$element.outerWidth() + 'px');\r\n            }\r\n\r\n            this.shown = true;\r\n            return this;\r\n        },\r\n\r\n        hide: function () {\r\n            this.$menu.hide();\r\n            this.shown = false;\r\n            return this;\r\n        },\r\n\r\n        lookup: function (query) {\r\n            if (typeof(query) != 'undefined' && query !== null) {\r\n                this.query = query;\r\n            } else {\r\n                this.query = this.$element.val();\r\n            }\r\n\r\n            if (this.query.length < this.options.minLength && !this.options.showHintOnFocus) {\r\n                return this.shown ? this.hide() : this;\r\n            }\r\n\r\n            var worker = $.proxy(function () {\r\n\r\n                // Bloodhound (since 0.11) needs three arguments.\r\n                // Two of them are callback functions (sync and async) for local and remote data processing\r\n                // see https://github.com/twitter/typeahead.js/blob/master/src/bloodhound/bloodhound.js#L132\r\n                if ($.isFunction(this.source) && this.source.length === 3) {\r\n                    this.source(this.query, $.proxy(this.process, this), $.proxy(this.process, this));\r\n                } else if ($.isFunction(this.source)) {\r\n                    this.source(this.query, $.proxy(this.process, this));\r\n                } else if (this.source) {\r\n                    this.process(this.source);\r\n                }\r\n            }, this);\r\n\r\n            clearTimeout(this.lookupWorker);\r\n            this.lookupWorker = setTimeout(worker, this.delay);\r\n        },\r\n\r\n        process: function (items) {\r\n            var that = this;\r\n\r\n            items = $.grep(items, function (item) {\r\n                return that.matcher(item);\r\n            });\r\n\r\n            items = this.sorter(items);\r\n\r\n            if (!items.length && !this.options.addItem) {\r\n                return this.shown ? this.hide() : this;\r\n            }\r\n\r\n            if (items.length > 0) {\r\n                this.$element.data('active', items[0]);\r\n            } else {\r\n                this.$element.data('active', null);\r\n            }\r\n\r\n            if (this.options.items != 'all') {\r\n                items = items.slice(0, this.options.items);\r\n            }\r\n\r\n            // Add item\r\n            if (this.options.addItem) {\r\n                items.push(this.options.addItem);\r\n            }\r\n\r\n            return this.render(items).show();\r\n        },\r\n\r\n        matcher: function (item) {\r\n            var it = this.displayText(item);\r\n            return ~it.toLowerCase().indexOf(this.query.toLowerCase());\r\n        },\r\n\r\n        sorter: function (items) {\r\n            var beginswith = [];\r\n            var caseSensitive = [];\r\n            var caseInsensitive = [];\r\n            var item;\r\n\r\n            while ((item = items.shift())) {\r\n                var it = this.displayText(item);\r\n                if (!it.toLowerCase().indexOf(this.query.toLowerCase())) {\r\n                    beginswith.push(item);\r\n                } else if (~it.indexOf(this.query)) {\r\n                    caseSensitive.push(item);\r\n                } else {\r\n                    caseInsensitive.push(item);\r\n                }\r\n            }\r\n\r\n            return beginswith.concat(caseSensitive, caseInsensitive);\r\n        },\r\n\r\n        highlighter: function (item) {\r\n            var text = this.query;\r\n            if (text === '') {\r\n                return item;\r\n            }\r\n            var matches = item.match(/(>)([^<]*)(<)/g);\r\n            var first = [];\r\n            var second = [];\r\n            var i;\r\n            if (matches && matches.length) {\r\n                // html\r\n                for (i = 0; i < matches.length; ++i) {\r\n                    if (matches[i].length > 2) {// escape '><'\r\n                        first.push(matches[i]);\r\n                    }\r\n                }\r\n            } else {\r\n                // text\r\n                first = [];\r\n                first.push(item);\r\n            }\r\n            text = text.replace((/[\\(\\)\\/\\.\\*\\+\\?\\[\\]]/g), function (mat) {\r\n                return '\\\\' + mat;\r\n            });\r\n            var reg = new RegExp(text, 'g');\r\n            var m;\r\n            for (i = 0; i < first.length; ++i) {\r\n                m = first[i].match(reg);\r\n                if (m && m.length > 0) {// find all text nodes matches\r\n                    second.push(first[i]);\r\n                }\r\n            }\r\n            for (i = 0; i < second.length; ++i) {\r\n                item = item.replace(second[i], second[i].replace(reg, '<strong>$&</strong>'));\r\n            }\r\n            return item;\r\n        },\r\n\r\n        render: function (items) {\r\n            var that = this;\r\n            var self = this;\r\n            var activeFound = false;\r\n            var data = [];\r\n            var _category = that.options.separator;\r\n\r\n            $.each(items, function (key, value) {\r\n                // inject separator\r\n                if (key > 0 && value[_category] !== items[key - 1][_category]) {\r\n                    data.push({\r\n                        __type: 'divider'\r\n                    });\r\n                }\r\n\r\n                if (this.showCategoryHeader) {\r\n                    // inject category header\r\n                    if (value[_category] && (key === 0 || value[_category] !== items[key - 1][_category])) {\r\n                        data.push({\r\n                            __type: 'category',\r\n                            name: value[_category]\r\n                        });\r\n                    }\r\n                }\r\n\r\n                data.push(value);\r\n            });\r\n\r\n            items = $(data).map(function (i, item) {\r\n                    if ((item.__type || false) == 'category'){\r\n                        return $(that.options.headerHtml || that.theme.headerHtml).text(item.name)[0];\r\n                    }\r\n\r\n                    if ((item.__type || false) == 'divider'){\r\n                        return $(that.options.headerDivider || that.theme.headerDivider)[0];\r\n                    }\r\n\r\n                    var text = self.displayText(item);\r\n                    i = $(that.options.item || that.theme.item).data('value', item);\r\n                    i.find(that.options.itemContentSelector || that.theme.itemContentSelector)\r\n                        .addBack(that.options.itemContentSelector || that.theme.itemContentSelector)\r\n                        .html(that.highlighter(text, item));\r\n                    if(that.options.followLinkOnSelect) {\r\n                        i.find('a').attr('href', self.itemLink(item));\r\n                    }\r\n                    i.find('a').attr('title', self.itemTitle(item));\r\n                    if (text == self.$element.val()) {\r\n                        i.addClass('active');\r\n                        self.$element.data('active', item);\r\n                        activeFound = true;\r\n                    }\r\n                    return i[0];\r\n                });\r\n\r\n            if (this.autoSelect && !activeFound) {\r\n                items.filter(':not(.dropdown-header)').first().addClass('active');\r\n                this.$element.data('active', items.first().data('value'));\r\n            }\r\n            this.$menu.html(items);\r\n            return this;\r\n        },\r\n\r\n        displayText: function (item) {\r\n            return typeof item !== 'undefined' && typeof item.name != 'undefined' ? item.name : item;\r\n        },\r\n\r\n        itemLink: function (item) {\r\n            return null;\r\n        },\r\n\r\n        itemTitle: function (item) {\r\n            return null;\r\n        },\r\n\r\n        next: function (event) {\r\n            var active = this.$menu.find('.active').removeClass('active');\r\n            var next = active.next();\r\n\r\n            if (!next.length) {\r\n                next = $(this.$menu.find($(this.options.item || this.theme.item).prop('tagName'))[0]);\r\n            }\r\n\r\n            while (next.hasClass('divider') || next.hasClass('dropdown-header')) {\r\n                next = next.next();\r\n            }\r\n\r\n            next.addClass('active');\r\n            // added for screen reader\r\n            var newVal = this.updater(next.data('value'));\r\n            if (this.changeInputOnMove) {\r\n                this.$element.val(this.displayText(newVal) || newVal);\r\n            }\r\n        },\r\n\r\n        prev: function (event) {\r\n            var active = this.$menu.find('.active').removeClass('active');\r\n            var prev = active.prev();\r\n\r\n            if (!prev.length) {\r\n                prev = this.$menu.find($(this.options.item || this.theme.item).prop('tagName')).last();\r\n            }\r\n\r\n            while (prev.hasClass('divider') || prev.hasClass('dropdown-header')) {\r\n                prev = prev.prev();\r\n            }\r\n\r\n            prev.addClass('active');\r\n            // added for screen reader\r\n            var newVal = this.updater(prev.data('value'));\r\n            if (this.changeInputOnMove) {\r\n                this.$element.val(this.displayText(newVal) || newVal);\r\n            }\r\n        },\r\n\r\n        listen: function () {\r\n            this.$element\r\n                .on('focus.bootstrap3Typeahead', $.proxy(this.focus, this))\r\n                .on('blur.bootstrap3Typeahead', $.proxy(this.blur, this))\r\n                .on('keypress.bootstrap3Typeahead', $.proxy(this.keypress, this))\r\n                .on('propertychange.bootstrap3Typeahead input.bootstrap3Typeahead', $.proxy(this.input, this))\r\n                .on('keyup.bootstrap3Typeahead', $.proxy(this.keyup, this));\r\n\r\n            if (this.eventSupported('keydown')) {\r\n                this.$element.on('keydown.bootstrap3Typeahead', $.proxy(this.keydown, this));\r\n            }\r\n\r\n            var itemTagName = $(this.options.item || this.theme.item).prop('tagName');\r\n            if ('ontouchstart' in document.documentElement && 'onmousemove' in document.documentElement) {\r\n\t\t        this.$menu\r\n\t\t            .on('touchstart', itemTagName, $.proxy(this.touchstart, this))\r\n\t\t            .on('touchend', itemTagName, $.proxy(this.click, this))\r\n\t\t            .on('click', $.proxy(this.click, this))\r\n\t\t            .on('mouseenter', itemTagName, $.proxy(this.mouseenter, this))\r\n\t\t            .on('mouseleave', itemTagName, $.proxy(this.mouseleave, this))\r\n\t\t            .on('mousedown', $.proxy(this.mousedown,this));\r\n\t        } else if ('ontouchstart' in document.documentElement) {\r\n\t\t        this.$menu\r\n\t\t            .on('touchstart', itemTagName, $.proxy(this.touchstart, this))\r\n\t\t            .on('touchend', itemTagName, $.proxy(this.click, this));\r\n\t        } else {\r\n                this.$menu\r\n                    .on('click', $.proxy(this.click, this))\r\n                    .on('mouseenter', itemTagName, $.proxy(this.mouseenter, this))\r\n                    .on('mouseleave', itemTagName, $.proxy(this.mouseleave, this))\r\n                    .on('mousedown', $.proxy(this.mousedown, this));\r\n            }\r\n        },\r\n\r\n        destroy: function () {\r\n            this.$element.data('typeahead', null);\r\n            this.$element.data('active', null);\r\n            this.$element\r\n                .unbind('focus.bootstrap3Typeahead')\r\n                .unbind('blur.bootstrap3Typeahead')\r\n                .unbind('keypress.bootstrap3Typeahead')\r\n                .unbind('propertychange.bootstrap3Typeahead input.bootstrap3Typeahead')\r\n                .unbind('keyup.bootstrap3Typeahead');\r\n\r\n            if (this.eventSupported('keydown')) {\r\n                this.$element.unbind('keydown.bootstrap3-typeahead');\r\n            }\r\n\r\n            this.$menu.remove();\r\n            this.destroyed = true;\r\n        },\r\n\r\n        eventSupported: function (eventName) {\r\n            var isSupported = eventName in this.$element;\r\n            if (!isSupported) {\r\n                this.$element.setAttribute(eventName, 'return;');\r\n                isSupported = typeof this.$element[eventName] === 'function';\r\n            }\r\n            return isSupported;\r\n        },\r\n\r\n        move: function (e) {\r\n            if (!this.shown) {\r\n                return;\r\n            }\r\n\r\n            switch (e.keyCode) {\r\n                case 9: // tab\r\n                case 13: // enter\r\n                case 27: // escape\r\n                    e.preventDefault();\r\n                    break;\r\n\r\n                case 38: // up arrow\r\n                    // with the shiftKey (this is actually the left parenthesis)\r\n                    if (e.shiftKey) {\r\n                        return;\r\n                    }\r\n                    e.preventDefault();\r\n                    this.prev();\r\n                    break;\r\n\r\n                case 40: // down arrow\r\n                    // with the shiftKey (this is actually the right parenthesis)\r\n                    if (e.shiftKey) {\r\n                        return;\r\n                    }\r\n                    e.preventDefault();\r\n                    this.next();\r\n                    break;\r\n            }\r\n        },\r\n\r\n        keydown: function (e) {\r\n            /**\r\n             * Prevent to make an ajax call while copying and pasting.\r\n             *\r\n             * @author Simone Sacchi\r\n             * @version 2018/01/18\r\n             */\r\n            if (e.keyCode === 17) { // ctrl\r\n                return;\r\n            }\r\n            this.keyPressed = true;\r\n            this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40, 38, 9, 13, 27]);\r\n            if (!this.shown && e.keyCode == 40) {\r\n                this.lookup();\r\n            } else {\r\n                this.move(e);\r\n            }\r\n        },\r\n\r\n        keypress: function (e) {\r\n            if (this.suppressKeyPressRepeat) {\r\n                return;\r\n            }\r\n            this.move(e);\r\n        },\r\n\r\n        input: function (e) {\r\n            // This is a fixed for IE10/11 that fires the input event when a placehoder is changed\r\n            // (https://connect.microsoft.com/IE/feedback/details/810538/ie-11-fires-input-event-on-focus)\r\n            var currentValue = this.$element.val() || this.$element.text();\r\n            if (this.value !== currentValue) {\r\n                this.value = currentValue;\r\n                this.lookup();\r\n            }\r\n        },\r\n\r\n        keyup: function (e) {\r\n            if (this.destroyed) {\r\n                return;\r\n            }\r\n            switch (e.keyCode) {\r\n                case 40: // down arrow\r\n                case 38: // up arrow\r\n                case 16: // shift\r\n                case 17: // ctrl\r\n                case 18: // alt\r\n                    break;\r\n\r\n                case 9: // tab\r\n                    if (!this.shown || (this.showHintOnFocus && !this.keyPressed)) {\r\n                        return;\r\n                    }\r\n                    this.select();\r\n                    break;\r\n                case 13: // enter\r\n                    if (!this.shown) {\r\n                        return;\r\n                    }\r\n                    this.select();\r\n                    break;\r\n\r\n                case 27: // escape\r\n                    if (!this.shown) {\r\n                        return;\r\n                    }\r\n                    this.hide();\r\n                    break;\r\n            }\r\n\r\n        },\r\n\r\n        focus: function (e) {\r\n            if (!this.focused) {\r\n                this.focused = true;\r\n                this.keyPressed = false;\r\n                if (this.options.showHintOnFocus && this.skipShowHintOnFocus !== true) {\r\n                    if (this.options.showHintOnFocus === 'all') {\r\n                        this.lookup('');\r\n                    } else {\r\n                        this.lookup();\r\n                    }\r\n                }\r\n            }\r\n            if (this.skipShowHintOnFocus) {\r\n                this.skipShowHintOnFocus = false;\r\n            }\r\n        },\r\n\r\n        blur: function (e) {\r\n            if (!this.mousedover && !this.mouseddown && this.shown) {\r\n                if (this.selectOnBlur) {\r\n                    this.select();\r\n                }\r\n                this.hide();\r\n                this.focused = false;\r\n                this.keyPressed = false;\r\n            } else if (this.mouseddown) {\r\n                // This is for IE that blurs the input when user clicks on scroll.\r\n                // We set the focus back on the input and prevent the lookup to occur again\r\n                this.skipShowHintOnFocus = true;\r\n                this.$element.focus();\r\n                this.mouseddown = false;\r\n            }\r\n        },\r\n\r\n        click: function (e) {\r\n            e.preventDefault();\r\n            this.skipShowHintOnFocus = true;\r\n            this.select();\r\n            this.$element.focus();\r\n            this.hide();\r\n        },\r\n\r\n        mouseenter: function (e) {\r\n            this.mousedover = true;\r\n            this.$menu.find('.active').removeClass('active');\r\n            $(e.currentTarget).addClass('active');\r\n        },\r\n\r\n        mouseleave: function (e) {\r\n            this.mousedover = false;\r\n            if (!this.focused && this.shown) {\r\n                this.hide();\r\n            }\r\n        },\r\n\r\n        /**\r\n         * We track the mousedown for IE. When clicking on the menu scrollbar, IE makes the input blur thus hiding the menu.\r\n         */\r\n        mousedown: function (e) {\r\n            this.mouseddown = true;\r\n            this.$menu.one('mouseup', function (e) {\r\n                // IE won't fire this, but FF and Chrome will so we reset our flag for them here\r\n                this.mouseddown = false;\r\n            }.bind(this));\r\n        },\r\n\r\n        touchstart: function (e) {\r\n            e.preventDefault();\r\n            this.$menu.find('.active').removeClass('active');\r\n            $(e.currentTarget).addClass('active');\r\n        },\r\n\r\n        touchend: function (e) {\r\n            e.preventDefault();\r\n            this.select();\r\n            this.$element.focus();\r\n        }\r\n\r\n    };\r\n\r\n\r\n    /* TYPEAHEAD PLUGIN DEFINITION\r\n     * =========================== */\r\n\r\n    var old = $.fn.typeahead;\r\n\r\n    $.fn.typeahead = function (option) {\r\n        var arg = arguments;\r\n        if (typeof option == 'string' && option == 'getActive') {\r\n            return this.data('active');\r\n        }\r\n        return this.each(function () {\r\n            var $this = $(this);\r\n            var data = $this.data('typeahead');\r\n            var options = typeof option == 'object' && option;\r\n            if (!data) {\r\n                $this.data('typeahead', (data = new Typeahead(this, options)));\r\n            }\r\n            if (typeof option == 'string' && data[option]) {\r\n                if (arg.length > 1) {\r\n                    data[option].apply(data, Array.prototype.slice.call(arg, 1));\r\n                } else {\r\n                    data[option]();\r\n                }\r\n            }\r\n        });\r\n    };\r\n\r\n    Typeahead.defaults = {\r\n        source: [],\r\n        items: 8,\r\n        minLength: 1,\r\n        scrollHeight: 0,\r\n        autoSelect: true,\r\n        afterSelect: $.noop,\r\n        afterEmptySelect: $.noop,\r\n        addItem: false,\r\n        followLinkOnSelect: false,\r\n        delay: 0,\r\n        separator: 'category',\r\n        changeInputOnSelect: true,\r\n        changeInputOnMove: true,\r\n        openLinkInNewTab: false,\r\n        selectOnBlur: true,\r\n        showCategoryHeader: true,\r\n        theme: \"bootstrap3\",\r\n        themes: {\r\n        bootstrap3: {\r\n            menu: '<ul class=\"typeahead dropdown-menu\" role=\"listbox\"></ul>',\r\n            item: '<li><a class=\"dropdown-item\" href=\"#\" role=\"option\"></a></li>',\r\n            itemContentSelector: \"a\",\r\n            headerHtml: '<li class=\"dropdown-header\"></li>',\r\n            headerDivider: '<li class=\"divider\" role=\"separator\"></li>'\r\n        },\r\n        bootstrap4: {\r\n            menu: '<div class=\"typeahead dropdown-menu\" role=\"listbox\"></div>',\r\n            item: '<button class=\"dropdown-item\" role=\"option\"></button>',\r\n            itemContentSelector: '.dropdown-item',\r\n            headerHtml: '<h6 class=\"dropdown-header\"></h6>',\r\n            headerDivider: '<div class=\"dropdown-divider\"></div>'\r\n        }\r\n    }\r\n};\r\n\r\n    $.fn.typeahead.Constructor = Typeahead;\r\n\r\n    /* TYPEAHEAD NO CONFLICT\r\n     * =================== */\r\n\r\n    $.fn.typeahead.noConflict = function () {\r\n        $.fn.typeahead = old;\r\n        return this;\r\n    };\r\n\r\n\r\n    /* TYPEAHEAD DATA-API\r\n     * ================== */\r\n\r\n    $(document).on('focus.typeahead.data-api', '[data-provide=\"typeahead\"]', function (e) {\r\n        var $this = $(this);\r\n        if ($this.data('typeahead')) {\r\n            return;\r\n        }\r\n        $this.typeahead($this.data());\r\n    });\r\n\r\n}));\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/validate/jquery.validate.extend.js",
    "content": "/*this is basic form validation using for validation person's basic information author:Clara Guo data:2017/07/20*/\r\n$(document).ready(function(){\r\n\t$.validator.setDefaults({       \r\n\t\tsubmitHandler: function(form) {    \r\n\t\t\tform.submit();    \r\n\t\t}       \r\n\t});\r\n\t// 非法字符验证\r\n\tjQuery.validator.addMethod(\"specialSign\",function(value,element) {\r\n\t\tvar char = /^[^<>\"'|\\\\]+$/;\r\n\t\treturn this.optional(element) || (char.test(value));\r\n\t},\"不能包含非法字符：< > \\\" ' \\\\\\ |\");\r\n\t// 手机号码验证身份证正则合并：(^\\d{15}$)|(^\\d{17}([0-9]|X)$)\r\n\tjQuery.validator.addMethod(\"isPhone\",function(value,element) {\r\n\t\tvar length = value.length;\r\n\t\tvar phone = /^1[3-9]\\d{9}$/;\r\n\t\treturn this.optional(element)||(length == 11 && phone.test(value));\r\n\t},\"请填写正确的11位手机号\");\r\n\t// 电话号码验证\r\n\tjQuery.validator.addMethod(\"isTel\",function(value,element) {\r\n\t\tvar tel = /^(0\\d{2,3}-)?\\d{7,8}$/g;//区号3,4位,号码7,8位\r\n\t\treturn this.optional(element) || (tel.test(value));\r\n\t},\"请填写正确的座机号码\");\r\n\t// 姓名校验\r\n\tjQuery.validator.addMethod(\"isName\",function(value,element) {\r\n\t\tvar name = /^[\\u4e00-\\u9fa5]{2,6}$/;\r\n\t\treturn this.optional(element) || (name.test(value));\r\n\t},\"姓名只能用汉字,长度2-4位\");\r\n\t// 校验用户名\r\n\tjQuery.validator.addMethod(\"isUserName\",function(value,element) {\r\n\t\tvar userName = /^[a-zA-Z0-9]{2,13}$/;\r\n\t\treturn this.optional(element) || (userName).test(value);\r\n\t},'请输入数字或者字母,不包含特殊字符');\r\n\t// 校验身份证\r\n\tjQuery.validator.addMethod(\"isIdentity\",function(value,element) {\r\n\t\tvar id = /^(\\d{15}$|^\\d{18}$|^\\d{17}(\\d|X))$/;\r\n\t\treturn this.optional(element) || (id.test(value));\r\n\t},\"请输入正确的15或18位身份证号,末尾若为X请大写\");\r\n\t// 校验二代身份证\r\n\tjQuery.validator.addMethod(\"isIdentity18\",function(value,element) {\r\n\t\tvar id = /^(^\\d{17}(\\d|X))$/;\r\n\t\treturn this.optional(element) || (id.test(value));\r\n\t},\"请输入正确的18位身份证号，末尾若为X请大写\");\r\n\t// 校验出生日期\r\n\tjQuery.validator.addMethod(\"isBirth\",function(value,element) {\r\n\t\tvar birth = /^(19|20)\\d{2}-(1[0-2]|0?[1-9])-(0?[1-9]|[1-2][0-9]|3[0-1])$/;\r\n\t\treturn this.optional(element) || (birth).test(value);\r\n\t},\"出生日期格式示例2000-01-01\");\r\n\t// 校验IP地址\r\n\tjQuery.validator.addMethod(\"isIp\",function(value,element) {\r\n\t\tvar ip = /^(?:(?:2[0-4][0-9]\\.)|(?:25[0-5]\\.)|(?:1[0-9][0-9]\\.)|(?:[1-9][0-9]\\.)|(?:[0-9]\\.)){3}(?:(?:2[0-4][0-9])|(?:25[0-5])|(?:1[0-9][0-9])|(?:[1-9][0-9])|(?:[0-9]))$/;\r\n\t\treturn this.optional(element) || (ip).test(value);\r\n\t},\"IP地址格式示例127.0.0.1\");\r\n\tjQuery.validator.addMethod(\"notEqual\", function(value, element, param) {\r\n        return value != param;\r\n    }, $.validator.format(\"输入值不允许为{0}\"));\r\n\tjQuery.validator.addMethod(\"gt\", function(value, element, param) {\r\n        return value > param;\r\n    }, $.validator.format(\"输入值必须大于{0}\"));\r\n\t// 校验新旧密码是否相同\r\n\tjQuery.validator.addMethod(\"isdiff\",function(){\r\n\t\tvar p1=$(\"#pwdOld\").val();\r\n\t\tvar p2=$(\"#pwdNew\").val();\r\n\t\tif(p1==p2){\r\n\t\t\treturn false;\r\n\t\t}else{\r\n\t\t\t return true;\r\n\t\t}\r\n\t\t});\r\n\t// 校验新密码和确认密码是否相同\r\n\tjQuery.validator.addMethod(\"issame\",function(){\r\n\t\tvar p3=$(\"#confirm_password\").val();\r\n\t\tvar p4=$(\"#pwdNew\").val();\r\n\t\tif(p3==p4){\r\n\t\t\treturn true;\r\n\t\t}else{\r\n\t\t\t return false;\r\n\t\t}\r\n\t\t});\r\n\t// 校验基础信息表单\r\n\t$(\"#basicInfoForm\").validate({\r\n\t\terrorElement:'span',\r\n\t\terrorClass:'help-block error-mes',\r\n\t\trules:{\r\n\t\t\tname:{\r\n\t\t\t\trequired:true,\r\n\t\t\t\tisName:true\r\n\t\t\t},\r\n\t\t\tsex:\"required\",\r\n\t\t\tbirth:\"required\",\r\n            mobile:{\r\n\t\t\t\trequired:true,\r\n\t\t\t\tisPhone:true\r\n\t\t\t},\r\n\t\t\temail:{\r\n\t\t\t\trequired:true,\r\n\t\t\t\temail:true\r\n\t\t\t}\r\n\t\t},\r\n\t\tmessages:{\r\n\t\t\tname:{\r\n\t\t\t\trequired:\"请输入中文姓名\",\r\n\t\t\t\tisName:\"姓名只能为汉字\"\r\n\t\t\t},\r\n\t\t\tsex:{\r\n\t\t\t\trequired:\"请输入性别\"\r\n\t\t\t},\r\n\t\t\tbirth:{\r\n\t\t\t\trequired:\"请输入出生年月\"\r\n\t\t\t},\r\n            mobile:{\r\n\t\t\t\trequired:\"请输入手机号\",\r\n\t\t\t\tisPhone:\"请填写正确的11位手机号\"\r\n\t\t\t},\r\n\t\t\temail:{\r\n\t\t\t\trequired:\"请输入邮箱\",\r\n\t\t\t\temail:\"请填写正确的邮箱格式\"\r\n\t\t\t}\r\n\t\t},\r\n\t\r\n\t\terrorPlacement:function(error,element){\r\n\t\t\telement.next().remove();\r\n\t\t\telement.closest('.gg-formGroup').append(error);\r\n\t\t},\r\n\t\t\r\n\t\thighlight:function(element){\r\n\t\t\t$(element).closest('.gg-formGroup').addClass('has-error has-feedback');\r\n\t\t},\r\n\t\tsuccess:function(label){\r\n\t\t\tvar el = label.closest('.gg-formGroup').find(\"input\");\r\n\t\t\tel.next().remove();\r\n\t\t\tlabel.closest('.gg-formGroup').removeClass('has-error').addClass(\"has-feedback has-success\");\r\n\t\t\tlabel.remove();\r\n\t\t},\r\n\t\tsubmitHandler:function(form){\r\n\t\t\talert(\"保存成功!\");\r\n\t\t}\r\n\t});\r\n\t\r\n\t// 校验修改密码表单\r\n\t$(\"#modifyPwd\").validate({\r\n\t\tonfocusout: function(element) { $(element).valid()},\r\n\t\t debug:false,   // 表示校验通过后是否直接提交表单\r\n\t\t onkeyup:false, // 表示按键松开时候监听验证\r\n\t\trules:{\r\n\t\t\tpwdOld:{\r\n\t\t\t\trequired:true,\r\n\t\t\t\tminlength:6\r\n\t\t\t},\r\n            pwdNew:{\r\n\t\t\t   required:true,\r\n\t\t\t   minlength:6,\r\n\t\t\t   isdiff:true,\r\n\t\t\t   //issame:true,\r\n\t\t   },\r\n\t\t\tconfirm_password:{\r\n\t\t\t  required:true,\r\n\t\t\t  minlength:6,\r\n\t\t\t  issame:true,\r\n\t\t\t}\r\n\t\t  \r\n\t\t   },\r\n\t\tmessages:{\r\n\t\t\t \tpwdOld : {\r\n\t\t\t\t\t required:'必填',\r\n\t\t\t\t\t minlength:$.validator.format('密码长度要大于6')\r\n\t\t\t\t},\r\n            \tpwdNew:{\r\n\t\t\t\t   required:'必填',\r\n\t\t\t\t   minlength:$.validator.format('密码长度要大于6'),\r\n\t\t\t\t   isdiff:'原密码与新密码不能重复',\r\n\t\t\t\t  \r\n\t\t\t   },\r\n\t\t\t\tconfirm_password:{\r\n\t\t\t\t   required:'必填',\r\n\t\t\t\t   minlength:$.validator.format('密码长度要大于6'),\r\n\t\t\t\t   issame:'新密码要与确认新密码一致',\r\n\t\t\t\t}\r\n\t\t\r\n\t\t},\r\n\t\terrorElement:\"mes\",\r\n\t\terrorClass:\"gg-star\",\r\n\t\terrorPlacement: function(error, element) \r\n\t\t{ \r\n\t\t\telement.closest('.gg-formGroup').append(error);\r\n\r\n\t\t}\r\n\t});\r\n});"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ajax/libs/validate/messages_zh.js",
    "content": "/*\r\n * Translated default messages for the jQuery validation plugin.\r\n * Locale: ZH (Chinese, 中文 (Zhōngwén), 汉语, 漢語)\r\n */\r\nvar icon = \"<i class='fa fa-times-circle'></i>  \";\r\n$.extend($.validator.messages, {\r\n\trequired: icon + \"必填\",\r\n\tremote: icon + \"请修正此字段\",\r\n\temail: icon + \"请输入有效的电子邮件\",\r\n\turl: icon + \"请输入有效的网址\",\r\n\tdate: icon + \"请输入有效的日期\",\r\n\tdateISO: icon + \"请输入有效的日期 (YYYY-MM-DD)\",\r\n\tnumber: icon + \"请输入有效的数字\",\r\n\tdigits: icon + \"只能输入数字\",\r\n\tcreditcard: icon + \"请输入有效的信用卡号码\",\r\n\tequalTo: icon + \"你的输入不相同\",\r\n\textension: icon + \"请输入有效的后缀\",\r\n\tmaxlength: $.validator.format(icon + \"最多可以输入 {0} 个字符\"),\r\n\tminlength: $.validator.format(icon + \"最少要输入 {0} 个字符\"),\r\n\trangelength: $.validator.format(icon + \"请输入长度在 {0} 到 {1} 之间的字符串\"),\r\n\trange: $.validator.format(icon + \"请输入范围在 {0} 到 {1} 之间的数值\"),\r\n\tstep: $.validator.format(icon + \"请输入 {0} 的整数倍值\" ),\r\n\tmax: $.validator.format(icon + \"请输入不大于 {0} 的数值\"),\r\n\tmin: $.validator.format(icon + \"请输入不小于 {0} 的数值\")\r\n});\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/css/login.css",
    "content": "html {\r\n\theight:100%\r\n}\r\nbody.signin {\r\n\theight:auto;\r\n\tbackground:url(../img/login-background.jpg) no-repeat center fixed;\r\n\t-webkit-background-size:cover;\r\n\t-moz-background-size:cover;\r\n\t-o-background-size:cover;\r\n\tbackground-size:cover\r\n}\r\n.signinpanel {\r\n\twidth:750px;\r\n\tmargin:10% auto 0;\r\n\tcolor:rgba(255,255,255,.95)\r\n}\r\n.signinpanel .logopanel {\r\n\tfloat:none;\r\n\twidth:auto;\r\n\tpadding:0;\r\n\tbackground:0 0\r\n}\r\n.signinpanel .signin-info ul {\r\n\tlist-style:none;\r\n\tpadding:0;\r\n\tmargin:20px 0\r\n}\r\n.signinpanel .form-control {\r\n\tdisplay:block;\r\n\tmargin-top:15px\r\n}\r\n.signinpanel .uname {\r\n\tbackground:#fff url(../img/user.png) no-repeat 95% center;\r\n\tcolor:#333\r\n}\r\n.signinpanel .pword {\r\n\tbackground:#fff url(../img/locked.png) no-repeat 95% center;\r\n\tcolor:#333\r\n}\r\n.signinpanel .code {\r\n    background: #fff no-repeat 95% center;color:#333; margin:0 0 15px 0;\r\n}\r\n.signinpanel .btn {\r\n\tmargin-top:15px\r\n}\r\n.signinpanel form {\r\n\tbackground:rgba(255,255,255,.2);\r\n\tborder:1px solid rgba(255,255,255,.3);\r\n\t-moz-box-shadow:0 3px 0 rgba(12,12,12,.03);\r\n\t-webkit-box-shadow:0 3px 0 rgba(12,12,12,.03);\r\n\tbox-shadow:0 3px 0 rgba(12,12,12,.03);\r\n\t-moz-border-radius:3px;\r\n\t-webkit-border-radius:3px;\r\n\tborder-radius:3px;\r\n\tpadding:30px\r\n}\r\n.signup-footer {\r\n\tborder-top:solid 1px rgba(255,255,255,.3);\r\n\tmargin:20px 0;\r\n\tpadding-top:15px\r\n}\r\n@media screen and (max-width:768px) {\r\n\t.signinpanel,.signuppanel {\r\n\tmargin:0 auto;\r\n\twidth:380px!important;\r\n\tpadding:20px\r\n}\r\n.signinpanel form {\r\n\tmargin-top:20px\r\n}\r\n.signup-footer,.signuppanel .form-control {\r\n\tmargin-bottom:10px\r\n}\r\n.signup-footer .pull-left,.signup-footer .pull-right {\r\n\tfloat:none!important;\r\n\ttext-align:center\r\n}\r\n.signinpanel .signin-info ul {\r\n\tdisplay:none\r\n}\r\n}@media screen and (max-width:320px) {\r\n\t.signinpanel,.signuppanel {\r\n\tmargin:0 20px;\r\n\twidth:auto\r\n}\r\n}\r\n/*\r\n登录界面check样式\r\n*/\r\n.checkbox-custom {\r\n    position: relative;\r\n    padding: 0 15px 0 25px;\r\n    margin-bottom: 7px;\r\n    display: inline-block;\r\n}\r\n/*\r\n将初始的checkbox的样式改变\r\n*/\r\n.checkbox-custom input[type=\"checkbox\"] {\r\n    opacity: 0; /*将初始的checkbox隐藏起来*/\r\n    position: absolute;\r\n    cursor: pointer;\r\n    z-index: 2;\r\n    margin: -6px 0 0 0;\r\n    top: 50%;\r\n    left: 3px;\r\n}\r\n/*\r\n设计新的checkbox，位置\r\n*/\r\n.checkbox-custom label:before {\r\n    content: '';\r\n    position: absolute;\r\n    top: 50%;\r\n    left: 0;\r\n    margin-top: -9px;\r\n    width: 18px;\r\n    height: 17px;\r\n    display: inline-block;\r\n    border-radius: 2px;\r\n    border: 1px solid #bbb;\r\n    background: #fff;\r\n}\r\n/*\r\n点击初始的checkbox，将新的checkbox关联起来\r\n*/\r\n.checkbox-custom input[type=\"checkbox\"]:checked +label:after {\r\n    position: absolute;\r\n    display: inline-block;\r\n    font-family: 'Glyphicons Halflings';\r\n    content: \"\\e013\";\r\n    top: 42%;\r\n    left: 3px;\r\n    margin-top: -5px;\r\n    font-size: 11px;\r\n    line-height: 1;\r\n    width: 16px;\r\n    height: 16px;\r\n    color: #333;\r\n}\r\n.checkbox-custom label {\r\n    cursor: pointer;\r\n    line-height: 1.2;\r\n    font-weight: normal; /*改变了rememberme的字体*/\r\n    margin-bottom: 0;\r\n    text-align: left;\r\n}\r\n\r\n.form-control, .form-control:focus, .has-error .form-control:focus,  .has-success .form-control:focus, .has-warning .form-control:focus,  .navbar-collapse, .navbar-form, .navbar-form-custom .form-control:focus,  .navbar-form-custom .form-control:hover, .open .btn.dropdown-toggle,  .panel, .popover, .progress, .progress-bar {\r\n    box-shadow: none;\r\n}\r\n\r\n.form-control {\r\n    border-radius: 1px!important;\r\n    padding: 6px 12px!important;\r\n    height: 34px!important;\r\n}\r\n\r\n.form-control:focus {\r\n    border-color: #1ab394 !important;\r\n}\r\n\r\nbody .layer-ext-moon-msg[type=\"dialog\"]{\r\n    min-width: 100px !important;\r\n}\r\nbody .layer-ext-moon-msg { \r\n    background-color: rgba(0,0,0,0.6);\r\n    color: #fff;\r\n    border: none;\r\n}\r\n\r\nbody .layer-ext-moon-msg .layui-layer-content{ \r\n    padding: 12px 25px;\r\n    text-align: center;\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/css/skins.css",
    "content": "﻿/*\n *\n *   SKIN blue 若依管理系统\n *   NAME - blue/green/purple/red/yellow\n *\n*/\n.nav-tabs {\n    border-bottom: 0px;\n}\n\n.navbar .navbar-toolbar>li>a {\n    border: none !important;\n}\n\n/** 蓝色主题 skin-blue **/\n.navbar, .skin-blue .navbar {\n\tbackground-color: #3c8dbc\n}\n\n.skin-blue .navbar-default .nav>li.selected>a,\n.skin-blue .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #1890ff;\n    color: rgba(255,255,255,1);\n}\n\n.skin-blue .navbar .nav>li>a {\n\tcolor: #fff\n}\n\n.skin-blue .navbar .nav>li>a:hover,\n.skin-blue .navbar .nav>li>a:active,\n.skin-blue .navbar .nav>li>a:focus,\n.skin-blue .navbar .nav .open>a,\n.skin-blue .navbar .nav .open>a:hover,\n.skin-blue .navbar .nav .open>a:focus,\n.skin-blue .navbar .nav>.active>a {\n\tbackground: rgba(0, 0, 0, 0.1);\n\tcolor: #f6f6f6\n}\n\n.skin-blue .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-blue .navbar .sidebar-toggle:hover {\n\tcolor: #f6f6f6;\n\tbackground: rgba(0, 0, 0, 0.1)\n}\n\n.skin-blue .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-blue .navbar .sidebar-toggle:hover {\n\tbackground-color: #367fa9\n}\n\n@media ( max-width :767px) {\n\t.skin-blue .navbar .dropdown-menu li.divider {\n\t\tbackground-color: rgba(255, 255, 255, 0.1)\n\t}\n\t.skin-blue .navbar .dropdown-menu li a {\n\t\tcolor: #fff\n\t}\n\t.skin-blue .navbar .dropdown-menu li a:hover {\n\t\tbackground: #367fa9\n\t}\n}\n\n.skin-blue .logo {\n\tbackground-color: #367fa9;\n\tcolor: #fff;\n\tborder-bottom: 0 solid transparent\n}\n\n.skin-blue .logo:hover {\n\tbackground-color: #357ca5\n}\n\n.skin-blue li.user-header {\n\tbackground-color: #3c8dbc\n}\n\n.skin-blue .content-header {\n\tbackground: transparent\n}\n\n.skin-blue .wrapper,\n.skin-blue .main-sidebar,\n.skin-blue .left-side {\n\tbackground-color: #222d32\n}\n\n.skin-blue .user-panel>.info,\n.skin-blue .user-panel>.info>a {\n\tcolor: #fff\n}\n\n.skin-blue .nav>li.header {\n\tcolor: #4b646f;\n\tbackground: #1a2226\n}\n\n.skin-blue .nav:not(.navbar-toolbar)>li.active {\n\tcolor: #fff;\n\tbackground: #293846;\n\tborder-left: 3px solid #3c8dbc;\n}\n\n.skin-blue .nav>li.active>ul li.active {\n\tborder-left: none;\n}\n\n.skin-blue .dropdown-menu > .active > a, .skin-blue .dropdown-menu > .active > a:hover, .skin-blue .dropdown-menu > .active > a:focus {\n    color: #fff !important;\n    text-decoration: none;\n    outline: 0;\n    background-color: #3c8dbc;\n}\n\n.skin-blue .sidebar a {\n\tcolor: #b8c7ce\n}\n\n.skin-blue .sidebar a:hover {\n\ttext-decoration: none\n}\n\n.skin-blue .sidebar-form {\n\tborder-radius: 3px;\n\tborder: 1px solid #374850;\n\tmargin: 10px 10px\n}\n\n.skin-blue .sidebar-form input[type=\"text\"],\n.skin-blue .sidebar-form .btn {\n\tbox-shadow: none;\n\tbackground-color: #374850;\n\tborder: 1px solid transparent;\n\theight: 35px\n}\n\n.skin-blue .sidebar-form input[type=\"text\"] {\n\tcolor: #666;\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 0;\n\tborder-bottom-right-radius: 0;\n\tborder-bottom-left-radius: 2px\n}\n\n.skin-blue .sidebar-form input[type=\"text\"]:focus,\n.skin-blue .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tbackground-color: #fff;\n\tcolor: #666\n}\n\n.skin-blue .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tborder-left-color: #fff\n}\n\n.skin-blue .sidebar-form .btn {\n\tcolor: #999;\n\tborder-top-left-radius: 0;\n\tborder-top-right-radius: 2px;\n\tborder-bottom-right-radius: 2px;\n\tborder-bottom-left-radius: 0\n}\n\n.skin-blue.layout-top-nav>.logo {\n\tbackground-color: #3c8dbc;\n\tcolor: #fff;\n\tborder-bottom: 0 solid transparent\n}\n\n.skin-blue.layout-top-nav>.logo:hover {\n\tbackground-color: #3b8ab8\n}\n\n.skin-blue .content-tabs {\n\tborder-bottom: 1px solid #e5e5e5;\n}\n\n.skin-blue.layout-top-nav>.logo {\n\tbackground-color: #3c8dbc;\n\tcolor: #fff;\n\tborder-bottom: 0 solid transparent\n}\n\n.skin-blue.layout-top-nav>.logo:hover {\n\tbackground-color: #3b8ab8\n}\n\n/** 绿色主题 skin-green **/\n.skin-green .navbar {\n\tbackground-color: #00a65a;\n}\n\n.skin-green .navbar-default .nav>li.selected>a,\n.skin-green .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #52c41a;\n    color: rgba(255,255,255,1);\n}\n\n.skin-green .content-tabs {\n\tborder-bottom: 1px solid #e5e5e5;\n}\n\n.skin-green .navbar .nav>li>a {\n\tcolor: #fff\n}\n\n.skin-green .navbar .nav>li>a:hover,\n.skin-green .navbar .nav>li>a:active,\n.skin-green .navbar .nav>li>a:focus,\n.skin-green .navbar .nav .open>a,\n.skin-green .navbar .nav .open>a:hover,\n.skin-green .navbar .nav .open>a:focus,\n.skin-green .navbar .nav>.active>a {\n\tbackground: rgba(0, 0, 0, 0.1);\n\tcolor: #f6f6f6\n}\n\n.skin-green .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-green .navbar .sidebar-toggle:hover {\n\tcolor: #f6f6f6;\n\tbackground: rgba(0, 0, 0, 0.1)\n}\n\n.skin-green .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-green .navbar .sidebar-toggle:hover {\n\tbackground-color: #008d4c\n}\n\n@media ( max-width :767px) {\n\t.skin-green .navbar .dropdown-menu li.divider {\n\t\tbackground-color: rgba(255, 255, 255, 0.1)\n\t}\n\t.skin-green .navbar .dropdown-menu li a {\n\t\tcolor: #fff\n\t}\n\t.skin-green .navbar .dropdown-menu li a:hover {\n\t\tbackground: #008d4c\n\t}\n}\n\n.skin-green .logo {\n\tbackground-color: #008d4c;\n\tcolor: #fff;\n\tborder-bottom: 0 solid transparent\n}\n\n.skin-green .logo:hover {\n\tbackground-color: #008749\n}\n\n.skin-green li.user-header {\n\tbackground-color: #00a65a\n}\n\n.skin-green .content-header {\n\tbackground: transparent\n}\n\n.skin-green .wrapper,\n.skin-green .main-sidebar,\n.skin-green .left-side {\n\tbackground-color: #222d32\n}\n\n.skin-green .user-panel>.info,\n.skin-green .user-panel>.info>a {\n\tcolor: #fff\n}\n\n.skin-green .nav>li.header {\n\tcolor: #4b646f;\n\tbackground: #1a2226;\n}\n\n.skin-green .nav:not(.navbar-toolbar)>li.active {\n\tcolor: #fff;\n\tbackground: #293846;\n\tborder-left: 3px solid #00a65a;\n}\n\n.skin-green .nav>li.active>ul li.active {\n\tborder-left: none;\n}\n\n.skin-green .dropdown-menu > .active > a, .skin-green .dropdown-menu > .active > a:hover, .skin-green .dropdown-menu > .active > a:focus {\n    color: #fff !important;\n    text-decoration: none;\n    outline: 0;\n    background-color: #00a65a;\n}\n\n.skin-green .sidebar a {\n\tcolor: #b8c7ce\n}\n\n.skin-green .sidebar a:hover {\n\ttext-decoration: none\n}\n\n.skin-green .sidebar-form {\n\tborder-radius: 3px;\n\tborder: 1px solid #374850;\n\tmargin: 10px 10px\n}\n\n.skin-green .sidebar-form input[type=\"text\"],\n.skin-green .sidebar-form .btn {\n\tbox-shadow: none;\n\tbackground-color: #374850;\n\tborder: 1px solid transparent;\n\theight: 35px\n}\n\n.skin-green .sidebar-form input[type=\"text\"] {\n\tcolor: #666;\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 0;\n\tborder-bottom-right-radius: 0;\n\tborder-bottom-left-radius: 2px\n}\n\n.skin-green .sidebar-form input[type=\"text\"]:focus,\n.skin-green .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tbackground-color: #fff;\n\tcolor: #666\n}\n\n.skin-green .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tborder-left-color: #fff\n}\n\n.skin-green .sidebar-form .btn {\n\tcolor: #999;\n\tborder-top-left-radius: 0;\n\tborder-top-right-radius: 2px;\n\tborder-bottom-right-radius: 2px;\n\tborder-bottom-left-radius: 0\n}\n\n/** 红色主题 skin-red **/\n.skin-red .navbar {\n\tbackground-color: #dd4b39\n}\n\n.skin-red .navbar-default .nav>li.selected>a,\n.skin-red .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #f5222d;\n    color: rgba(255,255,255,1);\n}\n\n.skin-red .navbar .nav>li>a {\n\tcolor: #fff\n}\n\n.skin-red .navbar .nav>li>a:hover,\n.skin-red .navbar .nav>li>a:active,\n.skin-red .navbar .nav>li>a:focus,\n.skin-red .navbar .nav .open>a,\n.skin-red .navbar .nav .open>a:hover,\n.skin-red .navbar .nav .open>a:focus,\n.skin-red .navbar .nav>.active>a {\n\tbackground: rgba(0, 0, 0, 0.1);\n\tcolor: #f6f6f6\n}\n\n.skin-red .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-red .navbar .sidebar-toggle:hover {\n\tcolor: #f6f6f6;\n\tbackground: rgba(0, 0, 0, 0.1)\n}\n\n.skin-red .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-red .navbar .sidebar-toggle:hover {\n\tbackground-color: #d73925\n}\n\n@media ( max-width :767px) {\n\t.skin-red .navbar .dropdown-menu li.divider {\n\t\tbackground-color: rgba(255, 255, 255, 0.1)\n\t}\n\t.skin-red .navbar .dropdown-menu li a {\n\t\tcolor: #fff\n\t}\n\t.skin-red .navbar .dropdown-menu li a:hover {\n\t\tbackground: #d73925\n\t}\n}\n\n.skin-red .logo {\n\tbackground-color: #d73925;\n\tcolor: #fff;\n\tborder-bottom: 0 solid transparent\n}\n\n.skin-red .logo:hover {\n\tbackground-color: #d33724\n}\n\n.skin-red li.user-header {\n\tbackground-color: #dd4b39\n}\n\n.skin-red .content-header {\n\tbackground: transparent\n}\n\n.skin-red .wrapper,\n.skin-red .main-sidebar,\n.skin-red .left-side {\n\tbackground-color: #222d32\n}\n\n.skin-red .user-panel>.info,\n.skin-red .user-panel>.info>a {\n\tcolor: #fff\n}\n\n.skin-red .nav>li.header {\n\tcolor: #4b646f;\n\tbackground: #1a2226\n}\n\n.skin-red .nav:not(.navbar-toolbar)>li.active {\n\tcolor: #fff;\n\tborder-left: 3px solid #dd4b39;\n\tbackground: #293846;\n}\n\n.skin-red .nav>li.active>ul li.active {\n\tborder-left: none;\n}\n\n.skin-red .dropdown-menu > .active > a, .skin-red .dropdown-menu > .active > a:hover, .skin-red .dropdown-menu > .active > a:focus {\n    color: #fff !important;\n    text-decoration: none;\n    outline: 0;\n    background-color: #dd4b39;\n}\n\n.skin-red .content-tabs {\n\tborder-bottom: 1px solid #e5e5e5;\n}\n\n.skin-red .sidebar a {\n\tcolor: #b8c7ce\n}\n\n.skin-red .sidebar a:hover {\n\ttext-decoration: none\n}\n\n.skin-red .sidebar-form {\n\tborder-radius: 3px;\n\tborder: 1px solid #374850;\n\tmargin: 10px 10px\n}\n\n.skin-red .sidebar-form input[type=\"text\"],\n.skin-red .sidebar-form .btn {\n\tbox-shadow: none;\n\tbackground-color: #374850;\n\tborder: 1px solid transparent;\n\theight: 35px\n}\n\n.skin-red .sidebar-form input[type=\"text\"] {\n\tcolor: #fff;\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 0;\n\tborder-bottom-right-radius: 0;\n\tborder-bottom-left-radius: 2px\n}\n\n.skin-red .sidebar-form input[type=\"text\"]:focus,\n.skin-red .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tbackground-color: #fff;\n\tcolor: #666\n}\n\n.skin-red .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tborder-left-color: #fff\n}\n\n.skin-red .sidebar-form .btn {\n\tcolor: #999;\n\tborder-top-left-radius: 0;\n\tborder-top-right-radius: 2px;\n\tborder-bottom-right-radius: 2px;\n\tborder-bottom-left-radius: 0\n}\n\n/** 黄色主题 skin-red **/\n.skin-yellow .navbar {\n\tbackground-color: #f39c12\n}\n\n.skin-yellow .navbar-default .nav>li.selected>a,\n.skin-yellow .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #faad14;\n    color: rgba(255,255,255,1);\n}\n\n.skin-yellow .navbar .nav>li>a {\n\tcolor: #fff\n}\n\n.skin-yellow .navbar .nav>li>a:hover,\n.skin-yellow .navbar .nav>li>a:active,\n.skin-yellow .navbar .nav>li>a:focus,\n.skin-yellow .navbar .nav .open>a,\n.skin-yellow .navbar .nav .open>a:hover,\n.skin-yellow .navbar .nav .open>a:focus,\n.skin-yellow .navbar .nav>.active>a {\n\tbackground: rgba(0, 0, 0, 0.1);\n\tcolor: #f6f6f6\n}\n\n.skin-yellow .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-yellow .navbar .sidebar-toggle:hover {\n\tcolor: #f6f6f6;\n\tbackground: rgba(0, 0, 0, 0.1)\n}\n\n.skin-yellow .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-yellow .navbar .sidebar-toggle:hover {\n\tbackground-color: #e08e0b\n}\n\n@media ( max-width :767px) {\n\t.skin-yellow .navbar .dropdown-menu li.divider {\n\t\tbackground-color: rgba(255, 255, 255, 0.1)\n\t}\n\t.skin-yellow .navbar .dropdown-menu li a {\n\t\tcolor: #fff\n\t}\n\t.skin-yellow .navbar .dropdown-menu li a:hover {\n\t\tbackground: #e08e0b\n\t}\n}\n\n.skin-yellow .logo {\n\tbackground-color: #e08e0b;\n\tcolor: #fff;\n\tborder-bottom: 0 solid transparent\n}\n\n.skin-yellow .logo:hover {\n\tbackground-color: #db8b0b\n}\n\n.skin-yellow li.user-header {\n\tbackground-color: #f39c12\n}\n\n.skin-yellow .content-header {\n\tbackground: transparent\n}\n\n.skin-yellow .wrapper,\n.skin-yellow .main-sidebar,\n.skin-yellow .left-side {\n\tbackground-color: #222d32\n}\n\n.skin-yellow .user-panel>.info,\n.skin-yellow .user-panel>.info>a {\n\tcolor: #fff\n}\n\n.skin-yellow .nav>li.header {\n\tcolor: #4b646f;\n\tbackground: #1a2226\n}\n\n.skin-yellow .nav:not(.navbar-toolbar)>li.active {\n\tcolor: #fff;\n\tbackground: #293846;\n\tborder-left: 3px solid #f39c12;\n}\n\n.skin-yellow .nav>li.active>ul li.active {\n\tborder-left: none;\n}\n\n.skin-yellow .dropdown-menu > .active > a, .skin-yellow .dropdown-menu > .active > a:hover, .skin-yellow .dropdown-menu > .active > a:focus {\n    color: #fff !important;\n    text-decoration: none;\n    outline: 0;\n    background-color: #f39c12;\n}\n\n.skin-yellow .content-tabs {\n\t border-bottom: 1px solid #e5e5e5;\n}\n\n.skin-yellow .sidebar a {\n\tcolor: #b8c7ce\n}\n\n.skin-yellow .sidebar a:hover {\n\ttext-decoration: none\n}\n\n.skin-yellow .sidebar-form {\n\tborder-radius: 3px;\n\tborder: 1px solid #374850;\n\tmargin: 10px 10px\n}\n\n.skin-yellow .sidebar-form input[type=\"text\"],\n.skin-yellow .sidebar-form .btn {\n\tbox-shadow: none;\n\tbackground-color: #374850;\n\tborder: 1px solid transparent;\n\theight: 35px\n}\n\n.skin-yellow .sidebar-form input[type=\"text\"] {\n\tcolor: #666;\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 0;\n\tborder-bottom-right-radius: 0;\n\tborder-bottom-left-radius: 2px\n}\n\n.skin-yellow .sidebar-form input[type=\"text\"]:focus,\n.skin-yellow .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tbackground-color: #fff;\n\tcolor: #666\n}\n\n.skin-yellow .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tborder-left-color: #fff\n}\n\n.skin-yellow .sidebar-form .btn {\n\tcolor: #999;\n\tborder-top-left-radius: 0;\n\tborder-top-right-radius: 2px;\n\tborder-bottom-right-radius: 2px;\n\tborder-bottom-left-radius: 0\n}\n\n/** 紫色主题 skin-purple **/\n.skin-purple .navbar {\n\tbackground-color: #605ca8\n}\n\n.skin-purple .navbar-default .nav>li.selected>a,\n.skin-purple .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #722ed1;\n    color: rgba(255,255,255,1);\n}\n\n.skin-purple .navbar .nav>li>a {\n\tcolor: #fff\n}\n\n.skin-purple .navbar .nav>li>a:hover,\n.skin-purple .navbar .nav>li>a:active,\n.skin-purple .navbar .nav>li>a:focus,\n.skin-purple .navbar .nav .open>a,\n.skin-purple .navbar .nav .open>a:hover,\n.skin-purple .navbar .nav .open>a:focus,\n.skin-purple .navbar .nav>.active>a {\n\tbackground: rgba(0, 0, 0, 0.1);\n\tcolor: #f6f6f6\n}\n\n.skin-purple .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-purple .navbar .sidebar-toggle:hover {\n\tcolor: #f6f6f6;\n\tbackground: rgba(0, 0, 0, 0.1)\n}\n\n.skin-purple .navbar .sidebar-toggle {\n\tcolor: #fff\n}\n\n.skin-purple .navbar .sidebar-toggle:hover {\n\tbackground-color: #555299\n}\n\n@media ( max-width :767px) {\n\t.skin-purple .navbar .dropdown-menu li.divider {\n\t\tbackground-color: rgba(255, 255, 255, 0.1)\n\t}\n\t.skin-purple .navbar .dropdown-menu li a {\n\t\tcolor: #fff\n\t}\n\t.skin-purple .navbar .dropdown-menu li a:hover {\n\t\tbackground: #555299\n\t}\n}\n\n.skin-purple .logo {\n\tbackground-color: #555299;\n\tcolor: #fff;\n\tborder-bottom: 0 solid transparent\n}\n\n.skin-purple .logo:hover {\n\tbackground-color: #545096\n}\n\n.skin-purple li.user-header {\n\tbackground-color: #605ca8\n}\n\n.skin-purple .content-header {\n\tbackground: transparent\n}\n\n.skin-purple .wrapper,\n.skin-purple .main-sidebar,\n.skin-purple .left-side {\n\tbackground-color: #222d32\n}\n\n.skin-purple .user-panel>.info,\n.skin-purple .user-panel>.info>a {\n\tcolor: #fff\n}\n\n.skin-purple .nav>li.header {\n\tcolor: #4b646f;\n\tbackground: #1a2226\n}\n\n.skin-purple .nav:not(.navbar-toolbar)>li.active {\n\tcolor: #fff;\n\tbackground: #293846;\n\tborder-left: 3px solid #605ca8;\n}\n\n.skin-purple .nav>li.active>ul li.active {\n\tborder-left: none;\n}\n\n.skin-purple .dropdown-menu > .active > a, .skin-purple .dropdown-menu > .active > a:hover, .skin-purple .dropdown-menu > .active > a:focus {\n    color: #fff !important;\n    text-decoration: none;\n    outline: 0;\n    background-color: #605ca8;\n}\n\n.skin-purple .content-tabs {\n\t border-bottom: 1px solid #e5e5e5;\n}\n\n.skin-purple .sidebar a {\n\tcolor: #b8c7ce\n}\n\n.skin-purple .sidebar a:hover {\n\ttext-decoration: none\n}\n\n.skin-purple .sidebar-form {\n\tborder-radius: 3px;\n\tborder: 1px solid #374850;\n\tmargin: 10px 10px\n}\n\n.skin-purple .sidebar-form input[type=\"text\"],\n.skin-purple .sidebar-form .btn {\n\tbox-shadow: none;\n\tbackground-color: #374850;\n\tborder: 1px solid transparent;\n\theight: 35px\n}\n\n.skin-purple .sidebar-form input[type=\"text\"] {\n\tcolor: #666;\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 0;\n\tborder-bottom-right-radius: 0;\n\tborder-bottom-left-radius: 2px\n}\n\n.skin-purple .sidebar-form input[type=\"text\"]:focus,\n.skin-purple .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tbackground-color: #fff;\n\tcolor: #666\n}\n\n.skin-purple .sidebar-form input[type=\"text\"]:focus+.input-group-btn .btn {\n\tborder-left-color: #fff\n}\n\n.skin-purple .sidebar-form .btn {\n\tcolor: #999;\n\tborder-top-left-radius: 0;\n\tborder-top-right-radius: 2px;\n\tborder-bottom-right-radius: 2px;\n\tborder-bottom-left-radius: 0\n}\n\n/*\n *\n *   侧边栏主题 若依管理系统\n *   NAME - .theme-dark/theme-light\n *\n*/\n/** 深黑主题 .theme-dark **/\n.theme-dark .user-panel>.info>p, .theme-dark .user-panel>.info, .theme-dark .user-panel>.info>a{\n\tcolor: #fff\n}\n\n.theme-dark .nav:not(.navbar-toolbar)>li.active {\n\tbackground: #293846;\n}\n\n.theme-dark .navbar-static-side {\n\tbackground-color: #2f4050;\n}\n\n.theme-dark .user-panel {\n\tbackground-color: #2f4050;\n}\n\n.theme-dark .navbar-default .nav>li>a:hover,\n.theme-dark .navbar-default .nav>li>a:focus {\n\tbackground: #293846;\n}\n\n/** 浅色主题 theme-light **/\n.theme-light .user-panel>.info>p, .theme-light .user-panel>.info, .theme-light .user-panel>.info>a{\n\tcolor: #555\n}\n\n.theme-light .nav:not(.navbar-toolbar)>li.active{\n\tbackground: #f9fafc;\n}\n\n.theme-light .navbar-static-side {\n\tbackground-color: #f9fafc;\n\tbox-shadow: 2px 0 2px 0 rgba(29,35,41,.05);\n}\n\n.theme-light .user-panel {\n\tbackground-color: #f9fafc;\n}\n\n.theme-light .navbar-default .nav>li>a {\n\tcolor: #777;\n}\n\n.theme-light.skin-blue .navbar-default .nav>li.active>a {\n\tcolor: #1890ff;\n}\n\n.theme-light.skin-blue .navbar-default .nav>li.selected>a,\n.theme-light.skin-blue .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: rgb(240, 245, 255);\n\tcolor: rgb(47, 84, 235);\n}\n\n.theme-light.skin-green .navbar-default .nav>li.active>a {\n\tcolor: #52c41a;\n}\n\n.theme-light.skin-green .navbar-default .nav>li.selected>a,\n.theme-light.skin-green .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: rgb(246, 255, 237);\n\tcolor: rgb(82, 196, 26);\n}\n\n.theme-light.skin-purple .navbar-default .nav>li.active>a {\n\tcolor: rgb(114, 46, 209);\n}\n\n.theme-light.skin-purple .navbar-default .nav>li.selected>a,\n.theme-light.skin-purple .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #f9f0ff;\n\tcolor: #722ed1;\n}\n\n.theme-light.skin-red .navbar-default .nav>li.active>a {\n\tcolor: rgb(245, 34, 45);\n}\n\n.theme-light.skin-red .navbar-default .nav>li.selected>a,\n.theme-light.skin-red .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: rgb(255, 241, 240);\n\tcolor: rgb(245, 34, 45);\n}\n\n.theme-light.skin-yellow .navbar-default .nav>li.active>a {\n\tcolor: rgb(250, 173, 20);\n}\n\n.theme-light.skin-yellow .navbar-default .nav>li.selected>a,\n.theme-light.skin-yellow .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #fffbe6;\n\tcolor: #faad14;\n}\n\n.theme-light .navbar-default .nav>li>a:hover,\n.theme-light .navbar-default .nav>li>a:focus {\n\tbackground-color: rgb(240, 245, 255);\n}\n\n.fixed-sidebar.theme-light.mini-navbar .nav li:hover>a> span.nav-label {\n    background-color: #f9fafc;\n}\n\n.fixed-sidebar.theme-light.mini-navbar .nav li:hover>.nav-second-level {\n    background-color: #f9fafc;\n}\n\n.theme-light.skin-blue .nav:not(.navbar-toolbar)>li.selected {\n\tborder-right: 3px solid #1890ff;\n\tmargin-right: 2px;\n}\n\n.theme-light.skin-purple .nav:not(.navbar-toolbar)>li.selected{\n\tborder-right: 3px solid #722ed1;\n\tmargin-right: 2px;\n}\n\n.theme-light.skin-green .nav:not(.navbar-toolbar)>li.selected{\n\tborder-right: 3px solid #52c41a;\n\tmargin-right: 2px;\n}\n\n.theme-light.skin-red .nav:not(.navbar-toolbar)>li.selected{\n\tborder-right: 3px solid #f5222d;\n\tmargin-right: 2px;\n}\n\n.theme-light.skin-yellow .nav:not(.navbar-toolbar)>li.selected{\n\tborder-right: 3px solid #faad14;\n\tmargin-right: 2px;\n}\n\n/** 深蓝主题 theme-light **/\n/**\n.skin-blue.theme-blue .logo, .skin-white.theme-blue .logo {\n\tbackground-color: rgba(15,41,80,1) !important;\n\tcolor: #fff;\n}\n**/\n.theme-blue .user-panel>.info>p, .theme-blue .user-panel>.info, .theme-blue .user-panel>.info>a{\n\tcolor: #a3b1cc\n}\n\n.theme-blue .nav:not(.navbar-toolbar)>li.active{\n\tbackground-color: rgba(15,41,80,1);\n}\n\n.theme-blue .navbar-static-side {\n\tbackground-color: rgba(15,41,80,1);\n\tbox-shadow: 2px 0 2px 0 rgba(29,35,41,.05);\n}\n\n.theme-blue .user-panel {\n\tbackground-color: rgba(15,41,80,1);\n}\n\n.theme-blue .navbar-default .nav>li>a {\n\tcolor: #a3b1cc;\n}\n\n.theme-blue.skin-blue .navbar-default .nav>li.active>a {\n\tcolor: #1890ff;\n}\n\n.theme-blue.skin-blue .navbar-default .nav>li.selected>a,\n.theme-blue.skin-blue .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #1890ff;\n\tcolor: rgba(255,255,255,1);\n}\n\n.theme-blue.skin-green .navbar-default .nav>li.active>a {\n\tcolor: #52c41a;\n}\n\n.theme-blue.skin-green .navbar-default .nav>li.selected>a,\n.theme-blue.skin-green .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #52c41a;\n    color: rgba(255,255,255,1);\n}\n\n.theme-blue.skin-purple .navbar-default .nav>li.active>a {\n\tcolor: rgb(114, 46, 209);\n}\n\n.theme-blue.skin-purple .navbar-default .nav>li.selected>a,\n.theme-blue.skin-purple .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #722ed1;\n    color: rgba(255,255,255,1);\n}\n\n.theme-blue.skin-red .navbar-default .nav>li.active>a {\n\tcolor: rgb(245, 34, 45);\n}\n\n.theme-blue.skin-red .navbar-default .nav>li.selected>a,\n.theme-blue.skin-red .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #f5222d;\n    color: rgba(255,255,255,1);\n}\n\n.theme-blue.skin-yellow .navbar-default .nav>li.active>a {\n\tcolor: rgb(250, 173, 20);\n}\n\n.theme-blue.skin-yellow .navbar-default .nav>li.selected>a,\n.theme-blue.skin-yellow .navbar-default .nav>li.selected>a:focus {\n\tbackground-color: #faad14;\n    color: rgba(255,255,255,1);\n}\n\n.theme-blue .navbar-default .nav>li>a:hover,\n.theme-blue .navbar-default .nav>li>a:focus {\n\tbackground-color: rgba(15,41,80,1);\n\tbox-shadow: 2px 0 2px 0 rgba(29,35,41,.05);\n}\n\n.fixed-sidebar.theme-blue.mini-navbar .nav li:hover>a> span.nav-label {\n    background-color: rgba(15,41,80,1);\n}\n\n.fixed-sidebar.theme-blue.mini-navbar .nav li:hover>.nav-second-level {\n    background-color: rgba(15,41,80,1);\n}\n\n/* tab页签样式 */\n.page-tabs a {\n\tcolor: rgba(0,0,0,0.65)!important;\n\tpadding: 0 8px 0 8px;\n\tmin-width: 50px;\n\ttext-align: center;\n\tline-height: 26px;\n\tborder-radius: 2px;\n\tmargin:5px 0 0 4px;\n\tborder: 1px solid #d9d9d9;\n}\n\n.page-tabs a.active:hover, .page-tabs a.active i:hover {\n\tcolor: #000000!important;\n\tbackground: #f5f5f5!important;\n}\n\n.page-tabs a.active:hover i {\n\tcolor: #ffffff!important;\n}\n\n.page-tabs a.active i:hover {\n\tcolor: #ffffff!important;\n\tbackground: transparent!important;\n}\n\n.page-tabs a.active i {\n\tcolor: #ffffff;\n}\n\n/* tab页签主题样式 */\n.skin-blue .page-tabs a.active {\n\tcolor: #ffffff!important;\n\tbackground: #1890ff!important;\n\tborder: 1px solid #1890ff;\n}\n\n.skin-purple .page-tabs a.active {\n\tcolor: #ffffff!important;\n\tbackground: #722ed1!important;\n\tborder: 1px solid #722ed1;\n}\n\n.skin-green .page-tabs a.active {\n\tcolor: #ffffff!important;\n\tbackground: #52c41a!important;\n\tborder: 1px solid #52c41a;\n}\n\n.skin-red .page-tabs a.active {\n\tcolor: #ffffff!important;\n\tbackground: #dd4b39!important;\n\tborder: 1px solid #dd4b39;\n}\n\n.skin-yellow .page-tabs a.active {\n\tcolor: #ffffff!important;\n\tbackground: #f39c12!important;\n\tborder: 1px solid #f39c12;\n}\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/css/style.css",
    "content": "h1, h2, h3, h4, h5, h6 {\r\n    font-weight: 100;\r\n}\r\n\r\nh1 {\r\n    font-size: 30px;\r\n}\r\n\r\nh2 {\r\n    font-size: 24px;\r\n}\r\n\r\nh3 {\r\n    font-size: 16px;\r\n}\r\n\r\nh4 {\r\n    font-size: 14px;\r\n}\r\n\r\nh5 {\r\n    font-size: 12px;\r\n}\r\n\r\nh6 {\r\n    font-size: 10px;\r\n}\r\n\r\nh3, h4, h5 {\r\n    margin-top: 5px;\r\n    font-weight: 600;\r\n}\r\n\r\na:focus {\r\n    outline: none;\r\n}\r\n\r\n.nav>li>a {\r\n    color: #a7b1c2;\r\n    font-weight: 600;\r\n    padding: 14px 20px 14px 25px;\r\n}\r\n\r\n.nav li>a {\r\n    display: block;\r\n    /*white-space: nowrap;*/\r\n}\r\n\r\n.nav.navbar-right>li>a, .nav.navbar-left>li>a {\r\n\tcolor: #fff;\r\n\tfont-size: 14px;\r\n\theight: 50px;\r\n\tpadding: 15px 15px;\r\n}\r\n\r\n.nav>li.active>a {\r\n    color: #ffffff;\r\n}\r\n\r\n.nav.navbar-right>li>a>.label, .nav.navbar-left>li>a>.label {\r\n\tposition: absolute;\r\n\ttop: 9px;\r\n\tright: 5px;\r\n\ttext-align: center;\r\n\tfont-size: 9px;\r\n\tpadding: 2px 4px;\r\n\tline-height: .9;\r\n}\r\n.nav.navbar-right>li>a:hover, .nav.navbar-left>li>a:hover {\r\n\tbackground-color: #367fa9;\r\n\tcolor: #fff;\r\n}\r\n\r\n.navbar-default .nav>li>a:hover,\r\n.navbar-default .nav>li>a:focus {\r\n\tbackground-color: #293846;\r\n\tcolor: white;\r\n}\r\n\r\n.nav .open>a,\r\n.nav .open>a:hover,\r\n.nav .open>a:focus {\r\n\tbackground: #fff;\r\n}\r\n\r\n.navbar {\r\n\tborder: 0;\r\n}\r\n\r\n.navbar-default {\r\n    background-color: transparent;\r\n    border-color: #2f4050;\r\n    position: relative;\r\n}\r\n\r\n.nav.navbar-top-links li {\r\n\tdisplay: inline-block;\r\n}\r\n\r\n.navbar-top-links li:last-child {\r\n    margin-right: 16px;\r\n}\r\n\r\nbody.body-small .navbar-top-links li:last-child {\r\n    margin-right: 10px;\r\n}\r\n\r\n.navbar-top-links li a {\r\n    padding: 20px 10px;\r\n    min-height: 50px;\r\n}\r\n\r\n.dropdown-menu {\r\n    border: medium none;\r\n    display: none;\r\n    float: left;\r\n    font-size: 12px;\r\n    left: 0;\r\n    list-style: none outside none;\r\n    padding: 0;\r\n    position: absolute;\r\n    text-shadow: none;\r\n    top: 100%;\r\n    z-index: 1000;\r\n    border-radius: 0;\r\n    box-shadow: 0 0 3px rgba(86, 96, 117, 0.3);\r\n}\r\n\r\n.dropdown-menu>li>a {\r\n    border-radius: 3px;\r\n    color: inherit;\r\n    line-height: 25px;\r\n    margin: 4px;\r\n    text-align: left;\r\n    font-weight: normal;\r\n}\r\n\r\n.dropdown-menu>li>a.font-bold {\r\n    font-weight: 600;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li {\r\n    display: block;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li:last-child {\r\n    margin-right: 0;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li a {\r\n    padding: 3px 20px;\r\n    min-height: 0;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li a div {\r\n    white-space: normal;\r\n}\r\n\r\n.navbar-top-links .dropdown-messages, .navbar-top-links .dropdown-tasks,  .navbar-top-links .dropdown-alerts {\r\n    width: 310px;\r\n    min-width: 0;\r\n}\r\n\r\n.navbar-top-links .dropdown-messages {\r\n    margin-left: 5px;\r\n}\r\n\r\n.navbar-top-links .dropdown-tasks {\r\n    margin-left: -59px;\r\n}\r\n\r\n.navbar-top-links .dropdown-alerts {\r\n    margin-left: -123px;\r\n}\r\n\r\n.navbar-top-links .dropdown-user {\r\n    right: 0;\r\n    left: auto;\r\n}\r\n\r\n.dropdown-messages, .dropdown-alerts {\r\n    padding: 10px 10px 10px 10px;\r\n}\r\n\r\n.dropdown-messages li a, .dropdown-alerts li a {\r\n    font-size: 12px;\r\n}\r\n\r\n.dropdown-messages li em, .dropdown-alerts li em {\r\n    font-size: 10px;\r\n}\r\n\r\n.nav.navbar-top-links .dropdown-alerts a {\r\n    font-size: 12px;\r\n}\r\n\r\n.nav>li.active {\r\n    border-left: 4px solid #19aa8d;\r\n    background: #293846;\r\n}\r\n\r\n.nav.nav-second-level>li.active {\r\n    border: none;\r\n}\r\n\r\n.nav.nav-second-level.collapse[style] {\r\n    height: auto !important;\r\n}\r\n\r\n.nav-header a {\r\n    color: #DFE4ED;\r\n}\r\n\r\n.nav-header .text-muted {\r\n    color: #8095a8;\r\n}\r\n\r\n.minimalize-styl-2 {\r\n    padding: 4px 12px;\r\n    margin: 12px 5px 5px 15px;\r\n    font-size: 14px;\r\n    float: left;\r\n}\r\n\r\n.navbar-form-custom {\r\n    float: left;\r\n    height: 50px;\r\n    padding: 0;\r\n    width: 200px;\r\n    display: inline-table;\r\n}\r\n\r\n.navbar-form-custom .form-group {\r\n    margin-bottom: 0;\r\n}\r\n\r\n.nav.navbar-top-links a {\r\n    font-size: 14px;\r\n}\r\n\r\n.navbar-form-custom .form-control {\r\n    background: none repeat scroll 0 0 rgba(0, 0, 0, 0);\r\n    border: medium none;\r\n    font-size: 14px;\r\n    height: 60px;\r\n    margin: 0;\r\n    z-index: 2000;\r\n}\r\n\r\n.count-info .label {\r\n    line-height: 12px;\r\n    padding: 1px 5px;\r\n    position: absolute;\r\n    right: 6px;\r\n    top: 12px;\r\n}\r\n\r\n.arrow {\r\n    float: right;\r\n    margin-top: 2px;\r\n}\r\n\r\n.fa.arrow:before {\r\n    content: \"\\f104\";\r\n}\r\n\r\n.active>a>.fa.arrow:before {\r\n    content: \"\\f107\";\r\n}\r\n\r\n.nav-second-level li, .nav-third-level li {\r\n    border-bottom: none !important;\r\n    padding-left: 2px;\r\n    padding-right: 2px;\r\n}\r\n\r\n.nav-second-level li a {\r\n    padding: 7px 15px 7px 10px;\r\n    padding-left: 52px;\r\n}\r\n\r\n.nav-third-level li a {\r\n    padding-left: 70px;\r\n}\r\n\r\n.nav-second-level li:last-child {\r\n    margin-bottom: 10px;\r\n}\r\n\r\nbody:not(.fixed-sidebar ):not(.canvas-menu ).mini-navbar .nav li:hover>.nav-second-level,.mini-navbar .nav li:focus>.nav-second-level {\r\n    display: block;\r\n    border-radius: 0 2px 2px 0;\r\n    min-width: 140px;\r\n    height: auto;\r\n}\r\n\r\nbody.mini-navbar .navbar-default .nav>li>.nav-second-level li a {\r\n    font-size: 12px;\r\n    border-radius: 0 2px 2px 0;\r\n}\r\n\r\nbody.mini-navbar .navbar-default .nav>li>.nav-third-level li a {\r\n    padding-left: 31px;\r\n}\r\n\r\n.fixed-nav .slimScrollDiv #side-menu {\r\n    padding-bottom: 60px;\r\n    position: relative;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .slimScrollDiv>* {\r\n    overflow: visible!important;\r\n}\r\n\r\n.fixed-sidebar .slimScrollDiv>* {\r\n    overflow-y: hidden;\r\n    overflow-x: visible;\r\n}\r\n\r\n.mini-navbar .nav-second-level li a {\r\n    padding: 10px 10px 10px 15px;\r\n}\r\n\r\n.canvas-menu.mini-navbar .nav-second-level {\r\n    background: #293846;\r\n}\r\n\r\n.mini-navbar li.active .nav-second-level {\r\n    left: 65px;\r\n}\r\n\r\n.navbar-default .special_link a {\r\n    background: #1ab394;\r\n    color: white;\r\n}\r\n\r\n.navbar-default .special_link a:hover {\r\n    background: #17987e !important;\r\n    color: white;\r\n}\r\n\r\n.navbar-default .special_link a span.label {\r\n    background: #fff;\r\n    color: #1ab394;\r\n}\r\n\r\n.navbar-default .landing_link a {\r\n    background: #1cc09f;\r\n    color: white;\r\n}\r\n\r\n.navbar-default .landing_link a:hover {\r\n    background: #1ab394 !important;\r\n    color: white;\r\n}\r\n\r\n.navbar-default .landing_link a span.label {\r\n    background: #fff;\r\n    color: #1cc09f;\r\n}\r\n\r\n.logo-element {\r\n    text-align: center;\r\n    font-size: 18px;\r\n    font-weight: 600;\r\n    color: white;\r\n    display: none;\r\n    padding: 18px 0;\r\n}\r\n\r\n.navbar-fixed-top {\r\n    background: #fff;\r\n    -webkit-transition-duration: 0.5s;\r\n    transition-duration: 0.5s;\r\n    z-index: 2030;\r\n}\r\n\r\n.fixed-nav #wrapper {\r\n    padding-top: 60px;\r\n    box-sizing: border-box;\r\n}\r\n\r\n.fixed-nav .minimalize-styl-2 {\r\n    margin: 14px 5px 5px 15px;\r\n}\r\n\r\n.body-small .navbar-fixed-top {\r\n    margin-left: 0px;\r\n}\r\n\r\nbody.mini-navbar .navbar-static-side {\r\n    width: 70px;\r\n}\r\n\r\nbody.mini-navbar .profile-element, body.mini-navbar .nav-label, body.mini-navbar .navbar-default .nav li a span {\r\n    display: none;\r\n}\r\n\r\nbody.canvas-menu .profile-element {\r\n    display: block;\r\n}\r\n\r\nbody:not(.fixed-sidebar ):not(.canvas-menu ).mini-navbar .nav-second-level {\r\n    display: none;\r\n}\r\n\r\nbody.mini-navbar .navbar-default .nav>li>a {\r\n    font-size: 16px;\r\n}\r\n\r\nbody.mini-navbar .logo-element {\r\n    display: block;\r\n}\r\n\r\nbody.canvas-menu .logo-element {\r\n    display: none;\r\n}\r\n\r\nbody.mini-navbar .nav-header {\r\n    padding: 0;\r\n    background-color: #1ab394;\r\n}\r\n\r\nbody.canvas-menu .nav-header {\r\n    padding: 33px 25px;\r\n}\r\n\r\nbody.mini-navbar #page-wrapper {\r\n    margin: 0 0 0 70px;\r\n}\r\n\r\nbody.canvas-menu.mini-navbar #page-wrapper, body.canvas-menu.mini-navbar .footer {\r\n    margin: 0 0 0 0;\r\n}\r\n\r\nbody.fixed-sidebar .navbar-static-side, body.canvas-menu .navbar-static-side {\r\n    position: fixed;\r\n    width: 200px;\r\n    z-index: 2001;\r\n    height: 100%;\r\n}\r\n\r\nbody.fixed-sidebar.mini-navbar .navbar-static-side {\r\n    width: 70px;\r\n}\r\n\r\nbody.fixed-sidebar.mini-navbar #page-wrapper {\r\n    margin: 0 0 0 70px;\r\n}\r\n\r\nbody.body-small.fixed-sidebar.mini-navbar #page-wrapper {\r\n    margin: 0 0 0 70px;\r\n}\r\n\r\nbody.body-small.fixed-sidebar.mini-navbar .navbar-static-side {\r\n    width: 70px;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li>.nav-second-level {\r\n    display: none;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li.active {\r\n    border-left-width: 0;\r\n}\r\n\r\n/* 伸缩菜单 */\r\n.fixed-sidebar.mini-navbar .nav li:hover>a> span.nav-label {\r\n    top: 0px;\r\n    padding: 10px 10px 10px 10px;\r\n    text-align: center;\r\n    background-color: #243747;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level {\r\n    top: 40px;\r\n    font-size: 12px;\r\n    background-color: #2f4050;\r\n    max-height: 400px;\r\n    overflow-y: auto;\r\n    overflow-x: hidden;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level {\r\n    position: relative;\r\n    overflow-y: overlay;\r\n    scrollbar-width: thin;\r\n    scrollbar-color: #555 #2f4050;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level::-webkit-scrollbar {\r\n    width: 8px;\r\n    background: transparent;\r\n    position: absolute;\r\n    right: 0;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level::-webkit-scrollbar-thumb {\r\n    background: #888;\r\n    border-radius: 4px;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level, .fixed-sidebar.mini-navbar .nav li:hover>a> span.nav-label {\r\n    position: absolute;\r\n    left: 70px;\r\n    display: block;\r\n    min-width: 140px;\r\n    border-radius: 2px;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav li.active:hover>.nav-second-level, .fixed-sidebar.mini-navbar .nav li.active:hover>a> span.nav-label {\r\n    left: 67px;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav .nav-second-level a> span, .fixed-sidebar.mini-navbar .nav .nav-third-level a> span {\r\n    display: inline-block;\r\n}\r\n\r\n/*伸缩菜单结束*/\r\n\r\nbody.fixed-sidebar.mini-navbar .navbar-default .nav>li>.nav-second-level li a {\r\n    font-size: 12px;\r\n    border-radius: 3px;\r\n}\r\n\r\nbody.canvas-menu.mini-navbar .navbar-default .nav>li>.nav-second-level li a {\r\n    font-size: 13px;\r\n    border-radius: 3px;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav-second-level li a, .canvas-menu.mini-navbar .nav-second-level li a {\r\n    padding: 10px 10px 10px 15px;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar .nav-second-level, .canvas-menu.mini-navbar .nav-second-level {\r\n    position: relative;\r\n    padding: 0;\r\n    font-size: 13px;\r\n}\r\n\r\n.fixed-sidebar.mini-navbar li.active .nav-second-level, .canvas-menu.mini-navbar li.active .nav-second-level {\r\n    left: 0px;\r\n}\r\n\r\nbody.canvas-menu nav.navbar-static-side {\r\n    z-index: 2001;\r\n    background: #2f4050;\r\n    height: 100%;\r\n    position: fixed;\r\n    display: none;\r\n}\r\n\r\nbody.canvas-menu.mini-navbar nav.navbar-static-side {\r\n    display: block;\r\n    width: 70px;\r\n}\r\n\r\n.top-navigation #page-wrapper {\r\n    margin-left: 0;\r\n}\r\n\r\n.top-navigation .navbar-nav .dropdown-menu>.active>a {\r\n    background: white;\r\n    color: #1ab394;\r\n    font-weight: bold;\r\n}\r\n\r\n.white-bg .navbar-fixed-top, .white-bg .navbar-static-top {\r\n    background: #fff;\r\n}\r\n\r\n.top-navigation .navbar {\r\n    margin-bottom: 0;\r\n}\r\n\r\n.top-navigation .nav>li>a {\r\n    padding: 15px 20px;\r\n    color: #676a6c;\r\n}\r\n\r\n.top-navigation .nav>li a:hover, .top-navigation .nav>li a:focus {\r\n    background: #fff;\r\n    color: #1ab394;\r\n}\r\n\r\n.top-navigation .nav>li.active {\r\n    background: #fff;\r\n    border: none;\r\n}\r\n\r\n.top-navigation .nav>li.active>a {\r\n    color: #1ab394;\r\n}\r\n\r\n.top-navigation .navbar-right {\r\n    padding-right: 10px;\r\n}\r\n\r\n.top-navigation .navbar-nav .dropdown-menu {\r\n    box-shadow: none;\r\n    border: 1px solid #e7eaec;\r\n}\r\n\r\n.top-navigation .dropdown-menu>li>a {\r\n    margin: 0;\r\n    padding: 7px 20px;\r\n}\r\n\r\n.navbar .dropdown-menu {\r\n    margin-top: 0px;\r\n}\r\n\r\n.top-navigation .navbar-brand {\r\n    background: #1ab394;\r\n    color: #fff;\r\n    padding: 15px 25px;\r\n}\r\n\r\n.top-navigation .navbar-top-links li:last-child {\r\n    margin-right: 0;\r\n}\r\n\r\n.top-navigation.mini-navbar #page-wrapper, .top-navigation.body-small.fixed-sidebar.mini-navbar #page-wrapper,  .mini-navbar .top-navigation #page-wrapper, .body-small.fixed-sidebar.mini-navbar .top-navigation #page-wrapper,  .canvas-menu #page-wrapper {\r\n    margin: 0;\r\n}\r\n\r\n.top-navigation.fixed-nav #wrapper, .fixed-nav #wrapper.top-navigation {\r\n    margin-top: 50px;\r\n}\r\n\r\n.top-navigation .footer.fixed {\r\n    margin-left: 0 !important;\r\n}\r\n\r\n.top-navigation .wrapper.wrapper-content {\r\n    padding: 40px;\r\n}\r\n\r\n.top-navigation.body-small .wrapper.wrapper-content, .body-small .top-navigation .wrapper.wrapper-content {\r\n    padding: 40px 0px 40px 0px;\r\n}\r\n\r\n.navbar-toggle {\r\n    background-color: #1ab394;\r\n    color: #fff;\r\n    padding: 6px 12px;\r\n    font-size: 14px;\r\n}\r\n\r\n.top-navigation .navbar-nav .open .dropdown-menu>li>a, .top-navigation .navbar-nav .open .dropdown-menu .dropdown-header {\r\n    padding: 10px 15px 10px 20px;\r\n}\r\n\r\n@media ( max-width : 768px) {\r\n    .top-navigation .navbar-header {\r\n        display: block;\r\n        float: none;\r\n    }\r\n}\r\n\r\n.menu-visible-lg, .menu-visible-md {\r\n    display: none !important;\r\n}\r\n\r\n@media ( min-width : 1200px) {\r\n    .menu-visible-lg {\r\n        display: block !important;\r\n    }\r\n}\r\n\r\n@media ( min-width : 992px) {\r\n    .menu-visible-md {\r\n        display: block !important;\r\n    }\r\n}\r\n\r\n@media ( max-width : 767px) {\r\n    .menu-visible-md {\r\n        display: block !important;\r\n    }\r\n\r\n    .menu-visible-lg {\r\n        display: block !important;\r\n    }\r\n}\r\n\r\n.btn {\r\n    border-radius: 3px;\r\n}\r\n\r\n.float-e-margins .btn {\r\n    margin-bottom: 5px;\r\n}\r\n\r\n.btn-w-m {\r\n    min-width: 120px;\r\n}\r\n\r\n.btn-primary.btn-outline {\r\n    color: #1ab394;\r\n}\r\n\r\n.btn-success.btn-outline {\r\n    color: #1c84c6;\r\n}\r\n\r\n.btn-info.btn-outline {\r\n    color: #23c6c8;\r\n}\r\n\r\n.btn-warning.btn-outline {\r\n    color: #f8ac59;\r\n}\r\n\r\n.btn-danger.btn-outline {\r\n    color: #ed5565;\r\n}\r\n\r\n.btn-primary.btn-outline:hover, .btn-success.btn-outline:hover,  .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover,  .btn-danger.btn-outline:hover {\r\n    color: #fff;\r\n}\r\n\r\n.btn-primary {\r\n    background-color: #1ab394;\r\n    border-color: #1ab394;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-primary:hover, .btn-primary:focus, .btn-primary:active,  .btn-primary.active, .open .dropdown-toggle.btn-primary {\r\n    background-color: #18a689;\r\n    border-color: #18a689;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary {\r\n    background-image: none;\r\n}\r\n\r\n.btn-primary.disabled, .btn-primary.disabled:hover, .btn-primary.disabled:focus,  .btn-primary.disabled:active, .btn-primary.disabled.active,  .btn-primary[disabled], .btn-primary[disabled]:hover, .btn-primary[disabled]:focus,  .btn-primary[disabled]:active, .btn-primary.active[disabled], fieldset[disabled] .btn-primary,  fieldset[disabled] .btn-primary:hover, fieldset[disabled] .btn-primary:focus,  fieldset[disabled] .btn-primary:active, fieldset[disabled] .btn-primary.active {\r\n    background-color: #1dc5a3;\r\n    border-color: #1dc5a3;\r\n}\r\n\r\n.btn-success {\r\n    background-color: #1c84c6;\r\n    border-color: #1c84c6;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-success:hover, .btn-success:focus, .btn-success:active,  .btn-success.active, .open .dropdown-toggle.btn-success {\r\n    background-color: #1a7bb9 !important;\r\n    border-color: #1a7bb9 !important;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success {\r\n    background-image: none;\r\n}\r\n\r\n.btn-success.disabled, .btn-success.disabled:hover, .btn-success.disabled:focus,  .btn-success.disabled:active, .btn-success.disabled.active,  .btn-success[disabled], .btn-success[disabled]:hover, .btn-success[disabled]:focus,  .btn-success[disabled]:active, .btn-success.active[disabled], fieldset[disabled] .btn-success,  fieldset[disabled] .btn-success:hover, fieldset[disabled] .btn-success:focus,  fieldset[disabled] .btn-success:active, fieldset[disabled] .btn-success.active {\r\n    background-color: #1f90d8;\r\n    border-color: #1f90d8;\r\n}\r\n\r\n.btn-info {\r\n    background-color: #23c6c8;\r\n    border-color: #23c6c8;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-info:hover, .btn-info:focus, .btn-info:active, .btn-info.active,  .open .dropdown-toggle.btn-info {\r\n    background-color: #21b9bb;\r\n    border-color: #21b9bb;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-info:active, .btn-info.active, .open .dropdown-toggle.btn-info {\r\n    background-image: none;\r\n}\r\n\r\n.btn-info.disabled, .btn-info.disabled:hover, .btn-info.disabled:focus,  .btn-info.disabled:active, .btn-info.disabled.active, .btn-info[disabled],  .btn-info[disabled]:hover, .btn-info[disabled]:focus, .btn-info[disabled]:active,  .btn-info.active[disabled], fieldset[disabled] .btn-info, fieldset[disabled] .btn-info:hover,  fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:active,  fieldset[disabled] .btn-info.active {\r\n    background-color: #26d7d9;\r\n    border-color: #26d7d9;\r\n}\r\n\r\n.btn-default {\r\n    background-color: #f4f4f4;\r\n    border-color: #ddd;\r\n    color: #444;\r\n}\r\n\r\n.btn-default:hover, .btn-default:focus, .btn-default:active,  .btn-default.active, .open .dropdown-toggle.btn-default {\r\n    background-color: #e7e7e7;\r\n    border-color: #e7e7e7;\r\n    color: #444;\r\n}\r\n\r\n.btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default {\r\n    background-image: none;\r\n}\r\n\r\n.btn-default.disabled, .btn-default.disabled:hover, .btn-default.disabled:focus,  .btn-default.disabled:active, .btn-default.disabled.active,  .btn-default[disabled], .btn-default[disabled]:hover, .btn-default[disabled]:focus,  .btn-default[disabled]:active, .btn-default.active[disabled], fieldset[disabled] .btn-default,  fieldset[disabled] .btn-default:hover, fieldset[disabled] .btn-default:focus,  fieldset[disabled] .btn-default:active, fieldset[disabled] .btn-default.active {\r\n    background-color: #cccccc;\r\n    border-color: #cccccc;\r\n}\r\n\r\n.btn-warning {\r\n    background-color: #f8ac59;\r\n    border-color: #f8ac59;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-warning:hover, .btn-warning:focus, .btn-warning:active,  .btn-warning.active, .open .dropdown-toggle.btn-warning {\r\n    background-color: #f7a54a;\r\n    border-color: #f7a54a;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-warning:active, .btn-warning.active, .open .dropdown-toggle.btn-warning {\r\n    background-image: none;\r\n}\r\n\r\n.btn-warning.disabled, .btn-warning.disabled:hover, .btn-warning.disabled:focus,  .btn-warning.disabled:active, .btn-warning.disabled.active,  .btn-warning[disabled], .btn-warning[disabled]:hover, .btn-warning[disabled]:focus,  .btn-warning[disabled]:active, .btn-warning.active[disabled], fieldset[disabled] .btn-warning,  fieldset[disabled] .btn-warning:hover, fieldset[disabled] .btn-warning:focus,  fieldset[disabled] .btn-warning:active, fieldset[disabled] .btn-warning.active {\r\n    background-color: #f9b66d;\r\n    border-color: #f9b66d;\r\n}\r\n\r\n.btn-danger {\r\n    background-color: #ed5565;\r\n    border-color: #ed5565;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active,  .open .dropdown-toggle.btn-danger {\r\n    background-color: #ec4758;\r\n    border-color: #ec4758;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.btn-danger:active, .btn-danger.active, .open .dropdown-toggle.btn-danger {\r\n    background-image: none;\r\n}\r\n\r\n.btn-danger.disabled, .btn-danger.disabled:hover, .btn-danger.disabled:focus,  .btn-danger.disabled:active, .btn-danger.disabled.active, .btn-danger[disabled],  .btn-danger[disabled]:hover, .btn-danger[disabled]:focus, .btn-danger[disabled]:active,  .btn-danger.active[disabled], fieldset[disabled] .btn-danger, fieldset[disabled] .btn-danger:hover,  fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:active,  fieldset[disabled] .btn-danger.active {\r\n    background-color: #ef6776;\r\n    border-color: #ef6776;\r\n}\r\n\r\n.btn-link {\r\n    color: inherit;\r\n}\r\n\r\n.btn-link:hover, .btn-link:focus, .btn-link:active, .btn-link.active,  .open .dropdown-toggle.btn-link {\r\n    color: #1ab394;\r\n    text-decoration: none;\r\n}\r\n\r\n.btn-link:active, .btn-link.active, .open .dropdown-toggle.btn-link {\r\n    background-image: none;\r\n}\r\n\r\n.btn-link.disabled, .btn-link.disabled:hover, .btn-link.disabled:focus,  .btn-link.disabled:active, .btn-link.disabled.active, .btn-link[disabled],  .btn-link[disabled]:hover, .btn-link[disabled]:focus, .btn-link[disabled]:active,  .btn-link.active[disabled], fieldset[disabled] .btn-link, fieldset[disabled] .btn-link:hover,  fieldset[disabled] .btn-link:focus, fieldset[disabled] .btn-link:active,  fieldset[disabled] .btn-link.active {\r\n    color: #cacaca;\r\n}\r\n\r\n.btn-white {\r\n    color: inherit;\r\n    background: white;\r\n    border: 1px solid #e7eaec;\r\n}\r\n\r\n.btn-white:hover, .btn-white:focus, .btn-white:active, .btn-white.active,  .open .dropdown-toggle.btn-white {\r\n    color: inherit;\r\n    border: 1px solid #d2d2d2;\r\n}\r\n\r\n.btn-white:active, .btn-white.active {\r\n    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15) inset;\r\n}\r\n\r\n.btn-white:active, .btn-white.active, .open .dropdown-toggle.btn-white {\r\n    background-image: none;\r\n}\r\n\r\n.btn-white.disabled, .btn-white.disabled:hover, .btn-white.disabled:focus,  .btn-white.disabled:active, .btn-white.disabled.active, .btn-white[disabled],  .btn-white[disabled]:hover, .btn-white[disabled]:focus, .btn-white[disabled]:active,  .btn-white.active[disabled], fieldset[disabled] .btn-white, fieldset[disabled] .btn-white:hover,  fieldset[disabled] .btn-white:focus, fieldset[disabled] .btn-white:active,  fieldset[disabled] .btn-white.active {\r\n    color: #cacaca;\r\n}\r\n\r\n.form-control, .has-error .form-control:focus,  .has-success .form-control:focus, .has-warning .form-control:focus,  .navbar-collapse, .navbar-form, .navbar-form-custom .form-control:focus,  .navbar-form-custom .form-control:hover, .open .btn.dropdown-toggle,  .panel, .popover, .progress, .progress-bar {\r\n    box-shadow: none;\r\n}\r\n\r\n.btn-outline {\r\n    color: inherit;\r\n    background-color: transparent;\r\n    -webkit-transition: all .5s;\r\n    transition: all .5s;\r\n}\r\n\r\n.btn-rounded {\r\n    border-radius: 50px;\r\n}\r\n\r\n.btn-large-dim {\r\n    width: 90px;\r\n    height: 90px;\r\n    font-size: 42px;\r\n}\r\n\r\nbutton.dim {\r\n    display: inline-block;\r\n    color: #fff;\r\n    text-decoration: none;\r\n    text-transform: uppercase;\r\n    text-align: center;\r\n    padding-top: 6px;\r\n    margin-right: 10px;\r\n    position: relative;\r\n    cursor: pointer;\r\n    border-radius: 5px;\r\n    font-weight: 600;\r\n    margin-bottom: 20px !important;\r\n}\r\n\r\nbutton.dim:active {\r\n    top: 3px;\r\n}\r\n\r\nbutton.btn-primary.dim {\r\n    box-shadow: inset 0px 0px 0px #16987e, 0px 5px 0px 0px #16987e, 0px 10px  5px #999999;\r\n}\r\n\r\nbutton.btn-primary.dim:active {\r\n    box-shadow: inset 0px 0px 0px #16987e, 0px 2px 0px 0px #16987e, 0px 5px  3px #999999;\r\n}\r\n\r\nbutton.btn-default.dim {\r\n    box-shadow: inset 0px 0px 0px #b3b3b3, 0px 5px 0px 0px #b3b3b3, 0px 10px  5px #999999;\r\n}\r\n\r\nbutton.btn-default.dim:active {\r\n    box-shadow: inset 0px 0px 0px #b3b3b3, 0px 2px 0px 0px #b3b3b3, 0px 5px  3px #999999;\r\n}\r\n\r\nbutton.btn-warning.dim {\r\n    box-shadow: inset 0px 0px 0px #f79d3c, 0px 5px 0px 0px #f79d3c, 0px 10px  5px #999999;\r\n}\r\n\r\nbutton.btn-warning.dim:active {\r\n    box-shadow: inset 0px 0px 0px #f79d3c, 0px 2px 0px 0px #f79d3c, 0px 5px  3px #999999;\r\n}\r\n\r\nbutton.btn-info.dim {\r\n    box-shadow: inset 0px 0px 0px #1eacae, 0px 5px 0px 0px #1eacae, 0px 10px  5px #999999;\r\n}\r\n\r\nbutton.btn-info.dim:active {\r\n    box-shadow: inset 0px 0px 0px #1eacae, 0px 2px 0px 0px #1eacae, 0px 5px  3px #999999;\r\n}\r\n\r\nbutton.btn-success.dim {\r\n    box-shadow: inset 0px 0px 0px #1872ab, 0px 5px 0px 0px #1872ab, 0px 10px  5px #999999;\r\n}\r\n\r\nbutton.btn-success.dim:active {\r\n    box-shadow: inset 0px 0px 0px #1872ab, 0px 2px 0px 0px #1872ab, 0px 5px  3px #999999;\r\n}\r\n\r\nbutton.btn-danger.dim {\r\n    box-shadow: inset 0px 0px 0px #ea394c, 0px 5px 0px 0px #ea394c, 0px 10px  5px #999999;\r\n}\r\n\r\nbutton.btn-danger.dim:active {\r\n    box-shadow: inset 0px 0px 0px #ea394c, 0px 2px 0px 0px #ea394c, 0px 5px  3px #999999;\r\n}\r\n\r\nbutton.dim:before {\r\n    font-size: 50px;\r\n    line-height: 1em;\r\n    font-weight: normal;\r\n    color: #fff;\r\n    display: block;\r\n    padding-top: 10px;\r\n}\r\n\r\nbutton.dim:active:before {\r\n    top: 7px;\r\n    font-size: 50px;\r\n}\r\n\r\n.label {\r\n    background-color: #d1dade;\r\n    color: #5e5e5e;\r\n    font-size: 10px;\r\n    font-weight: 600;\r\n    padding: 3px 8px;\r\n    text-shadow: none;\r\n}\r\n\r\n.badge {\r\n    background-color: #d1dade;\r\n    color: #5e5e5e;\r\n    font-size: 11px;\r\n    font-weight: 600;\r\n    padding-bottom: 4px;\r\n    padding-left: 6px;\r\n    padding-right: 6px;\r\n    text-shadow: none;\r\n}\r\n\r\n.label-primary, .badge-primary {\r\n    background-color: #1ab394;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.label-success, .badge-success {\r\n    background-color: #1c84c6;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.label-warning, .badge-warning {\r\n    background-color: #f8ac59;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.label-warning-light, .badge-warning-light {\r\n    background-color: #f8ac59;\r\n    color: #ffffff;\r\n}\r\n\r\n.label-danger, .badge-danger {\r\n    background-color: #ed5565;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.label-info, .badge-info {\r\n    background-color: #23c6c8;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.label-inverse, .badge-inverse {\r\n    background-color: #262626;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.label-white, .badge-white {\r\n    background-color: #FFFFFF;\r\n    color: #5E5E5E;\r\n}\r\n\r\n.label-white, .badge-disable {\r\n    background-color: #2A2E36;\r\n    color: #8B91A0;\r\n}\r\n/* TOOGLE SWICH */\r\n.onoffswitch {\r\n    position: relative;\r\n    width: 64px;\r\n    -webkit-user-select: none;\r\n    -moz-user-select: none;\r\n    -ms-user-select: none;\r\n}\r\n\r\n.onoffswitch-checkbox {\r\n    display: none;\r\n}\r\n\r\n.onoffswitch-label {\r\n    display: block;\r\n    overflow: hidden;\r\n    cursor: pointer;\r\n    border: 2px solid #1ab394;\r\n    border-radius: 2px;\r\n}\r\n\r\n.onoffswitch-inner {\r\n    width: 200%;\r\n    margin-left: -100%;\r\n    -webkit-transition: margin 0.3s ease-in 0s;\r\n    transition: margin 0.3s ease-in 0s;\r\n}\r\n\r\n.onoffswitch-inner:before, .onoffswitch-inner:after {\r\n    float: left;\r\n    width: 50%;\r\n    height: 20px;\r\n    padding: 0;\r\n    line-height: 20px;\r\n    font-size: 12px;\r\n    color: white;\r\n    font-family: Trebuchet, Arial, sans-serif;\r\n    font-weight: bold;\r\n    box-sizing: border-box;\r\n}\r\n\r\n.onoffswitch-inner:before {\r\n    content: \"ON\";\r\n    padding-left: 10px;\r\n    background-color: #1ab394;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.onoffswitch-inner:after {\r\n    content: \"OFF\";\r\n    padding-right: 10px;\r\n    background-color: #FFFFFF;\r\n    color: #999999;\r\n    text-align: right;\r\n}\r\n\r\n.onoffswitch-switch {\r\n    width: 20px;\r\n    margin: 0px;\r\n    background: #FFFFFF;\r\n    border: 2px solid #1ab394;\r\n    border-radius: 2px;\r\n    position: absolute;\r\n    top: 0;\r\n    bottom: 0;\r\n    right: 44px;\r\n    -webkit-transition: all 0.3s ease-in 0s;\r\n    transition: all 0.3s ease-in 0s;\r\n}\r\n\r\n.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-inner {\r\n    margin-left: 0;\r\n}\r\n\r\n.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-switch {\r\n    right: 0px;\r\n}\r\n/* CHOSEN PLUGIN */\r\n.chosen-container-single .chosen-single {\r\n    background: #ffffff;\r\n    box-shadow: none;\r\n    -moz-box-sizing: border-box;\r\n    background-color: #FFFFFF;\r\n    border: 1px solid #CBD5DD;\r\n    border-radius: 2px;\r\n    cursor: text;\r\n    height: auto !important;\r\n    margin: 0;\r\n    min-height: 30px;\r\n    overflow: hidden;\r\n    padding: 4px 12px;\r\n    position: relative;\r\n    width: 100%;\r\n}\r\n\r\n.chosen-container-multi .chosen-choices li.search-choice {\r\n    background: #f1f1f1;\r\n    border: 1px solid #ededed;\r\n    border-radius: 2px;\r\n    box-shadow: none;\r\n    color: #333333;\r\n    cursor: default;\r\n    line-height: 13px;\r\n    margin: 3px 0 3px 5px;\r\n    padding: 3px 20px 3px 5px;\r\n    position: relative;\r\n}\r\n/* PAGINATIN */\r\n.pagination>.active>a, .pagination>.active>span, .pagination>.active>a:hover,  .pagination>.active>span:hover, .pagination>.active>a:focus,  .pagination>.active>span:focus {\r\n    background-color: #f4f4f4;\r\n    border-color: #DDDDDD;\r\n    color: inherit;\r\n    cursor: default;\r\n    z-index: 2;\r\n}\r\n\r\n.pagination>li>a, .pagination>li>span {\r\n    background-color: #FFFFFF;\r\n    border: 1px solid #DDDDDD;\r\n    color: inherit;\r\n    float: left;\r\n    line-height: 1.42857;\r\n    margin-left: -1px;\r\n    padding: 4px 10px;\r\n    position: relative;\r\n    text-decoration: none;\r\n}\r\n/* TOOLTIPS */\r\n.tooltip-inner {\r\n    background-color: #2F4050;\r\n   \tword-break: break-all;\r\n    overflow-wrap: break-word;\r\n}\r\n\r\n.tooltip.top .tooltip-arrow {\r\n    border-top-color: #2F4050;\r\n}\r\n\r\n.tooltip.right .tooltip-arrow {\r\n    border-right-color: #2F4050;\r\n}\r\n\r\n.tooltip.bottom .tooltip-arrow {\r\n    border-bottom-color: #2F4050;\r\n}\r\n\r\n.tooltip.left .tooltip-arrow {\r\n    border-left-color: #2F4050;\r\n}\r\n/* EASY PIE CHART*/\r\n.easypiechart {\r\n    position: relative;\r\n    text-align: center;\r\n}\r\n\r\n.easypiechart .h2 {\r\n    margin-left: 10px;\r\n    margin-top: 10px;\r\n    display: inline-block;\r\n}\r\n\r\n.easypiechart canvas {\r\n    top: 0;\r\n    left: 0;\r\n}\r\n\r\n.easypiechart .easypie-text {\r\n    line-height: 1;\r\n    position: absolute;\r\n    top: 33px;\r\n    width: 100%;\r\n    z-index: 1;\r\n}\r\n\r\n.easypiechart img {\r\n    margin-top: -4px;\r\n}\r\n\r\n.jqstooltip {\r\n    box-sizing: content-box;\r\n}\r\n/* FULLCALENDAR */\r\n.fc-state-default {\r\n    background-color: #ffffff;\r\n    background-image: none;\r\n    background-repeat: repeat-x;\r\n    box-shadow: none;\r\n    color: #333333;\r\n    text-shadow: none;\r\n}\r\n\r\n.fc-state-default {\r\n    border: 1px solid;\r\n}\r\n\r\n.fc-button {\r\n    color: inherit;\r\n    border: 1px solid #e7eaec;\r\n    cursor: pointer;\r\n    display: inline-block;\r\n    height: 1.9em;\r\n    line-height: 1.9em;\r\n    overflow: hidden;\r\n    padding: 0 0.6em;\r\n    position: relative;\r\n    white-space: nowrap;\r\n}\r\n\r\n.fc-state-active {\r\n    background-color: #1ab394;\r\n    border-color: #1ab394;\r\n    color: #ffffff;\r\n}\r\n\r\n.fc-header-title h2 {\r\n    font-size: 16px;\r\n    font-weight: 600;\r\n    color: inherit;\r\n}\r\n\r\n.fc-content .fc-widget-header, .fc-content .fc-widget-content {\r\n    border-color: #e7eaec;\r\n    font-weight: normal;\r\n}\r\n\r\n.fc-border-separate tbody {\r\n    background-color: #F8F8F8;\r\n}\r\n\r\n.fc-state-highlight {\r\n    background: none repeat scroll 0 0 #FCF8E3;\r\n}\r\n\r\n.external-event {\r\n    padding: 5px 10px;\r\n    border-radius: 2px;\r\n    cursor: pointer;\r\n    margin-bottom: 5px;\r\n}\r\n\r\n.fc-ltr .fc-event-hori.fc-event-end, .fc-rtl .fc-event-hori.fc-event-start {\r\n    border-radius: 2px;\r\n}\r\n\r\n.fc-event, .fc-agenda .fc-event-time, .fc-event a {\r\n    padding: 4px 6px;\r\n    background-color: #1ab394;\r\n    /* background color */\r\n    border-color: #1ab394;\r\n    /* border color */\r\n}\r\n\r\n.fc-event-time, .fc-event-title {\r\n    color: #717171;\r\n    padding: 0 1px;\r\n}\r\n\r\n.ui-calendar .fc-event-time, .ui-calendar .fc-event-title {\r\n    color: #fff;\r\n}\r\n/* Chat */\r\n.chat-activity-list .chat-element {\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.chat-element:first-child {\r\n    margin-top: 0;\r\n}\r\n\r\n.chat-element {\r\n    padding-bottom: 15px;\r\n}\r\n\r\n.chat-element, .chat-element .media {\r\n    margin-top: 15px;\r\n}\r\n\r\n.chat-element, .media-body {\r\n    overflow: hidden;\r\n}\r\n\r\n.media-body {\r\n    display: block;\r\n    width: auto;\r\n}\r\n\r\n.chat-element>.pull-left {\r\n    margin-right: 10px;\r\n}\r\n\r\n.chat-element img.img-circle, .dropdown-messages-box img.img-circle {\r\n    width: 38px;\r\n    height: 38px;\r\n}\r\n\r\n.chat-element .well {\r\n    border: 1px solid #e7eaec;\r\n    box-shadow: none;\r\n    margin-top: 10px;\r\n    margin-bottom: 5px;\r\n    padding: 10px 20px;\r\n    font-size: 11px;\r\n    line-height: 16px;\r\n}\r\n\r\n.chat-element .actions {\r\n    margin-top: 10px;\r\n}\r\n\r\n.chat-element .photos {\r\n    margin: 10px 0;\r\n}\r\n\r\n.right.chat-element>.pull-right {\r\n    margin-left: 10px;\r\n}\r\n\r\n.chat-photo {\r\n    max-height: 180px;\r\n    border-radius: 4px;\r\n    overflow: hidden;\r\n    margin-right: 10px;\r\n    margin-bottom: 10px;\r\n}\r\n\r\n.chat {\r\n    margin: 0;\r\n    padding: 0;\r\n    list-style: none;\r\n}\r\n\r\n.chat li {\r\n    margin-bottom: 10px;\r\n    padding-bottom: 5px;\r\n    border-bottom: 1px dotted #B3A9A9;\r\n}\r\n\r\n.chat li.left .chat-body {\r\n    margin-left: 60px;\r\n}\r\n\r\n.chat li.right .chat-body {\r\n    margin-right: 60px;\r\n}\r\n\r\n.chat li .chat-body p {\r\n    margin: 0;\r\n    color: #777777;\r\n}\r\n\r\n.panel .slidedown .glyphicon, .chat .glyphicon {\r\n    margin-right: 5px;\r\n}\r\n\r\n.chat-panel .panel-body {\r\n    height: 350px;\r\n    overflow-y: scroll;\r\n}\r\n/* LIST GROUP */\r\na.list-group-item.active, a.list-group-item.active:hover, a.list-group-item.active:focus {\r\n    background-color: #1ab394;\r\n    border-color: #1ab394;\r\n    color: #FFFFFF;\r\n    z-index: 2;\r\n}\r\n\r\n.list-group-item-heading {\r\n    margin-top: 10px;\r\n}\r\n\r\n.list-group-item-text {\r\n    margin: 0 0 10px;\r\n    color: inherit;\r\n    font-size: 12px;\r\n    line-height: inherit;\r\n}\r\n\r\n.no-padding .list-group-item {\r\n    border-left: none;\r\n    border-right: none;\r\n    border-bottom: none;\r\n}\r\n\r\n.no-padding .list-group-item:first-child {\r\n    border-left: none;\r\n    border-right: none;\r\n    border-bottom: none;\r\n    border-top: none;\r\n}\r\n\r\n.no-padding .list-group {\r\n    margin-bottom: 0;\r\n}\r\n\r\n.list-group-item {\r\n    background-color: inherit;\r\n    border: 1px solid #e7eaec;\r\n    display: block;\r\n    margin-bottom: -1px;\r\n    padding: 10px 15px;\r\n    position: relative;\r\n}\r\n\r\n.elements-list .list-group-item {\r\n    border-left: none;\r\n    border-right: none;\r\n    /*border-top: none;*/\r\n    padding: 15px 25px;\r\n}\r\n\r\n.elements-list .list-group-item:first-child {\r\n    border-left: none;\r\n    border-right: none;\r\n    border-top: none !important;\r\n}\r\n\r\n.elements-list .list-group {\r\n    margin-bottom: 0;\r\n}\r\n\r\n.elements-list a {\r\n    color: inherit;\r\n}\r\n\r\n.elements-list .list-group-item.active, .elements-list .list-group-item:hover {\r\n    background: #f3f3f4;\r\n    color: inherit;\r\n    border-color: #e7eaec;\r\n    /*border-bottom: 1px solid #e7eaec;*/\r\n    /*border-top: 1px solid #e7eaec;*/\r\n    border-radius: 0;\r\n}\r\n\r\n.elements-list li.active {\r\n    -webkit-transition: none;\r\n    transition: none;\r\n}\r\n\r\n.element-detail-box {\r\n    padding: 25px;\r\n}\r\n/* FLOT CHART  */\r\n.flot-chart {\r\n    display: block;\r\n    height: 200px;\r\n}\r\n\r\n.widget .flot-chart.dashboard-chart {\r\n    display: block;\r\n    height: 120px;\r\n    margin-top: 40px;\r\n}\r\n\r\n.flot-chart.dashboard-chart {\r\n    display: block;\r\n    height: 180px;\r\n    margin-top: 40px;\r\n}\r\n\r\n.flot-chart-content {\r\n    width: 100%;\r\n    height: 100%;\r\n}\r\n\r\n.flot-chart-pie-content {\r\n    width: 200px;\r\n    height: 200px;\r\n    margin: auto;\r\n}\r\n\r\n.jqstooltip {\r\n    position: absolute;\r\n    display: block;\r\n    left: 0px;\r\n    top: 0px;\r\n    visibility: hidden;\r\n    background: #2b303a;\r\n    background-color: rgba(43, 48, 58, 0.8);\r\n    color: white;\r\n    text-align: left;\r\n    white-space: nowrap;\r\n    z-index: 10000;\r\n    padding: 5px 5px 5px 5px;\r\n    min-height: 22px;\r\n    border-radius: 3px;\r\n}\r\n\r\n.jqsfield {\r\n    color: white;\r\n    text-align: left;\r\n}\r\n\r\n.h-200 {\r\n    min-height: 200px;\r\n}\r\n\r\n.legendLabel {\r\n    padding-left: 5px;\r\n}\r\n\r\n.stat-list li:first-child {\r\n    margin-top: 0;\r\n}\r\n\r\n.stat-list {\r\n    list-style: none;\r\n    padding: 0;\r\n    margin: 0;\r\n}\r\n\r\n.stat-percent {\r\n    float: right;\r\n}\r\n\r\n.stat-list li {\r\n    margin-top: 15px;\r\n    position: relative;\r\n}\r\n/* DATATABLES */\r\ntable.dataTable thead .sorting, table.dataTable thead .sorting_asc:after,  table.dataTable thead .sorting_desc, table.dataTable thead .sorting_asc_disabled,  table.dataTable thead .sorting_desc_disabled {\r\n    background: transparent;\r\n}\r\n\r\ntable.dataTable thead .sorting_asc:after {\r\n    float: right;\r\n    font-family: fontawesome;\r\n}\r\n\r\ntable.dataTable thead .sorting_desc:after {\r\n    content: \"\\f0dd\";\r\n    float: right;\r\n    font-family: fontawesome;\r\n}\r\n\r\ntable.dataTable thead .sorting:after {\r\n    content: \"\\f0dc\";\r\n    float: right;\r\n    font-family: fontawesome;\r\n    color: rgba(50, 50, 50, 0.5);\r\n}\r\n\r\n.dataTables_wrapper {\r\n    padding-bottom: 30px;\r\n}\r\n/* CIRCLE */\r\n.img-circle {\r\n    border-radius: 50%;\r\n}\r\n\r\n.btn-circle {\r\n    width: 30px;\r\n    height: 30px;\r\n    padding: 6px 0;\r\n    border-radius: 15px;\r\n    text-align: center;\r\n    font-size: 12px;\r\n    line-height: 1.428571429;\r\n}\r\n\r\n.btn-circle.btn-lg {\r\n    width: 50px;\r\n    height: 50px;\r\n    padding: 10px 16px;\r\n    border-radius: 25px;\r\n    font-size: 18px;\r\n    line-height: 1.33;\r\n}\r\n\r\n.btn-circle.btn-xl {\r\n    width: 70px;\r\n    height: 70px;\r\n    padding: 10px 16px;\r\n    border-radius: 35px;\r\n    font-size: 24px;\r\n    line-height: 1.33;\r\n}\r\n\r\n.show-grid [class^=\"col-\"] {\r\n    padding-top: 10px;\r\n    padding-bottom: 10px;\r\n    border: 1px solid #ddd;\r\n    background-color: #eee !important;\r\n}\r\n\r\n.show-grid {\r\n    margin: 15px 0;\r\n}\r\n/* ANIMATION */\r\n.css-animation-box h1 {\r\n    font-size: 44px;\r\n}\r\n\r\n.animation-efect-links a {\r\n    padding: 4px 6px;\r\n    font-size: 12px;\r\n}\r\n\r\n#animation_box {\r\n    background-color: #f9f8f8;\r\n    border-radius: 16px;\r\n    width: 80%;\r\n    margin: 0 auto;\r\n    padding-top: 80px;\r\n}\r\n\r\n.animation-text-box {\r\n    position: absolute;\r\n    margin-top: 40px;\r\n    left: 50%;\r\n    margin-left: -100px;\r\n    width: 200px;\r\n}\r\n\r\n.animation-text-info {\r\n    position: absolute;\r\n    margin-top: -60px;\r\n    left: 50%;\r\n    margin-left: -100px;\r\n    width: 200px;\r\n    font-size: 10px;\r\n}\r\n\r\n.animation-text-box h2 {\r\n    font-size: 54px;\r\n    font-weight: 600;\r\n    margin-bottom: 5px;\r\n}\r\n\r\n.animation-text-box p {\r\n    font-size: 12px;\r\n    text-transform: uppercase;\r\n}\r\n/* PEACE */\r\n.pace {\r\n    -webkit-pointer-events: none;\r\n    pointer-events: none;\r\n    -webkit-user-select: none;\r\n    -moz-user-select: none;\r\n    -ms-user-select: none;\r\n    user-select: none;\r\n}\r\n\r\n.pace-inactive {\r\n    display: none;\r\n}\r\n\r\n.pace .pace-progress {\r\n    background: #1ab394;\r\n    position: fixed;\r\n    z-index: 2000;\r\n    top: 0;\r\n    width: 100%;\r\n    height: 2px;\r\n}\r\n\r\n.pace-inactive {\r\n    display: none;\r\n}\r\n/* WIDGETS */\r\n.widget {\r\n    border-radius: 5px;\r\n    padding: 15px 20px;\r\n    margin-bottom: 10px;\r\n    margin-top: 10px;\r\n}\r\n\r\n.widget.style1 h2 {\r\n    font-size: 30px;\r\n}\r\n\r\n.widget h2, .widget h3 {\r\n    margin-top: 5px;\r\n    margin-bottom: 0;\r\n}\r\n\r\n.widget-text-box {\r\n    padding: 20px;\r\n    border: 1px solid #e7eaec;\r\n    background: #ffffff;\r\n}\r\n\r\n.widget-head-color-box {\r\n    border-radius: 5px 5px 0px 0px;\r\n    margin-top: 10px;\r\n}\r\n\r\n.widget .flot-chart {\r\n    height: 100px;\r\n}\r\n\r\n.vertical-align div {\r\n    display: inline-block;\r\n    vertical-align: middle;\r\n}\r\n\r\n.vertical-align h2, .vertical-align h3 {\r\n    margin: 0;\r\n}\r\n\r\n.todo-list {\r\n    list-style: none outside none;\r\n    margin: 0;\r\n    padding: 0;\r\n    font-size: 14px;\r\n}\r\n\r\n.todo-list.small-list {\r\n    font-size: 12px;\r\n}\r\n\r\n.todo-list.small-list>li {\r\n    background: #f3f3f4;\r\n    border-left: none;\r\n    border-right: none;\r\n    border-radius: 4px;\r\n    color: inherit;\r\n    margin-bottom: 2px;\r\n    padding: 6px 6px 6px 12px;\r\n}\r\n\r\n.todo-list.small-list .btn-xs, .todo-list.small-list .btn-group-xs>.btn {\r\n    border-radius: 5px;\r\n    font-size: 10px;\r\n    line-height: 1.5;\r\n    padding: 1px 2px 1px 5px;\r\n}\r\n\r\n.todo-list>li {\r\n    background: #f3f3f4;\r\n    border-left: 6px solid #e7eaec;\r\n    border-right: 6px solid #e7eaec;\r\n    border-radius: 4px;\r\n    color: inherit;\r\n    margin-bottom: 2px;\r\n    padding: 10px;\r\n}\r\n\r\n.todo-list .handle {\r\n    cursor: move;\r\n    display: inline-block;\r\n    font-size: 16px;\r\n    margin: 0 5px;\r\n}\r\n\r\n.todo-list>li .label {\r\n    font-size: 9px;\r\n    margin-left: 10px;\r\n}\r\n\r\n.check-link {\r\n    font-size: 16px;\r\n}\r\n\r\n.todo-completed {\r\n    text-decoration: line-through;\r\n}\r\n\r\n.geo-statistic h1 {\r\n    font-size: 36px;\r\n    margin-bottom: 0;\r\n}\r\n\r\n.glyphicon.fa {\r\n    font-family: \"FontAwesome\";\r\n}\r\n/* INPUTS */\r\n.inline {\r\n    display: inline-block !important;\r\n}\r\n\r\n.input-s-sm {\r\n    width: 120px;\r\n}\r\n\r\n.input-s {\r\n    width: 200px;\r\n}\r\n\r\n.input-s-lg {\r\n    width: 250px;\r\n}\r\n\r\n.i-checks {\r\n    padding-left: 0;\r\n}\r\n\r\n.form-control, .single-line {\r\n    background: #FFFFFF none;\r\n    border: 1px solid #e5e6e7;\r\n    border-radius: 4px;\r\n    color: inherit;\r\n    display: block;\r\n    padding: 3px 6px 4px;\r\n    -webkit-transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s  ease-in-out 0s;\r\n    transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s  ease-in-out 0s;\r\n    width: 100%;\r\n    height: 31px;\r\n    font-size: 14px;\r\n}\r\n\r\n.form-control.kv-fileinput-caption {\r\n    height: 34px!important;\r\n}\r\n\r\n.form-control:focus, .single-line:focus {\r\n    border-color: #3c8dbc !important;\r\n}\r\n\r\n.has-success .form-control {\r\n    border-color: #1ab394;\r\n}\r\n\r\n.has-warning .form-control {\r\n    border-color: #f8ac59;\r\n}\r\n\r\n.has-error .form-control {\r\n    border-color: #ed5565;\r\n}\r\n\r\n.has-success .control-label {\r\n    color: #1ab394;\r\n}\r\n\r\n.has-warning .control-label {\r\n    color: #f8ac59;\r\n}\r\n\r\n.has-error .control-label {\r\n    color: #ed5565;\r\n}\r\n\r\n.input-group-addon {\r\n    background-color: #fff;\r\n    border: 1px solid #e5e6e7;\r\n    border-radius: 4px;\r\n    color: inherit;\r\n    font-size: 14px;\r\n    font-weight: 400;\r\n    line-height: 1;\r\n    padding: 6px 12px;\r\n    text-align: center;\r\n}\r\n\r\n.spinner-buttons.input-group-btn .btn-xs {\r\n    line-height: 1.13;\r\n}\r\n\r\n.spinner-buttons.input-group-btn {\r\n    width: 20%;\r\n}\r\n\r\n.noUi-connect {\r\n    background: none repeat scroll 0 0 #1ab394;\r\n    box-shadow: none;\r\n}\r\n\r\n.slider_red .noUi-connect {\r\n    background: none repeat scroll 0 0 #ed5565;\r\n    box-shadow: none;\r\n}\r\n/* UI Sortable */\r\n.ui-sortable .ibox-title {\r\n    cursor: move;\r\n}\r\n\r\n.ui-sortable-placeholder {\r\n    border: 1px dashed #cecece !important;\r\n    visibility: visible !important;\r\n    background: #e7eaec;\r\n}\r\n\r\n.ibox.ui-sortable-placeholder {\r\n    margin: 0px 0px 23px !important;\r\n}\r\n/* Tabs */\r\n.tabs-container .panel-body {\r\n    background: #fff;\r\n    border: 1px solid #e7eaec;\r\n    border-radius: 2px;\r\n    padding: 20px;\r\n    position: relative;\r\n}\r\n\r\n.tabs-container .nav-tabs>li.active>a, .tabs-container .nav-tabs>li.active>a:hover,  .tabs-container .nav-tabs>li.active>a:focus {\r\n    border: 1px solid #e7eaec;\r\n    border-bottom-color: transparent;\r\n    background-color: #fff;\r\n}\r\n\r\n.tabs-container .nav-tabs>li {\r\n    float: left;\r\n    margin-bottom: -1px;\r\n}\r\n\r\n.tabs-container .tab-pane .panel-body {\r\n    border-top: none;\r\n}\r\n\r\n.tabs-container .nav-tabs>li.active>a, .tabs-container .nav-tabs>li.active>a:hover,  .tabs-container .nav-tabs>li.active>a:focus {\r\n    border: 1px solid #e7eaec;\r\n    border-bottom-color: transparent;\r\n}\r\n\r\n.tabs-container .nav-tabs {\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.tabs-container .tab-pane .panel-body {\r\n    border-top: none;\r\n}\r\n\r\n.tabs-container .tabs-left .tab-pane .panel-body, .tabs-container .tabs-right .tab-pane .panel-body {\r\n    border-top: 1px solid #e7eaec;\r\n}\r\n\r\n.tabs-container .nav-tabs>li a:hover {\r\n    background: transparent;\r\n    border-color: transparent;\r\n}\r\n\r\n.tabs-container .tabs-below>.nav-tabs, .tabs-container .tabs-right>.nav-tabs,  .tabs-container .tabs-left>.nav-tabs {\r\n    border-bottom: 0;\r\n}\r\n\r\n.tabs-container .tabs-left .panel-body {\r\n    position: static;\r\n}\r\n\r\n.tabs-container .tabs-left>.nav-tabs, .tabs-container .tabs-right>.nav-tabs {\r\n    width: 20%;\r\n}\r\n\r\n.tabs-container .tabs-left .panel-body {\r\n    width: 80%;\r\n    margin-left: 20%;\r\n}\r\n\r\n.tabs-container .tabs-right .panel-body {\r\n    width: 80%;\r\n    margin-right: 20%;\r\n}\r\n\r\n.tabs-container .tab-content>.tab-pane, .tabs-container .pill-content>.pill-pane {\r\n    display: none;\r\n}\r\n\r\n.tabs-container .tab-content>.active, .tabs-container .pill-content>.active {\r\n    display: block;\r\n}\r\n\r\n.tabs-container .tabs-below>.nav-tabs {\r\n    border-top: 1px solid #e7eaec;\r\n}\r\n\r\n.tabs-container .tabs-below>.nav-tabs>li {\r\n    margin-top: -1px;\r\n    margin-bottom: 0;\r\n}\r\n\r\n.tabs-container .tabs-below>.nav-tabs>li>a {\r\n    border-radius: 0 0 4px 4px;\r\n}\r\n\r\n.tabs-container .tabs-below>.nav-tabs>li>a:hover, .tabs-container .tabs-below>.nav-tabs>li>a:focus {\r\n    border-top-color: #e7eaec;\r\n    border-bottom-color: transparent;\r\n}\r\n\r\n.tabs-container .tabs-left>.nav-tabs>li, .tabs-container .tabs-right>.nav-tabs>li {\r\n    float: none;\r\n}\r\n\r\n.tabs-container .tabs-left>.nav-tabs>li>a, .tabs-container .tabs-right>.nav-tabs>li>a {\r\n    min-width: 74px;\r\n    margin-right: 0;\r\n    margin-bottom: 3px;\r\n}\r\n\r\n.tabs-container .tabs-left>.nav-tabs {\r\n    float: left;\r\n    margin-right: 19px;\r\n}\r\n\r\n.tabs-container .tabs-left>.nav-tabs>li>a {\r\n    margin-right: -1px;\r\n    border-radius: 4px 0 0 4px;\r\n}\r\n\r\n.tabs-container .tabs-left>.nav-tabs .active>a, .tabs-container .tabs-left>.nav-tabs .active>a:hover,  .tabs-container .tabs-left>.nav-tabs .active>a:focus {\r\n    border-color: #e7eaec transparent #e7eaec #e7eaec;\r\n    border-right-color: #ffffff;\r\n}\r\n\r\n.tabs-container .tabs-right>.nav-tabs {\r\n    float: right;\r\n    margin-left: 19px;\r\n}\r\n\r\n.tabs-container .tabs-right>.nav-tabs>li>a {\r\n    margin-left: -1px;\r\n    border-radius: 0 4px 4px 0;\r\n}\r\n\r\n.tabs-container .tabs-right>.nav-tabs .active>a, .tabs-container .tabs-right>.nav-tabs .active>a:hover,  .tabs-container .tabs-right>.nav-tabs .active>a:focus {\r\n    border-color: #e7eaec #e7eaec #e7eaec transparent;\r\n    border-left-color: #ffffff;\r\n    z-index: 1;\r\n}\r\n/*SWITCHES */\r\n\r\n.onoffswitch{\r\n    position: relative;\r\n    width: 54px;\r\n    -webkit-user-select: none;\r\n    -moz-user-select: none;\r\n    -ms-user-select: none;\r\n}\r\n\r\n.onoffswitch-checkbox {\r\n    display: none;\r\n}\r\n\r\n.onoffswitch-label {\r\n    display: block;\r\n    overflow: hidden;\r\n    cursor: pointer;\r\n    border: 2px solid #1AB394;\r\n    border-radius: 3px;\r\n}\r\n\r\n.onoffswitch-inner {\r\n    display: block;\r\n    width: 200%;\r\n    margin-left: -100%;\r\n    -webkit-transition: margin 0.3s ease-in 0s;\r\n    transition: margin 0.3s ease-in 0s;\r\n}\r\n\r\n.onoffswitch-inner:before, .onoffswitch-inner:after {\r\n    display: block;\r\n    float: left;\r\n    width: 50%;\r\n    /* height: 16px; */\r\n    padding: 0;\r\n    /*  line-height: 16px; */\r\n    font-size: 10px;\r\n    color: white;\r\n    font-family: Trebuchet, Arial, sans-serif;\r\n    font-weight: bold;\r\n    box-sizing: border-box;\r\n}\r\n\r\n.onoffswitch-inner:before {\r\n    content: \"ON\";\r\n    padding-left: 7px;\r\n    background-color: #1AB394;\r\n    color: #FFFFFF;\r\n}\r\n\r\n.onoffswitch-inner:after {\r\n    content: \"OFF\";\r\n    padding-right: 7px;\r\n    background-color: #FFFFFF;\r\n    color: #919191;\r\n    text-align: right;\r\n}\r\n\r\n.onoffswitch-switch {\r\n    display: block;\r\n    width: 18px;\r\n    margin: 0px;\r\n    background: #FFFFFF;\r\n    border: 2px solid #1AB394;\r\n    border-radius: 3px;\r\n    position: absolute;\r\n    top: 0;\r\n    bottom: 0;\r\n    right: 36px;\r\n    -webkit-transition: all 0.3s ease-in 0s;\r\n    transition: all 0.3s ease-in 0s;\r\n}\r\n\r\n.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-inner {\r\n    margin-left: 0;\r\n}\r\n\r\n.onoffswitch-checkbox:checked+.onoffswitch-label .onoffswitch-switch {\r\n    right: 0px;\r\n}\r\n/* Nestable list */\r\n.dd {\r\n    position: relative;\r\n    display: block;\r\n    margin: 0;\r\n    padding: 0;\r\n    list-style: none;\r\n    font-size: 13px;\r\n    line-height: 20px;\r\n}\r\n\r\n.dd-list {\r\n    display: block;\r\n    position: relative;\r\n    margin: 0;\r\n    padding: 0;\r\n    list-style: none;\r\n}\r\n\r\n.dd-list .dd-list {\r\n    padding-left: 30px;\r\n}\r\n\r\n.dd-collapsed .dd-list {\r\n    display: none;\r\n}\r\n\r\n.dd-item, .dd-empty, .dd-placeholder {\r\n    display: block;\r\n    position: relative;\r\n    margin: 0;\r\n    padding: 0;\r\n    min-height: 20px;\r\n    font-size: 13px;\r\n    line-height: 20px;\r\n}\r\n\r\n.dd-handle {\r\n    display: block;\r\n    margin: 5px 0;\r\n    padding: 5px 10px;\r\n    color: #333;\r\n    text-decoration: none;\r\n    border: 1px solid #e7eaec;\r\n    background: #f5f5f5;\r\n    border-radius: 3px;\r\n    box-sizing: border-box;\r\n    -moz-box-sizing: border-box;\r\n}\r\n\r\n.dd-handle span {\r\n    font-weight: bold;\r\n}\r\n\r\n.dd-handle:hover {\r\n    background: #f0f0f0;\r\n    cursor: pointer;\r\n    font-weight: bold;\r\n}\r\n\r\n.dd-item>button {\r\n    display: block;\r\n    position: relative;\r\n    cursor: pointer;\r\n    float: left;\r\n    width: 25px;\r\n    height: 20px;\r\n    margin: 5px 0;\r\n    padding: 0;\r\n    text-indent: 100%;\r\n    white-space: nowrap;\r\n    overflow: hidden;\r\n    border: 0;\r\n    background: transparent;\r\n    font-size: 12px;\r\n    line-height: 1;\r\n    text-align: center;\r\n    font-weight: bold;\r\n}\r\n\r\n.dd-item>button:before {\r\n    content: '+';\r\n    display: block;\r\n    position: absolute;\r\n    width: 100%;\r\n    text-align: center;\r\n    text-indent: 0;\r\n}\r\n\r\n.dd-item>button[data-action=\"collapse\"]:before {\r\n    content: '-';\r\n}\r\n\r\n#nestable2 .dd-item>button {\r\n    font-family: FontAwesome;\r\n    height: 34px;\r\n    width: 33px;\r\n    color: #c1c1c1;\r\n}\r\n\r\n#nestable2 .dd-item>button:before {\r\n    content: \"\\f067\";\r\n}\r\n\r\n#nestable2 .dd-item>button[data-action=\"collapse\"]:before {\r\n    content: \"\\f068\";\r\n}\r\n\r\n.dd-placeholder, .dd-empty {\r\n    margin: 5px 0;\r\n    padding: 0;\r\n    min-height: 30px;\r\n    background: #f2fbff;\r\n    border: 1px dashed #b6bcbf;\r\n    box-sizing: border-box;\r\n    -moz-box-sizing: border-box;\r\n}\r\n\r\n.dd-empty {\r\n    border: 1px dashed #bbb;\r\n    min-height: 100px;\r\n    background-color: #e5e5e5;\r\n    background-image: -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent  75%, #ffffff 75%, #ffffff),  -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent  75%, #ffffff 75%, #ffffff);\r\n    background-image: linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%,  #ffffff 75%, #ffffff),  linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%,  #ffffff 75%, #ffffff);\r\n    background-size: 60px 60px;\r\n    background-position: 0 0, 30px 30px;\r\n}\r\n\r\n.dd-dragel {\r\n    position: absolute;\r\n    z-index: 9999;\r\n    pointer-events: none;\r\n}\r\n\r\n.dd-dragel>.dd-item .dd-handle {\r\n    margin-top: 0;\r\n}\r\n\r\n.dd-dragel .dd-handle {\r\n    box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1);\r\n}\r\n/**\r\n* Nestable Extras\r\n*/\r\n.nestable-lists {\r\n    display: block;\r\n    clear: both;\r\n    padding: 30px 0;\r\n    width: 100%;\r\n    border: 0;\r\n    border-top: 2px solid #ddd;\r\n    border-bottom: 2px solid #ddd;\r\n}\r\n\r\n#nestable-menu {\r\n    padding: 0;\r\n    margin: 10px 0 20px 0;\r\n}\r\n\r\n#nestable-output, #nestable2-output {\r\n    width: 100%;\r\n    font-size: 0.75em;\r\n    line-height: 1.333333em;\r\n    font-family: lucida grande, lucida sans unicode, helvetica, arial,  sans-serif;\r\n    padding: 5px;\r\n    box-sizing: border-box;\r\n    -moz-box-sizing: border-box;\r\n}\r\n\r\n#nestable2 .dd-handle {\r\n    color: inherit;\r\n    border: 1px dashed #e7eaec;\r\n    background: #f3f3f4;\r\n    padding: 10px;\r\n}\r\n\r\n#nestable2 .dd-handle:hover {\r\n    /*background: #bbb;*/\r\n}\r\n\r\n#nestable2 span.label {\r\n    margin-right: 10px;\r\n}\r\n\r\n#nestable-output, #nestable2-output {\r\n    font-size: 12px;\r\n    padding: 25px;\r\n    box-sizing: border-box;\r\n    -moz-box-sizing: border-box;\r\n}\r\n/* CodeMirror */\r\n.CodeMirror {\r\n    border: 1px solid #eee;\r\n    height: auto;\r\n}\r\n\r\n.CodeMirror-scroll {\r\n    overflow-y: hidden;\r\n    overflow-x: auto;\r\n}\r\n/* Google Maps */\r\n.google-map {\r\n    height: 300px;\r\n}\r\n/* ngGrid */\r\n.gridStyle {\r\n    border: 1px solid #d4d4d4;\r\n    width: 100%;\r\n    height: 400px;\r\n}\r\n\r\n.gridStyle2 {\r\n    border: 1px solid #d4d4d4;\r\n    width: 500px;\r\n    height: 300px;\r\n}\r\n\r\n.ngH eaderCell {\r\n    border-right: none;\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.ngCell {\r\n    border-right: none;\r\n}\r\n\r\n.ngTopPanel {\r\n    background: #F5F5F6;\r\n}\r\n\r\n.ngRow.even {\r\n    background: #f9f9f9;\r\n}\r\n\r\n.ngRow.selected {\r\n    background: #EBF2F1;\r\n}\r\n\r\n.ngRow {\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.ngCell {\r\n    background-color: transparent;\r\n}\r\n\r\n.ngHeaderCell {\r\n    border-right: none;\r\n}\r\n/* Toastr custom style */\r\n#toast-container>.toast {\r\n    background-image: none !important;\r\n}\r\n\r\n#toast-container>.toast:before {\r\n    position: fixed;\r\n    font-family: FontAwesome;\r\n    font-size: 24px;\r\n    line-height: 24px;\r\n    float: left;\r\n    color: #FFF;\r\n    padding-right: 0.5em;\r\n    margin: auto 0.5em auto -1.5em;\r\n}\r\n\r\n#toast-container>div {\r\n    box-shadow: 0 0 3px #999;\r\n    opacity: .9;\r\n    -ms-filter: alpha(opacity = 90);\r\n    filter: alpha(opacity = 90);\r\n}\r\n\r\n#toast-container>:hover {\r\n    box-shadow: 0 0 4px #999;\r\n    opacity: 1;\r\n    -ms-filter: alpha(opacity = 100);\r\n    filter: alpha(opacity = 100);\r\n    cursor: pointer;\r\n}\r\n\r\n.toast {\r\n    background-color: #1ab394;\r\n}\r\n\r\n.toast-success {\r\n    background-color: #1ab394;\r\n}\r\n\r\n.toast-error {\r\n    background-color: #ed5565;\r\n}\r\n\r\n.toast-info {\r\n    background-color: #23c6c8;\r\n}\r\n\r\n.toast-warning {\r\n    background-color: #f8ac59;\r\n}\r\n\r\n.toast-top-full-width {\r\n    margin-top: 20px;\r\n}\r\n\r\n.toast-bottom-full-width {\r\n    margin-bottom: 20px;\r\n}\r\n/* Image cropper style */\r\n.img-container, .img-preview {\r\n    overflow: hidden;\r\n    text-align: center;\r\n    width: 100%;\r\n}\r\n\r\n.img-preview-sm {\r\n    height: 130px;\r\n    width: 200px;\r\n}\r\n/* Forum styles  */\r\n.forum-post-container .media {\r\n    margin: 10px 10px 10px 10px;\r\n    padding: 20px 10px 20px 10px;\r\n    border-bottom: 1px solid #f1f1f1;\r\n}\r\n\r\n.forum-avatar {\r\n    float: left;\r\n    margin-right: 20px;\r\n    text-align: center;\r\n    width: 110px;\r\n}\r\n\r\n.forum-avatar .img-circle {\r\n    height: 48px;\r\n    width: 48px;\r\n}\r\n\r\n.author-info {\r\n    color: #676a6c;\r\n    font-size: 11px;\r\n    margin-top: 5px;\r\n    text-align: center;\r\n}\r\n\r\n.forum-post-info {\r\n    padding: 9px 12px 6px 12px;\r\n    background: #f9f9f9;\r\n    border: 1px solid #f1f1f1;\r\n}\r\n\r\n.media-body>.media {\r\n    background: #f9f9f9;\r\n    border-radius: 3px;\r\n    border: 1px solid #f1f1f1;\r\n}\r\n\r\n.forum-post-container .media-body .photos {\r\n    margin: 10px 0;\r\n}\r\n\r\n.forum-photo {\r\n    max-width: 140px;\r\n    border-radius: 3px;\r\n}\r\n\r\n.media-body>.media .forum-avatar {\r\n    width: 70px;\r\n    margin-right: 10px;\r\n}\r\n\r\n.media-body>.media .forum-avatar .img-circle {\r\n    height: 38px;\r\n    width: 38px;\r\n}\r\n\r\n.mid-icon {\r\n    font-size: 66px;\r\n}\r\n\r\n.forum-item {\r\n    margin: 10px 0;\r\n    padding: 10px 0 20px;\r\n    border-bottom: 1px solid #f1f1f1;\r\n}\r\n\r\n.views-number {\r\n    font-size: 24px;\r\n    line-height: 18px;\r\n    font-weight: 400;\r\n}\r\n\r\n.forum-container, .forum-post-container {\r\n    padding: 30px !important;\r\n}\r\n\r\n.forum-item small {\r\n    color: #999;\r\n}\r\n\r\n.forum-item .forum-sub-title {\r\n    color: #999;\r\n    margin-left: 50px;\r\n}\r\n\r\n.forum-title {\r\n    margin: 15px 0 15px 0;\r\n}\r\n\r\n.forum-info {\r\n    text-align: center;\r\n}\r\n\r\n.forum-desc {\r\n    color: #999;\r\n}\r\n\r\n.forum-icon {\r\n    float: left;\r\n    width: 30px;\r\n    margin-right: 20px;\r\n    text-align: center;\r\n}\r\n\r\na.forum-item-title {\r\n    color: inherit;\r\n    display: block;\r\n    font-size: 18px;\r\n    font-weight: 600;\r\n}\r\n\r\na.forum-item-title:hover {\r\n    color: inherit;\r\n}\r\n\r\n.forum-icon .fa {\r\n    font-size: 30px;\r\n    margin-top: 8px;\r\n    color: #9b9b9b;\r\n}\r\n\r\n.forum-item.active .fa {\r\n    color: #1ab394;\r\n}\r\n\r\n.forum-item.active a.forum-item-title {\r\n    color: #1ab394;\r\n}\r\n\r\n@media ( max-width : 992px) {\r\n    .forum-info {\r\n        margin: 15px 0 10px 0px;\r\n        /* Comment this is you want to show forum info in small devices */\r\n        display: none;\r\n    }\r\n\r\n    .forum-desc {\r\n        float: none !important;\r\n    }\r\n}\r\n/* New Timeline style */\r\n.vertical-container {\r\n    /* this class is used to give a max-width to the element it is applied to, and center it horizontally when it reaches that max-width */\r\n    width: 90%;\r\n    max-width: 1170px;\r\n    margin: 0 auto;\r\n}\r\n\r\n.vertical-container::after {\r\n    /* clearfix */\r\n    content: '';\r\n    display: table;\r\n    clear: both;\r\n}\r\n\r\n#vertical-timeline {\r\n    position: relative;\r\n    padding: 0;\r\n    margin-top: 2em;\r\n    margin-bottom: 2em;\r\n}\r\n\r\n#vertical-timeline::before {\r\n    content: '';\r\n    position: absolute;\r\n    top: 0;\r\n    left: 18px;\r\n    height: 100%;\r\n    width: 4px;\r\n    background: #f1f1f1;\r\n}\r\n\r\n.vertical-timeline-content .btn {\r\n    float: right;\r\n}\r\n\r\n#vertical-timeline.light-timeline:before {\r\n    background: #e7eaec;\r\n}\r\n\r\n.dark-timeline .vertical-timeline-content:before {\r\n    border-color: transparent #f5f5f5 transparent transparent;\r\n}\r\n\r\n.dark-timeline.center-orientation .vertical-timeline-content:before {\r\n    border-color: transparent transparent transparent #f5f5f5;\r\n}\r\n\r\n.dark-timeline .vertical-timeline-block:nth-child(2n) .vertical-timeline-content:before,  .dark-timeline.center-orientation .vertical-timeline-block:nth-child(2n) .vertical-timeline-content:before {\r\n    border-color: transparent #f5f5f5 transparent transparent;\r\n}\r\n\r\n.dark-timeline .vertical-timeline-content, .dark-timeline.center-orientation .vertical-timeline-content {\r\n    background: #f5f5f5;\r\n}\r\n\r\n@media only screen and (min-width: 1170px) {\r\n    #vertical-timeline.center-orientation {\r\n        margin-top: 3em;\r\n        margin-bottom: 3em;\r\n    }\r\n\r\n    #vertical-timeline.center-orientation:before {\r\n        left: 50%;\r\n        margin-left: -2px;\r\n    }\r\n}\r\n\r\n@media only screen and (max-width: 1170px) {\r\n    .center-orientation.dark-timeline .vertical-timeline-content:before {\r\n        border-color: transparent #f5f5f5 transparent transparent;\r\n    }\r\n}\r\n\r\n.vertical-timeline-block {\r\n    position: relative;\r\n    margin: 2em 0;\r\n}\r\n\r\n.vertical-timeline-block:after {\r\n    content: \"\";\r\n    display: table;\r\n    clear: both;\r\n}\r\n\r\n.vertical-timeline-block:first-child {\r\n    margin-top: 0;\r\n}\r\n\r\n.vertical-timeline-block:last-child {\r\n    margin-bottom: 0;\r\n}\r\n\r\n@media only screen and (min-width: 1170px) {\r\n    .center-orientation .vertical-timeline-block {\r\n        margin: 4em 0;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-block:first-child {\r\n        margin-top: 0;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-block:last-child {\r\n        margin-bottom: 0;\r\n    }\r\n}\r\n\r\n.vertical-timeline-icon {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 40px;\r\n    height: 40px;\r\n    border-radius: 50%;\r\n    font-size: 16px;\r\n    border: 3px solid #f1f1f1;\r\n    text-align: center;\r\n}\r\n\r\n.vertical-timeline-icon i {\r\n    display: block;\r\n    width: 24px;\r\n    height: 24px;\r\n    position: relative;\r\n    left: 50%;\r\n    top: 50%;\r\n    margin-left: -12px;\r\n    margin-top: -9px;\r\n}\r\n\r\n@media only screen and (min-width: 1170px) {\r\n    .center-orientation .vertical-timeline-icon {\r\n        width: 50px;\r\n        height: 50px;\r\n        left: 50%;\r\n        margin-left: -25px;\r\n        -webkit-transform: translateZ(0);\r\n        -webkit-backface-visibility: hidden;\r\n        font-size: 19px;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-icon i {\r\n        margin-left: -12px;\r\n        margin-top: -10px;\r\n    }\r\n\r\n    .center-orientation .cssanimations .vertical-timeline-icon.is-hidden {\r\n        visibility: hidden;\r\n    }\r\n}\r\n\r\n.vertical-timeline-content {\r\n    position: relative;\r\n    margin-left: 60px;\r\n    background: white;\r\n    border-radius: 0.25em;\r\n    padding: 1em;\r\n}\r\n\r\n.vertical-timeline-content:after {\r\n    content: \"\";\r\n    display: table;\r\n    clear: both;\r\n}\r\n\r\n.vertical-timeline-content h2 {\r\n    font-weight: 400;\r\n    margin-top: 4px;\r\n}\r\n\r\n.vertical-timeline-content p {\r\n    margin: 1em 0;\r\n    line-height: 1.6;\r\n}\r\n\r\n.vertical-timeline-content .vertical-date {\r\n    float: left;\r\n    font-weight: 500;\r\n}\r\n\r\n.vertical-date small {\r\n    color: #1ab394;\r\n    font-weight: 400;\r\n}\r\n\r\n.vertical-timeline-content::before {\r\n    content: '';\r\n    position: absolute;\r\n    top: 16px;\r\n    right: 100%;\r\n    height: 0;\r\n    width: 0;\r\n    border: 7px solid transparent;\r\n    border-right: 7px solid white;\r\n}\r\n\r\n@media only screen and (min-width: 768px) {\r\n    .vertical-timeline-content h2 {\r\n        font-size: 18px;\r\n    }\r\n\r\n    .vertical-timeline-content p {\r\n        font-size: 13px;\r\n    }\r\n}\r\n\r\n@media only screen and (min-width: 1170px) {\r\n    .center-orientation .vertical-timeline-content {\r\n        margin-left: 0;\r\n        padding: 1.6em;\r\n        width: 45%;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-content::before {\r\n        top: 24px;\r\n        left: 100%;\r\n        border-color: transparent;\r\n        border-left-color: white;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-content .btn {\r\n        float: left;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-content .vertical-date {\r\n        position: absolute;\r\n        width: 100%;\r\n        left: 122%;\r\n        top: 2px;\r\n        font-size: 14px;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content {\r\n        float: right;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content::before {\r\n        top: 24px;\r\n        left: auto;\r\n        right: 100%;\r\n        border-color: transparent;\r\n        border-right-color: white;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content .btn {\r\n        float: right;\r\n    }\r\n\r\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content .vertical-date {\r\n        left: auto;\r\n        right: 122%;\r\n        text-align: right;\r\n    }\r\n\r\n    .center-orientation .cssanimations .vertical-timeline-content.is-hidden {\r\n        visibility: hidden;\r\n    }\r\n}\r\n\r\n.sidebard-panel {\r\n    width: 220px;\r\n    background: #ebebed;\r\n    padding: 10px 20px;\r\n    position: absolute;\r\n    right: 0;\r\n}\r\n\r\n.sidebard-panel .feed-element img.img-circle {\r\n    width: 32px;\r\n    height: 32px;\r\n}\r\n\r\n.sidebard-panel .feed-element, .media-body, .sidebard-panel p {\r\n    font-size: 12px;\r\n}\r\n\r\n.sidebard-panel .feed-element {\r\n    margin-top: 20px;\r\n    padding-bottom: 0;\r\n}\r\n\r\n.sidebard-panel .list-group {\r\n    margin-bottom: 10px;\r\n}\r\n\r\n.sidebard-panel .list-group .list-group-item {\r\n    padding: 5px 0;\r\n    font-size: 12px;\r\n    border: 0;\r\n}\r\n\r\n.sidebar-content .wrapper, .wrapper.sidebar-content {\r\n    padding-right: 240px !important;\r\n}\r\n\r\n#right-sidebar {\r\n    background-color: #fff;\r\n    border-left: 1px solid #e7eaec;\r\n    border-top: 1px solid #e7eaec;\r\n    overflow: hidden;\r\n    position: fixed;\r\n    top: 60px;\r\n    width: 260px !important;\r\n    z-index: 1009;\r\n    bottom: 0;\r\n    right: -260px;\r\n}\r\n\r\n#right-sidebar.sidebar-open {\r\n    right: 0;\r\n}\r\n\r\n#right-sidebar.sidebar-open.sidebar-top {\r\n    top: 0;\r\n    border-top: none;\r\n}\r\n\r\n.sidebar-container ul.nav-tabs {\r\n    border: none;\r\n}\r\n\r\n.sidebar-container ul.nav-tabs.navs-4 li {\r\n    width: 25%;\r\n}\r\n\r\n.sidebar-container ul.nav-tabs.navs-3 li {\r\n    width: 33.3333%;\r\n}\r\n\r\n.sidebar-container ul.nav-tabs.navs-2 li {\r\n    width: 50%;\r\n}\r\n\r\n.sidebar-container ul.nav-tabs li {\r\n    border: none;\r\n}\r\n\r\n.sidebar-container ul.nav-tabs li a {\r\n    border: none;\r\n    padding: 12px 10px;\r\n    margin: 0;\r\n    border-radius: 0;\r\n    background: #2f4050;\r\n    color: #fff;\r\n    text-align: center;\r\n    border-right: 1px solid #334556;\r\n}\r\n\r\n.sidebar-container ul.nav-tabs li.active a {\r\n    border: none;\r\n    background: #f9f9f9;\r\n    color: #676a6c;\r\n    font-weight: bold;\r\n}\r\n\r\n.sidebar-container .nav-tabs>li.active>a:hover, .sidebar-container .nav-tabs>li.active>a:focus {\r\n    border: none;\r\n}\r\n\r\n.sidebar-container ul.sidebar-list {\r\n    margin: 0;\r\n    padding: 0;\r\n}\r\n\r\n.sidebar-container ul.sidebar-list li {\r\n    border-bottom: 1px solid #e7eaec;\r\n    padding: 15px 20px;\r\n    list-style: none;\r\n    font-size: 12px;\r\n}\r\n\r\n.sidebar-container .sidebar-message:nth-child(2n+2) {\r\n    background: #f9f9f9;\r\n}\r\n\r\n.sidebar-container ul.sidebar-list li a {\r\n    text-decoration: none;\r\n    color: inherit;\r\n}\r\n\r\n.sidebar-container .sidebar-content {\r\n    padding: 15px 20px;\r\n    font-size: 12px;\r\n}\r\n\r\n.sidebar-container .sidebar-title {\r\n    background: #f9f9f9;\r\n    padding: 20px;\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.sidebar-container .sidebar-title h3 {\r\n    margin-bottom: 3px;\r\n    padding-left: 2px;\r\n}\r\n\r\n.sidebar-container .tab-content h4 {\r\n    margin-bottom: 5px;\r\n}\r\n\r\n.sidebar-container .sidebar-message>a>.pull-left {\r\n    margin-right: 10px;\r\n}\r\n\r\n.sidebar-container .sidebar-message>a {\r\n    text-decoration: none;\r\n    color: inherit;\r\n}\r\n\r\n.sidebar-container .sidebar-message {\r\n    padding: 15px 20px;\r\n}\r\n\r\n.sidebar-container .sidebar-message .message-avatar {\r\n    height: 38px;\r\n    width: 38px;\r\n    border-radius: 50%;\r\n}\r\n\r\n.sidebar-container .setings-item {\r\n    padding: 15px 20px;\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\nbody {\r\n    font-family: \"open sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\r\n    font-size: 13px;\r\n    color: #676a6c;\r\n    overflow-x: hidden;\r\n}\r\n\r\nhtml, body {\r\n    height: 100%;\r\n}\r\n\r\nbody.full-height-layout #wrapper, body.full-height-layout #page-wrapper {\r\n    height: 100%;\r\n}\r\n\r\n#page-wrapper {\r\n    min-height: auto;\r\n}\r\n\r\nbody.boxed-layout #wrapper {\r\n    background-color: #2f4050;\r\n    max-width: 1200px;\r\n    margin: 0 auto;\r\n}\r\n\r\n.top-navigation.boxed-layout #wrapper, .boxed-layout #wrapper.top-navigation {\r\n    max-width: 1300px !important;\r\n}\r\n\r\n.block {\r\n    display: block;\r\n}\r\n\r\na {\r\n    cursor: pointer;\r\n}\r\n\r\na:hover, a:focus {\r\n    text-decoration: none;\r\n}\r\n\r\n.border-bottom {\r\n    border-bottom: 1px solid #e7eaec !important;\r\n}\r\n\r\n.font-bold {\r\n    font-weight: 600;\r\n}\r\n\r\n.font-noraml {\r\n    font-weight: 400;\r\n}\r\n\r\n.text-uppercase {\r\n    text-transform: uppercase;\r\n}\r\n\r\n.b-r {\r\n    border-right: 1px solid #e7eaec;\r\n}\r\n\r\n.hr-line-dashed {\r\n    border-top: 1px dashed #e7eaec;\r\n    color: #ffffff;\r\n    background-color: #ffffff;\r\n    height: 1px;\r\n    margin: 20px 0;\r\n}\r\n\r\n.hr-line-solid {\r\n    border-bottom: 1px solid #e7eaec;\r\n    background-color: rgba(0, 0, 0, 0);\r\n    border-style: solid !important;\r\n    margin-top: 15px;\r\n    margin-bottom: 15px;\r\n}\r\n\r\nvideo {\r\n    width: 100% !important;\r\n    height: auto !important;\r\n}\r\n/* GALLERY */\r\n.gallery>.row>div {\r\n    margin-bottom: 15px;\r\n}\r\n\r\n.fancybox img {\r\n    margin-bottom: 5px;\r\n    /* Only for demo */\r\n    width: 24%;\r\n}\r\n/* Summernote text editor  */\r\n.note-editor {\r\n    height: auto !important;\r\n    min-height: 100px;\r\n    border: solid 1px #e5e6e7;\r\n}\r\n/* MODAL */\r\n.modal-content {\r\n    background-clip: padding-box;\r\n    background-color: #FFFFFF;\r\n    border: 1px solid rgba(0, 0, 0, 0);\r\n    border-radius: 4px;\r\n    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\r\n    outline: 0 none;\r\n}\r\n\r\n.modal-dialog {\r\n    z-index: 1200;\r\n}\r\n\r\n.modal-body {\r\n    padding: 20px 30px 30px 30px;\r\n}\r\n\r\n.inmodal .modal-body {\r\n    background: #f8fafb;\r\n}\r\n\r\n.inmodal .modal-header {\r\n    padding: 30px 15px;\r\n    text-align: center;\r\n}\r\n\r\n.animated.modal.fade .modal-dialog {\r\n    -webkit-transform: none;\r\n    -ms-transform: none;\r\n    transform: none;\r\n}\r\n\r\n.inmodal .modal-title {\r\n    font-size: 26px;\r\n}\r\n\r\n.inmodal .modal-icon {\r\n    font-size: 84px;\r\n    color: #e2e3e3;\r\n}\r\n\r\n.modal-footer {\r\n    margin-top: 0;\r\n}\r\n/* WRAPPERS */\r\n#wrapper {\r\n    width: 100%;\r\n    overflow-x: hidden;\r\n    background-color: #2f4050;\r\n}\r\n\r\n.wrapper {\r\n    padding: 0 20px;\r\n}\r\n\r\n.wrapper-content {\r\n    padding: 20px;\r\n}\r\n\r\n#page-wrapper {\r\n    padding: 0 15px;\r\n    position: inherit;\r\n    margin: 0 0 0 200px;\r\n}\r\n\r\n.title-action {\r\n    text-align: right;\r\n    padding-top: 30px;\r\n}\r\n\r\n.ibox-content h1, .ibox-content h2, .ibox-content h3, .ibox-content h4,  .ibox-content h5, .ibox-title h1, .ibox-title h2, .ibox-title h3,  .ibox-title h4, .ibox-title h5 {\r\n    margin-top: 5px;\r\n}\r\n\r\nul.unstyled, ol.unstyled {\r\n    list-style: none outside none;\r\n    margin-left: 0;\r\n}\r\n\r\n.big-icon {\r\n    font-size: 160px;\r\n    color: #e5e6e7;\r\n}\r\n/* FOOTER */\r\n.footer {\r\n    background: none repeat scroll 0 0 white;\r\n    border-top: 1px solid #e7eaec;\r\n    overflow: hidden;\r\n    padding: 10px 20px;\r\n    margin: 0 -15px;\r\n    height: 36px;\r\n}\r\n\r\n.footer.fixed_full {\r\n    position: fixed;\r\n    bottom: 0;\r\n    left: 0;\r\n    right: 0;\r\n    z-index: 1000;\r\n    padding: 10px 20px;\r\n    background: white;\r\n    border-top: 1px solid #e7eaec;\r\n}\r\n\r\n.footer.fixed {\r\n    position: fixed;\r\n    bottom: 0;\r\n    left: 0;\r\n    right: 0;\r\n    z-index: 1000;\r\n    padding: 10px 20px;\r\n    background: white;\r\n    border-top: 1px solid #e7eaec;\r\n    margin-left: 220px;\r\n}\r\n\r\nbody.mini-navbar .footer.fixed, body.body-small.mini-navbar .footer.fixed {\r\n    margin: 0 0 0 70px;\r\n}\r\n\r\nbody.mini-navbar.canvas-menu .footer.fixed, body.canvas-menu .footer.fixed {\r\n    margin: 0 !important;\r\n}\r\n\r\nbody.fixed-sidebar.body-small.mini-navbar .footer.fixed {\r\n    margin: 0 0 0 220px;\r\n}\r\n\r\nbody.body-small .footer.fixed {\r\n    margin-left: 0px;\r\n}\r\n/* PANELS */\r\n.page-heading {\r\n    border-top: 0;\r\n    padding: 0px 20px 20px;\r\n}\r\n\r\n.panel-heading h1, .panel-heading h2 {\r\n    margin-bottom: 5px;\r\n}\r\n/*CONTENTTABS*/\r\n.content-tabs {\r\n    position: relative;\r\n    height: 39px;\r\n    background: #fafafa;\r\n    line-height: 39px;\r\n}\r\n\r\n.content-tabs .roll-nav, .page-tabs-list {\r\n    position: absolute;\r\n    width: 30px;\r\n    height: 38px;\r\n    text-align: center;\r\n    color: #999;\r\n    z-index: 2;\r\n    top: 0;\r\n}\r\n\r\n.content-tabs .roll-left {\r\n    left: 0;\r\n    border-right: solid 1px #eee;\r\n}\r\n\r\n.content-tabs .roll-right {\r\n    right: 0;\r\n    border-left: solid 1px #eee;\r\n}\r\n\r\n.content-tabs button {\r\n    background: #fff;\r\n    border: 0;\r\n    height: 40px;\r\n    width: 40px;\r\n    outline: none;\r\n}\r\n\r\n.content-tabs button:hover {\r\n    background: #fafafa;\r\n}\r\n\r\nnav.page-tabs {\r\n    margin-left: 30px;\r\n    width: 100000px;\r\n    height: 39px;\r\n    overflow: hidden;\r\n}\r\n\r\nnav.page-tabs .page-tabs-content {\r\n    float: left;\r\n}\r\n\r\n.page-tabs a {\r\n    display: block;\r\n    float: left;\r\n    border-right: solid 1px #eee;\r\n    padding: 0 15px;\r\n}\r\n\r\n.page-tabs a i:hover {\r\n    color: #c00;\r\n}\r\n\r\n.page-tabs a:hover, .content-tabs .roll-nav:hover {\r\n    color: #777;\r\n    background: #f2f2f2;\r\n    cursor: pointer;\r\n}\r\n\r\n.roll-right.tabRight {\r\n    right: 60px;\r\n}\r\n\r\n.roll-right.btn-group {\r\n    right: 60px;\r\n    width: 80px;\r\n    padding: 0;\r\n}\r\n\r\n.roll-right.btn-group button {\r\n    width: 80px;\r\n}\r\n\r\n.roll-right.tabReload {\r\n    background: #fff;\r\n    height: 38px;\r\n    width: 60px;\r\n    outline: none;\r\n}\r\n\r\n.dropdown-menu-right {\r\n    left: auto;\r\n}\r\n\r\n#content-main {\r\n    height: calc(100% - 127px);\r\n    overflow: hidden;\r\n}\r\n\r\n.tagsview-hide#content-main {\r\n    height: calc(100% - 88px);\r\n    overflow: hidden;\r\n}\r\n\r\n.footer-hide#content-main {\r\n    height: calc(100% - 91px);\r\n    overflow: hidden;\r\n}\r\n\r\n.tagsview-footer-hide#content-main {\r\n    height: calc(100% - 52px);\r\n    overflow: hidden;\r\n}\r\n\r\n.fixed-nav #content-main {\r\n    height: calc(100% - 80px);\r\n    overflow: hidden;\r\n}\r\n/* TABLES */\r\n.table-bordered {\r\n    border: 1px solid #EBEBEB;\r\n}\r\n\r\n.table-bordered>thead>tr>th, .table-bordered>thead>tr>td {\r\n    background-color: #F5F5F6;\r\n    border-bottom-width: 1px;\r\n}\r\n\r\n.table-bordered>thead>tr>th, .table-bordered>tbody>tr>th,  .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td,  .table-bordered>tbody>tr>td, .table-bordered>tfoot>tr>td {\r\n    border: 1px solid #e7e7e7;\r\n}\r\n\r\n.table>thead>tr>th {\r\n    border-bottom: 1px solid #DDDDDD;\r\n    vertical-align: bottom;\r\n}\r\n\r\n.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td,  .table>tbody>tr>td, .table>tfoot>tr>td {\r\n    border-top: 1px solid #e7eaec;\r\n    line-height: 1.42857;\r\n    padding: 8px;\r\n    vertical-align: middle;\r\n}\r\n/* PANELS */\r\n.panel.blank-panel {\r\n    background: none;\r\n    margin: 0;\r\n}\r\n\r\n.blank-panel .panel-heading {\r\n    padding-bottom: 0;\r\n}\r\n\r\n.nav-tabs>li.active>a, .nav-tabs>li.active>a:hover, .nav-tabs>li.active>a:focus {\r\n    -moz-border-bottom-colors: none;\r\n    -moz-border-left-colors: none;\r\n    -moz-border-right-colors: none;\r\n    -moz-border-top-colors: none;\r\n    background: none;\r\n    border-color: #dddddd #dddddd rgba(0, 0, 0, 0);\r\n    border-bottom: #f3f3f4;\r\n    -webkit-border-image: none;\r\n    -o-border-image: none;\r\n    border-image: none;\r\n    border-style: solid;\r\n    border-width: 1px;\r\n    color: #555555;\r\n    cursor: default;\r\n}\r\n\r\n.nav.nav-tabs li {\r\n    background: none;\r\n    border: none;\r\n}\r\n\r\n.nav-tabs>li>a {\r\n    color: #A7B1C2;\r\n    font-weight: 600;\r\n    padding: 10px 20px 10px 25px;\r\n}\r\n\r\n.nav-tabs>li>a:hover, .nav-tabs>li>a:focus {\r\n    background-color: #e6e6e6;\r\n    color: #676a6c;\r\n}\r\n\r\n.ui-tab .tab-content {\r\n    padding: 20px 0px;\r\n}\r\n/* GLOBAL  */\r\n.no-padding {\r\n    padding: 0 !important;\r\n}\r\n\r\n.no-borders {\r\n    border: none !important;\r\n}\r\n\r\n.no-margins {\r\n    margin: 0 !important;\r\n}\r\n\r\n.no-top-border {\r\n    border-top: 0 !important;\r\n}\r\n\r\n.ibox-content.text-box {\r\n    padding-bottom: 0px;\r\n    padding-top: 15px;\r\n}\r\n\r\n.border-left-right {\r\n    border-left: 1px solid #e7eaec;\r\n    border-right: 1px solid #e7eaec;\r\n    border-top: none;\r\n    border-bottom: none;\r\n}\r\n\r\n.border-left {\r\n    border-left: 1px solid #e7eaec;\r\n    border-right: none;\r\n    border-top: none;\r\n    border-bottom: none;\r\n}\r\n\r\n.border-right {\r\n    border-left: none;\r\n    border-right: 1px solid #e7eaec;\r\n    border-top: none;\r\n    border-bottom: none;\r\n}\r\n\r\n.full-width {\r\n    width: 100% !important;\r\n}\r\n\r\n.link-block {\r\n    font-size: 12px;\r\n    padding: 10px;\r\n}\r\n\r\n.nav.navbar-top-links .link-block a {\r\n    font-size: 12px;\r\n}\r\n\r\n.link-block a {\r\n    font-size: 10px;\r\n    color: inherit;\r\n}\r\n\r\nbody.mini-navbar .branding {\r\n    display: none;\r\n}\r\n\r\nimg.circle-border {\r\n    border: 6px solid #FFFFFF;\r\n    border-radius: 50%;\r\n}\r\n\r\n.branding {\r\n    float: left;\r\n    color: #FFFFFF;\r\n    font-size: 18px;\r\n    font-weight: 600;\r\n    padding: 17px 20px;\r\n    text-align: center;\r\n    background-color: #1ab394;\r\n}\r\n\r\n.login-panel {\r\n    margin-top: 25%;\r\n}\r\n\r\n.page-header {\r\n    padding: 20px 0 9px;\r\n    margin: 0 0 20px;\r\n    border-bottom: 1px solid #eeeeee;\r\n}\r\n\r\n.fontawesome-icon-list {\r\n    margin-top: 22px;\r\n}\r\n\r\n.fontawesome-icon-list .fa-hover a {\r\n    overflow: hidden;\r\n    text-overflow: ellipsis;\r\n    white-space: nowrap;\r\n    display: block;\r\n    color: #222222;\r\n    line-height: 32px;\r\n    height: 32px;\r\n    padding-left: 10px;\r\n    border-radius: 4px;\r\n}\r\n\r\n.fontawesome-icon-list .fa-hover a .fa {\r\n    width: 32px;\r\n    font-size: 14px;\r\n    display: inline-block;\r\n    text-align: right;\r\n    margin-right: 10px;\r\n}\r\n\r\n.fontawesome-icon-list .fa-hover a:hover {\r\n    background-color: #1d9d74;\r\n    color: #ffffff;\r\n    text-decoration: none;\r\n}\r\n\r\n.fontawesome-icon-list .fa-hover a:hover .fa {\r\n    font-size: 30px;\r\n    vertical-align: -6px;\r\n}\r\n\r\n.fontawesome-icon-list .fa-hover a:hover .text-muted {\r\n    color: #bbe2d5;\r\n}\r\n\r\n.feature-list .col-md-4 {\r\n    margin-bottom: 22px;\r\n}\r\n\r\n.feature-list h4 .fa:before {\r\n    vertical-align: -10%;\r\n    font-size: 28px;\r\n    display: inline-block;\r\n    width: 1.07142857em;\r\n    text-align: center;\r\n    margin-right: 5px;\r\n}\r\n\r\n.ui-draggable .ibox-title {\r\n    cursor: move;\r\n}\r\n\r\n.breadcrumb {\r\n    background-color: #ffffff;\r\n    padding: 0;\r\n    margin-bottom: 0;\r\n}\r\n\r\n.breadcrumb>li a {\r\n    color: inherit;\r\n}\r\n\r\n.breadcrumb>.active {\r\n    color: inherit;\r\n}\r\n\r\ncode {\r\n    background-color: #F9F2F4;\r\n    border-radius: 4px;\r\n    color: #ca4440;\r\n    font-size: 90%;\r\n    padding: 2px 4px;\r\n    white-space: nowrap;\r\n}\r\n\r\n.ibox {\r\n    clear: both;\r\n    margin-bottom: 25px;\r\n    margin-top: 0;\r\n    padding: 0;\r\n}\r\n\r\n.ibox.collapsed .ibox-content {\r\n    display: none;\r\n}\r\n\r\n.ibox.collapsed .fa.fa-chevron-up:before {\r\n    content: \"\\f078\";\r\n}\r\n\r\n.ibox.collapsed .fa.fa-chevron-down:before {\r\n    content: \"\\f077\";\r\n}\r\n\r\n.ibox:after, .ibox:before {\r\n    display: table;\r\n}\r\n\r\n.ibox-title {\r\n    -moz-border-bottom-colors: none;\r\n    -moz-border-left-colors: none;\r\n    -moz-border-right-colors: none;\r\n    -moz-border-top-colors: none;\r\n    background-color: #ffffff;\r\n    border-color: #e7eaec;\r\n    -webkit-border-image: none;\r\n    -o-border-image: none;\r\n    border-image: none;\r\n    border-style: solid solid none;\r\n    border-width: 0px 0px 0;\r\n    color: inherit;\r\n    margin-bottom: 0;\r\n    padding: 14px 15px 7px;\r\n    min-height: 40px;\r\n}\r\n\r\n.ibox-content {\r\n    background-color: #ffffff;\r\n    color: inherit;\r\n    padding: 15px 20px 20px 20px;\r\n    border-color: #e7eaec;\r\n    -webkit-border-image: none;\r\n    -o-border-image: none;\r\n    border-image: none;\r\n    border-style: solid solid none;\r\n    border-width: 1px 0px;\r\n}\r\n\r\ntable.table-mail tr td {\r\n    padding: 12px;\r\n}\r\n\r\n.table-mail .check-mail {\r\n    padding-left: 20px;\r\n}\r\n\r\n.table-mail .mail-date {\r\n    padding-right: 20px;\r\n}\r\n\r\n.star-mail, .check-mail {\r\n    width: 40px;\r\n}\r\n\r\n.unread td a, .unread td {\r\n    font-weight: 600;\r\n    color: inherit;\r\n}\r\n\r\n.read td a, .read td {\r\n    font-weight: normal;\r\n    color: inherit;\r\n}\r\n\r\n.unread td {\r\n    background-color: #f9f8f8;\r\n}\r\n\r\n.ibox-content {\r\n    clear: both;\r\n}\r\n\r\n.ibox-heading {\r\n    background-color: #f3f6fb;\r\n    border-bottom: none;\r\n}\r\n\r\n.ibox-heading h3 {\r\n    font-weight: 200;\r\n    font-size: 24px;\r\n}\r\n\r\n.ibox-title h5 {\r\n    display: inline-block;\r\n    font-size: 14px;\r\n    margin: 0 0 7px;\r\n    padding: 0;\r\n    text-overflow: ellipsis;\r\n    float: left;\r\n}\r\n\r\n.ibox-title .label {\r\n    float: left;\r\n    margin-left: 4px;\r\n}\r\n\r\n.ibox-tools {\r\n    display: inline-block;\r\n    float: right;\r\n    margin-top: 0;\r\n    position: relative;\r\n    padding: 0;\r\n}\r\n\r\n.ibox-tools a {\r\n    cursor: pointer;\r\n    margin-left: 5px;\r\n    color: #676a6c;\r\n}\r\n\r\n.ibox-tools a.btn-primary {\r\n    color: #fff;\r\n}\r\n\r\n.ibox-tools .dropdown-menu>li>a {\r\n    padding: 4px 10px;\r\n    font-size: 12px;\r\n}\r\n\r\n.ibox .open>.dropdown-menu {\r\n    left: auto;\r\n    right: 0;\r\n}\r\n/* BACKGROUNDS */\r\n.gray-bg {\r\n    background-color: #f3f3f4;\r\n}\r\n\r\n.white-bg {\r\n    background-color: #ffffff;\r\n}\r\n\r\n.navy-bg {\r\n    background-color: #1ab394;\r\n    color: #ffffff;\r\n}\r\n\r\n.blue-bg {\r\n    background-color: #1c84c6;\r\n    color: #ffffff;\r\n}\r\n\r\n.lazur-bg {\r\n    background-color: #23c6c8;\r\n    color: #ffffff;\r\n}\r\n\r\n.yellow-bg {\r\n    background-color: #f8ac59;\r\n    color: #ffffff;\r\n}\r\n\r\n.red-bg {\r\n    background-color: #ed5565;\r\n    color: #ffffff;\r\n}\r\n\r\n.black-bg {\r\n    background-color: #262626;\r\n}\r\n\r\n.panel-primary {\r\n    border-color: #1ab394;\r\n}\r\n\r\n.panel-primary>.panel-heading {\r\n    background-color: #1ab394;\r\n    border-color: #1ab394;\r\n}\r\n\r\n.panel-success {\r\n    border-color: #1c84c6;\r\n}\r\n\r\n.panel-success>.panel-heading {\r\n    background-color: #1c84c6;\r\n    border-color: #1c84c6;\r\n    color: #ffffff;\r\n}\r\n\r\n.panel-info {\r\n    border-color: #23c6c8;\r\n}\r\n\r\n.panel-info>.panel-heading {\r\n    background-color: #23c6c8;\r\n    border-color: #23c6c8;\r\n    color: #ffffff;\r\n}\r\n\r\n.panel-warning {\r\n    border-color: #f8ac59;\r\n}\r\n\r\n.panel-warning>.panel-heading {\r\n    background-color: #f8ac59;\r\n    border-color: #f8ac59;\r\n    color: #ffffff;\r\n}\r\n\r\n.panel-danger {\r\n    border-color: #ed5565;\r\n}\r\n\r\n.panel-danger>.panel-heading {\r\n    background-color: #ed5565;\r\n    border-color: #ed5565;\r\n    color: #ffffff;\r\n}\r\n\r\n.progress-bar {\r\n    background-color: #1ab394;\r\n}\r\n\r\n.progress-small, .progress-small .progress-bar {\r\n    height: 10px;\r\n}\r\n\r\n.progress-small, .progress-mini {\r\n    margin-top: 5px;\r\n}\r\n\r\n.progress-mini, .progress-mini .progress-bar {\r\n    height: 5px;\r\n    margin-bottom: 0px;\r\n}\r\n\r\n.progress-bar-navy-light {\r\n    background-color: #3dc7ab;\r\n}\r\n\r\n.progress-bar-success {\r\n    background-color: #1c84c6;\r\n}\r\n\r\n.progress-bar-info {\r\n    background-color: #23c6c8;\r\n}\r\n\r\n.progress-bar-warning {\r\n    background-color: #f8ac59;\r\n}\r\n\r\n.progress-bar-danger {\r\n    background-color: #ed5565;\r\n}\r\n\r\n.panel-title {\r\n    font-size: inherit;\r\n}\r\n\r\n.jumbotron {\r\n    border-radius: 6px;\r\n    padding: 40px;\r\n}\r\n\r\n.jumbotron h1 {\r\n    margin-top: 0;\r\n}\r\n/* COLORS */\r\n.text-navy {\r\n    color: #1ab394;\r\n}\r\n\r\n.text-primary {\r\n    color: inherit;\r\n}\r\n\r\n.text-success {\r\n    color: #1c84c6;\r\n}\r\n\r\n.text-info {\r\n    color: #23c6c8;\r\n}\r\n\r\n.text-warning {\r\n    color: #f8ac59;\r\n}\r\n\r\n.text-danger {\r\n    color: #ed5565;\r\n}\r\n\r\n.text-muted {\r\n    color: #888888;\r\n}\r\n\r\n.simple_tag {\r\n    background-color: #f3f3f4;\r\n    border: 1px solid #e7eaec;\r\n    border-radius: 2px;\r\n    color: inherit;\r\n    font-size: 10px;\r\n    margin-right: 5px;\r\n    margin-top: 5px;\r\n    padding: 5px 12px;\r\n    display: inline-block;\r\n}\r\n\r\n.img-shadow {\r\n    box-shadow: 0px 0px 3px 0px #919191;\r\n}\r\n/* For handle diferent bg color in AngularJS version */\r\n.dashboards\\.dashboard_2 nav.navbar, .dashboards\\.dashboard_3 nav.navbar,  .mailbox\\.inbox nav.navbar, .mailbox\\.email_view nav.navbar,  .mailbox\\.email_compose nav.navbar, .dashboards\\.dashboard_4_1 nav.navbar {\r\n    background: #fff;\r\n}\r\n/* For handle diferent bg color in MVC version */\r\n.Dashboard_2 .navbar.navbar-static-top, .Dashboard_3 .navbar.navbar-static-top,  .Dashboard_4_1 .navbar.navbar-static-top, .ComposeEmail .navbar.navbar-static-top,  .EmailView .navbar.navbar-static-top, .Inbox .navbar.navbar-static-top {\r\n    background: #fff;\r\n}\r\n\r\na.close-canvas-menu {\r\n    position: absolute;\r\n    top: 10px;\r\n    right: 15px;\r\n    z-index: 1011;\r\n    color: #a7b1c2;\r\n}\r\n\r\na.close-canvas-menu:hover {\r\n    color: #fff;\r\n}\r\n/* FULL HEIGHT */\r\n.full-height {\r\n    height: 100%;\r\n}\r\n\r\n.fh-breadcrumb {\r\n    height: calc(100% - 196px);\r\n    margin: 0 -15px;\r\n    position: relative;\r\n}\r\n\r\n.fh-no-breadcrumb {\r\n    height: calc(100% - 99px);\r\n    margin: 0 -15px;\r\n    position: relative;\r\n}\r\n\r\n.fh-column {\r\n    background: #fff;\r\n    height: 100%;\r\n    width: 240px;\r\n    float: left;\r\n}\r\n\r\n.modal-backdrop {\r\n    z-index: 2040 !important;\r\n}\r\n\r\n.modal {\r\n    z-index: 2050 !important;\r\n}\r\n\r\n.spiner-example {\r\n    height: 200px;\r\n    padding-top: 70px;\r\n}\r\n/* MARGINS & PADDINGS */\r\n.p-xxs {\r\n    padding: 5px;\r\n}\r\n\r\n.p-xs {\r\n    padding: 10px;\r\n}\r\n\r\n.p-sm {\r\n    padding: 15px;\r\n}\r\n\r\n.p-m {\r\n    padding: 20px;\r\n}\r\n\r\n.p-md {\r\n    padding: 25px;\r\n}\r\n\r\n.p-lg {\r\n    padding: 30px;\r\n}\r\n\r\n.p-xl {\r\n    padding: 40px;\r\n}\r\n\r\n.m-xxs {\r\n    margin: 2px 4px;\r\n}\r\n\r\n.m-xs {\r\n    margin: 5px;\r\n}\r\n\r\n.m-sm {\r\n    margin: 10px;\r\n}\r\n\r\n.m {\r\n    margin: 15px;\r\n}\r\n\r\n.m-md {\r\n    margin: 20px;\r\n}\r\n\r\n.m-lg {\r\n    margin: 30px;\r\n}\r\n\r\n.m-xl {\r\n    margin: 50px;\r\n}\r\n\r\n.m-n {\r\n    margin: 0 !important;\r\n}\r\n\r\n.m-l-none {\r\n    margin-left: 0;\r\n}\r\n\r\n.m-l-xs {\r\n    margin-left: 5px;\r\n}\r\n\r\n.m-l-sm {\r\n    margin-left: 10px;\r\n}\r\n\r\n.m-l {\r\n    margin-left: 15px;\r\n}\r\n\r\n.m-l-md {\r\n    margin-left: 20px;\r\n}\r\n\r\n.m-l-lg {\r\n    margin-left: 30px;\r\n}\r\n\r\n.m-l-xl {\r\n    margin-left: 40px;\r\n}\r\n\r\n.m-l-n-xxs {\r\n    margin-left: -1px;\r\n}\r\n\r\n.m-l-n-xs {\r\n    margin-left: -5px;\r\n}\r\n\r\n.m-l-n-sm {\r\n    margin-left: -10px;\r\n}\r\n\r\n.m-l-n {\r\n    margin-left: -15px;\r\n}\r\n\r\n.m-l-n-md {\r\n    margin-left: -20px;\r\n}\r\n\r\n.m-l-n-lg {\r\n    margin-left: -30px;\r\n}\r\n\r\n.m-l-n-xl {\r\n    margin-left: -40px;\r\n}\r\n\r\n.m-t-none {\r\n    margin-top: 0;\r\n}\r\n\r\n.m-t-xxs {\r\n    margin-top: 1px;\r\n}\r\n\r\n.m-t-xs {\r\n    margin-top: 5px;\r\n}\r\n\r\n.m-t-sm {\r\n    margin-top: 10px;\r\n}\r\n\r\n.m-t {\r\n    margin-top: 15px;\r\n}\r\n\r\n.m-t-md {\r\n    margin-top: 20px;\r\n}\r\n\r\n.m-t-lg {\r\n    margin-top: 30px;\r\n}\r\n\r\n.m-t-xl {\r\n    margin-top: 40px;\r\n}\r\n\r\n.m-t-n-xxs {\r\n    margin-top: -1px;\r\n}\r\n\r\n.m-t-n-xs {\r\n    margin-top: -5px;\r\n}\r\n\r\n.m-t-n-sm {\r\n    margin-top: -10px;\r\n}\r\n\r\n.m-t-n {\r\n    margin-top: -15px;\r\n}\r\n\r\n.m-t-n-md {\r\n    margin-top: -20px;\r\n}\r\n\r\n.m-t-n-lg {\r\n    margin-top: -30px;\r\n}\r\n\r\n.m-t-n-xl {\r\n    margin-top: -40px;\r\n}\r\n\r\n.m-r-none {\r\n    margin-right: 0;\r\n}\r\n\r\n.m-r-xxs {\r\n    margin-right: 1px;\r\n}\r\n\r\n.m-r-xs {\r\n    margin-right: 5px;\r\n}\r\n\r\n.m-r-sm {\r\n    margin-right: 10px;\r\n}\r\n\r\n.m-r {\r\n    margin-right: 15px;\r\n}\r\n\r\n.m-r-md {\r\n    margin-right: 20px;\r\n}\r\n\r\n.m-r-lg {\r\n    margin-right: 30px;\r\n}\r\n\r\n.m-r-xl {\r\n    margin-right: 40px;\r\n}\r\n\r\n.m-r-n-xxs {\r\n    margin-right: -1px;\r\n}\r\n\r\n.m-r-n-xs {\r\n    margin-right: -5px;\r\n}\r\n\r\n.m-r-n-sm {\r\n    margin-right: -10px;\r\n}\r\n\r\n.m-r-n {\r\n    margin-right: -15px;\r\n}\r\n\r\n.m-r-n-md {\r\n    margin-right: -20px;\r\n}\r\n\r\n.m-r-n-lg {\r\n    margin-right: -30px;\r\n}\r\n\r\n.m-r-n-xl {\r\n    margin-right: -40px;\r\n}\r\n\r\n.m-b-none {\r\n    margin-bottom: 0;\r\n}\r\n\r\n.m-b-xxs {\r\n    margin-bottom: 1px;\r\n}\r\n\r\n.m-b-xs {\r\n    margin-bottom: 5px;\r\n}\r\n\r\n.m-b-sm {\r\n    margin-bottom: 10px;\r\n}\r\n\r\n.m-b {\r\n    margin-bottom: 15px;\r\n}\r\n\r\n.m-b-md {\r\n    margin-bottom: 20px;\r\n}\r\n\r\n.m-b-lg {\r\n    margin-bottom: 30px;\r\n}\r\n\r\n.m-b-xl {\r\n    margin-bottom: 40px;\r\n}\r\n\r\n.m-b-n-xxs {\r\n    margin-bottom: -1px;\r\n}\r\n\r\n.m-b-n-xs {\r\n    margin-bottom: -5px;\r\n}\r\n\r\n.m-b-n-sm {\r\n    margin-bottom: -10px;\r\n}\r\n\r\n.m-b-n {\r\n    margin-bottom: -15px;\r\n}\r\n\r\n.m-b-n-md {\r\n    margin-bottom: -20px;\r\n}\r\n\r\n.m-b-n-lg {\r\n    margin-bottom: -30px;\r\n}\r\n\r\n.m-b-n-xl {\r\n    margin-bottom: -40px;\r\n}\r\n\r\n.space-15 {\r\n    margin: 15px 0;\r\n}\r\n\r\n.space-20 {\r\n    margin: 20px 0;\r\n}\r\n\r\n.space-25 {\r\n    margin: 25px 0;\r\n}\r\n\r\n.space-30 {\r\n    margin: 30px 0;\r\n}\r\n\r\nbody.modal-open {\r\n    padding-right: inherit !important;\r\n}\r\n/* SEARCH PAGE */\r\n.search-form {\r\n    margin-top: 10px;\r\n}\r\n\r\n.search-result h3 {\r\n    margin-bottom: 0;\r\n    color: #1E0FBE;\r\n}\r\n\r\n.search-result .search-link {\r\n    color: #006621;\r\n}\r\n\r\n.search-result p {\r\n    font-size: 12px;\r\n    margin-top: 5px;\r\n}\r\n/* CONTACTS */\r\n.contact-box {\r\n    background-color: #ffffff;\r\n    border: 1px solid #e7eaec;\r\n    padding: 20px;\r\n    margin-bottom: 20px;\r\n}\r\n\r\n.contact-box a {\r\n    color: inherit;\r\n}\r\n\r\n/* INVOICE */\r\n.invoice-table tbody>tr>td:last-child, .invoice-table tbody>tr>td:nth-child(4),  .invoice-table tbody>tr>td:nth-child(3), .invoice-table tbody>tr>td:nth-child(2) {\r\n    text-align: right;\r\n}\r\n\r\n.invoice-table thead>tr>th:last-child, .invoice-table thead>tr>th:nth-child(4),  .invoice-table thead>tr>th:nth-child(3), .invoice-table thead>tr>th:nth-child(2) {\r\n    text-align: right;\r\n}\r\n\r\n.invoice-total>tbody>tr>td:first-child {\r\n    text-align: right;\r\n}\r\n\r\n.invoice-total>tbody>tr>td {\r\n    border: 0 none;\r\n}\r\n\r\n.invoice-total>tbody>tr>td:last-child {\r\n    border-bottom: 1px solid #DDDDDD;\r\n    text-align: right;\r\n    width: 15%;\r\n}\r\n/* ERROR & LOGIN & LOCKSCREEN*/\r\n.middle-box {\r\n    max-width: 400px;\r\n    z-index: 100;\r\n    margin: 0 auto;\r\n    padding-top: 40px;\r\n}\r\n\r\n.lockscreen.middle-box {\r\n    width: 200px;\r\n    padding-top: 110px;\r\n}\r\n\r\n.loginscreen.middle-box {\r\n    width: 300px;\r\n}\r\n\r\n.loginColumns {\r\n    max-width: 800px;\r\n    margin: 0 auto;\r\n    padding: 100px 20px 20px 20px;\r\n}\r\n\r\n.passwordBox {\r\n    max-width: 460px;\r\n    margin: 0 auto;\r\n    padding: 100px 20px 20px 20px;\r\n}\r\n\r\n.logo-name {\r\n    color: #e6e6e6;\r\n    font-size: 180px;\r\n    font-weight: 800;\r\n    letter-spacing: -10px;\r\n    margin-bottom: 0px;\r\n}\r\n\r\n.middle-box h1 {\r\n    font-size: 170px;\r\n}\r\n\r\n.wrapper .middle-box {\r\n    margin-top: 140px;\r\n}\r\n\r\n.lock-word {\r\n    z-index: 10;\r\n    position: absolute;\r\n    top: 110px;\r\n    left: 50%;\r\n    margin-left: -470px;\r\n}\r\n\r\n.lock-word span {\r\n    font-size: 100px;\r\n    font-weight: 600;\r\n    color: #e9e9e9;\r\n    display: inline-block;\r\n}\r\n\r\n.lock-word .first-word {\r\n    margin-right: 160px;\r\n}\r\n/* DASBOARD */\r\n.dashboard-header {\r\n    border-top: 0;\r\n    padding: 20px 20px 20px 20px;\r\n}\r\n\r\n.dashboard-header h2 {\r\n    margin-top: 10px;\r\n    font-size: 26px;\r\n}\r\n\r\n.fist-item {\r\n    border-top: none !important;\r\n}\r\n\r\n.statistic-box {\r\n    margin-top: 40px;\r\n}\r\n\r\n.dashboard-header .list-group-item span.label {\r\n    margin-right: 10px;\r\n}\r\n\r\n.list-group.clear-list .list-group-item {\r\n    border-top: 1px solid #e7eaec;\r\n    border-bottom: 0;\r\n    border-right: 0;\r\n    border-left: 0;\r\n    padding: 10px 0;\r\n}\r\n\r\nul.clear-list:first-child {\r\n    border-top: none !important;\r\n}\r\n/* Intimeline */\r\n.timeline-item .date i {\r\n    position: absolute;\r\n    top: 0;\r\n    right: 0;\r\n    padding: 5px;\r\n    width: 30px;\r\n    text-align: center;\r\n    border-top: 1px solid #e7eaec;\r\n    border-bottom: 1px solid #e7eaec;\r\n    border-left: 1px solid #e7eaec;\r\n    background: #f8f8f8;\r\n}\r\n\r\n.timeline-item .date {\r\n    text-align: right;\r\n    width: 110px;\r\n    position: relative;\r\n    padding-top: 30px;\r\n}\r\n\r\n.timeline-item .content {\r\n    border-left: 1px solid #e7eaec;\r\n    border-top: 1px solid #e7eaec;\r\n    padding-top: 10px;\r\n    min-height: 100px;\r\n}\r\n\r\n.timeline-item .content:hover {\r\n    background: #f6f6f6;\r\n}\r\n/* PIN BOARD */\r\nul.notes li, ul.tag-list li {\r\n    list-style: none;\r\n}\r\n\r\nul.notes li h4 {\r\n    margin-top: 20px;\r\n    font-size: 16px;\r\n}\r\n\r\nul.notes li div {\r\n    text-decoration: none;\r\n    color: #000;\r\n    background: #ffc;\r\n    display: block;\r\n    height: 140px;\r\n    width: 140px;\r\n    padding: 1em;\r\n    position: relative;\r\n}\r\n\r\nul.notes li div small {\r\n    position: absolute;\r\n    top: 5px;\r\n    right: 5px;\r\n    font-size: 10px;\r\n}\r\n\r\nul.notes li div a {\r\n    position: absolute;\r\n    right: 10px;\r\n    bottom: 10px;\r\n    color: inherit;\r\n}\r\n\r\nul.notes li {\r\n    margin: 10px 40px 50px 0px;\r\n    float: left;\r\n}\r\n\r\nul.notes li div p {\r\n    font-size: 12px;\r\n}\r\n\r\nul.notes li div {\r\n    text-decoration: none;\r\n    color: #000;\r\n    background: #ffc;\r\n    display: block;\r\n    height: 140px;\r\n    width: 140px;\r\n    padding: 1em;\r\n    /* Firefox */\r\n    /* Safari+Chrome */\r\n    /* Opera */\r\n    box-shadow: 5px 5px 2px rgba(33, 33, 33, 0.7);\r\n}\r\n\r\nul.notes li div {\r\n    -webkit-transform: rotate(-6deg);\r\n    -o-transform: rotate(-6deg);\r\n    -moz-transform: rotate(-6deg);\r\n}\r\n\r\nul.notes li:nth-child(even) div {\r\n    -o-transform: rotate(4deg);\r\n    -webkit-transform: rotate(4deg);\r\n    -moz-transform: rotate(4deg);\r\n    position: relative;\r\n    top: 5px;\r\n}\r\n\r\nul.notes li:nth-child(3n) div {\r\n    -o-transform: rotate(-3deg);\r\n    -webkit-transform: rotate(-3deg);\r\n    -moz-transform: rotate(-3deg);\r\n    position: relative;\r\n    top: -5px;\r\n}\r\n\r\nul.notes li:nth-child(5n) div {\r\n    -o-transform: rotate(5deg);\r\n    -webkit-transform: rotate(5deg);\r\n    -moz-transform: rotate(5deg);\r\n    position: relative;\r\n    top: -10px;\r\n}\r\n\r\nul.notes li div:hover, ul.notes li div:focus {\r\n    -webkit-transform: scale(1.1);\r\n    -moz-transform: scale(1.1);\r\n    -o-transform: scale(1.1);\r\n    position: relative;\r\n    z-index: 5;\r\n}\r\n\r\nul.notes li div {\r\n    text-decoration: none;\r\n    color: #000;\r\n    background: #ffc;\r\n    display: block;\r\n    height: 210px;\r\n    width: 210px;\r\n    padding: 1em;\r\n    box-shadow: 5px 5px 7px rgba(33, 33, 33, 0.7);\r\n    -webkit-transition: -webkit-transform 0.15s linear;\r\n}\r\n/* FILE MANAGER */\r\n.file-box {\r\n    float: left;\r\n    width: 220px;\r\n}\r\n\r\n.file-manager h5 {\r\n    text-transform: uppercase;\r\n}\r\n\r\n.file-manager {\r\n    list-style: none outside none;\r\n    margin: 0;\r\n    padding: 0;\r\n}\r\n\r\n.folder-list li a {\r\n    color: #666666;\r\n    display: block;\r\n    padding: 5px 0;\r\n}\r\n\r\n.folder-list li {\r\n    border-bottom: 1px solid #e7eaec;\r\n    display: block;\r\n}\r\n\r\n.folder-list li i {\r\n    margin-right: 8px;\r\n    color: #3d4d5d;\r\n}\r\n\r\n.category-list li a {\r\n    color: #666666;\r\n    display: block;\r\n    padding: 5px 0;\r\n}\r\n\r\n.category-list li {\r\n    display: block;\r\n}\r\n\r\n.category-list li i {\r\n    margin-right: 8px;\r\n    color: #3d4d5d;\r\n}\r\n\r\n.category-list li a .text-navy {\r\n    color: #1ab394;\r\n}\r\n\r\n.category-list li a .text-primary {\r\n    color: #1c84c6;\r\n}\r\n\r\n.category-list li a .text-info {\r\n    color: #23c6c8;\r\n}\r\n\r\n.category-list li a .text-danger {\r\n    color: #EF5352;\r\n}\r\n\r\n.category-list li a .text-warning {\r\n    color: #F8AC59;\r\n}\r\n\r\n.file-manager h5.tag-title {\r\n    margin-top: 20px;\r\n}\r\n\r\n.tag-list li {\r\n    float: left;\r\n}\r\n\r\n.tag-list li a {\r\n    font-size: 10px;\r\n    background-color: #f3f3f4;\r\n    padding: 5px 12px;\r\n    color: inherit;\r\n    border-radius: 2px;\r\n    border: 1px solid #e7eaec;\r\n    margin-right: 5px;\r\n    margin-top: 5px;\r\n    display: block;\r\n}\r\n\r\n.file {\r\n    border: 1px solid #e7eaec;\r\n    padding: 0;\r\n    background-color: #ffffff;\r\n    position: relative;\r\n    margin-bottom: 20px;\r\n    margin-right: 20px;\r\n}\r\n\r\n.file-manager .hr-line-dashed {\r\n    margin: 15px 0;\r\n}\r\n\r\n.file .icon, .file .image {\r\n    height: 100px;\r\n    overflow: hidden;\r\n}\r\n\r\n.file .icon {\r\n    padding: 15px 10px;\r\n    text-align: center;\r\n}\r\n\r\n.file-control {\r\n    color: inherit;\r\n    font-size: 14px;\r\n    margin-right: 10px;\r\n}\r\n\r\n.file-control.active {\r\n    text-decoration: underline;\r\n}\r\n\r\n.file .icon i {\r\n    font-size: 70px;\r\n    color: #dadada;\r\n}\r\n\r\n.file .file-name {\r\n    padding: 10px;\r\n    background-color: #f8f8f8;\r\n    border-top: 1px solid #e7eaec;\r\n}\r\n\r\n.file-name small {\r\n    color: #676a6c;\r\n}\r\n\r\n.corner {\r\n    position: absolute;\r\n    display: inline-block;\r\n    width: 0;\r\n    height: 0;\r\n    line-height: 0;\r\n    border: 0.6em solid transparent;\r\n    border-right: 0.6em solid #f1f1f1;\r\n    border-bottom: 0.6em solid #f1f1f1;\r\n    right: 0em;\r\n    bottom: 0em;\r\n}\r\n\r\na.compose-mail {\r\n    padding: 8px 10px;\r\n}\r\n\r\n.mail-search {\r\n    max-width: 300px;\r\n}\r\n/* PROFILE */\r\n.profile-content {\r\n    border-top: none !important;\r\n}\r\n\r\n.feed-activity-list .feed-element {\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.feed-element:first-child {\r\n    margin-top: 0;\r\n}\r\n\r\n.feed-element {\r\n    padding-bottom: 15px;\r\n}\r\n\r\n.feed-element, .feed-element .media {\r\n    margin-top: 15px;\r\n}\r\n\r\n.feed-element, .media-body {\r\n    overflow: hidden;\r\n}\r\n\r\n.feed-element>.pull-left {\r\n    margin-right: 10px;\r\n}\r\n\r\n.feed-element img.img-circle, .dropdown-messages-box img.img-circle {\r\n    width: 38px;\r\n    height: 38px;\r\n}\r\n\r\n.feed-element .well {\r\n    border: 1px solid #e7eaec;\r\n    box-shadow: none;\r\n    margin-top: 10px;\r\n    margin-bottom: 5px;\r\n    padding: 10px 20px;\r\n    font-size: 11px;\r\n    line-height: 16px;\r\n}\r\n\r\n.feed-element .actions {\r\n    margin-top: 10px;\r\n}\r\n\r\n.feed-element .photos {\r\n    margin: 10px 0;\r\n}\r\n\r\n.feed-photo {\r\n    max-height: 180px;\r\n    border-radius: 4px;\r\n    overflow: hidden;\r\n    margin-right: 10px;\r\n    margin-bottom: 10px;\r\n}\r\n/* MAILBOX */\r\n.mail-box {\r\n    background-color: #ffffff;\r\n    border: 1px solid #e7eaec;\r\n    border-top: 0;\r\n    padding: 0px;\r\n    margin-bottom: 20px;\r\n}\r\n\r\n.mail-box-header {\r\n    background-color: #ffffff;\r\n    border: 1px solid #e7eaec;\r\n    border-bottom: 0;\r\n    padding: 30px 20px 20px 20px;\r\n}\r\n\r\n.mail-box-header h2 {\r\n    margin-top: 0px;\r\n}\r\n\r\n.mailbox-content .tag-list li a {\r\n    background: #ffffff;\r\n}\r\n\r\n.mail-body {\r\n    border-top: 1px solid #e7eaec;\r\n    padding: 20px;\r\n}\r\n\r\n.mail-text {\r\n    border-top: 1px solid #e7eaec;\r\n}\r\n\r\n.mail-text .note-toolbar {\r\n    padding: 10px 15px;\r\n}\r\n\r\n.mail-body .form-group {\r\n    margin-bottom: 5px;\r\n}\r\n\r\n.mail-text .note-editor .note-toolbar {\r\n    background-color: #F9F8F8;\r\n}\r\n\r\n.mail-attachment {\r\n    border-top: 1px solid #e7eaec;\r\n    padding: 20px;\r\n    font-size: 12px;\r\n}\r\n\r\n.mailbox-content {\r\n    background: none;\r\n    border: none;\r\n    padding: 10px;\r\n}\r\n\r\n.mail-ontact {\r\n    width: 23%;\r\n}\r\n/* PROJECTS */\r\n.project-people, .project-actions {\r\n    text-align: right;\r\n    vertical-align: middle;\r\n}\r\n\r\ndd.project-people {\r\n    text-align: left;\r\n    margin-top: 5px;\r\n}\r\n\r\n.project-people img {\r\n    width: 32px;\r\n    height: 32px;\r\n}\r\n\r\n.project-title a {\r\n    font-size: 14px;\r\n    color: #676a6c;\r\n    font-weight: 600;\r\n}\r\n\r\n.project-list table tr td {\r\n    border-top: none;\r\n    border-bottom: 1px solid #e7eaec;\r\n    padding: 15px 10px;\r\n    vertical-align: middle;\r\n}\r\n\r\n.project-manager .tag-list li a {\r\n    font-size: 10px;\r\n    background-color: white;\r\n    padding: 5px 12px;\r\n    color: inherit;\r\n    border-radius: 2px;\r\n    border: 1px solid #e7eaec;\r\n    margin-right: 5px;\r\n    margin-top: 5px;\r\n    display: block;\r\n}\r\n\r\n.project-files li a {\r\n    font-size: 11px;\r\n    color: #676a6c;\r\n    margin-left: 10px;\r\n    line-height: 22px;\r\n}\r\n/* FAQ */\r\n.faq-item {\r\n    padding: 20px;\r\n    margin-bottom: 2px;\r\n    background: #fff;\r\n}\r\n\r\n.faq-question {\r\n    font-size: 18px;\r\n    font-weight: 600;\r\n    color: #1ab394;\r\n    display: block;\r\n}\r\n\r\n.faq-question:hover {\r\n    color: #179d82;\r\n}\r\n\r\n.faq-answer {\r\n    margin-top: 10px;\r\n    background: #f3f3f4;\r\n    border: 1px solid #e7eaec;\r\n    border-radius: 3px;\r\n    padding: 15px;\r\n}\r\n\r\n.faq-item .tag-item {\r\n    background: #f3f3f4;\r\n    padding: 2px 6px;\r\n    font-size: 10px;\r\n    text-transform: uppercase;\r\n}\r\n\r\n/* Chat view */\r\n.message-input {\r\n    height: 90px !important;\r\n}\r\n\r\n.chat-avatar {\r\n    width: 36px;\r\n    height: 36px;\r\n    float: left;\r\n    margin-right: 10px;\r\n}\r\n\r\n.chat-user-name {\r\n    padding: 10px;\r\n}\r\n\r\n.chat-user {\r\n    padding: 8px 10px;\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.chat-user a {\r\n    color: inherit;\r\n}\r\n\r\n.chat-view {\r\n    z-index: 20012;\r\n}\r\n\r\n.chat-users, .chat-statistic {\r\n    margin-left: -30px;\r\n}\r\n\r\n@media (max-width: 992px) {\r\n    .chat-users,\r\n    .chat-statistic {\r\n        margin-left: 0;\r\n    }\r\n}\r\n\r\n.chat-view .ibox-content {\r\n    padding: 0;\r\n}\r\n\r\n.chat-message {\r\n    padding: 10px 20px;\r\n}\r\n\r\n.message-avatar {\r\n    height: 48px;\r\n    width: 48px;\r\n    border: 1px solid #e7eaec;\r\n    border-radius: 4px;\r\n    margin-top: 1px;\r\n}\r\n\r\n.chat-discussion .chat-message.left .message-avatar {\r\n    float: left;\r\n    margin-right: 10px;\r\n}\r\n\r\n.chat-discussion .chat-message.right .message-avatar {\r\n    float: right;\r\n    margin-left: 10px;\r\n}\r\n\r\n.message {\r\n    background-color: #fff;\r\n    border: 1px solid #e7eaec;\r\n    text-align: left;\r\n    display: block;\r\n    padding: 10px 20px;\r\n    position: relative;\r\n    border-radius: 4px;\r\n}\r\n\r\n.chat-discussion .chat-message.left .message-date {\r\n    float: right;\r\n}\r\n\r\n.chat-discussion .chat-message.right .message-date {\r\n    float: left;\r\n}\r\n\r\n.chat-discussion .chat-message.left .message {\r\n    text-align: left;\r\n    margin-left: 55px;\r\n}\r\n\r\n.chat-discussion .chat-message.right .message {\r\n    text-align: right;\r\n    margin-right: 55px;\r\n}\r\n\r\n.message-date {\r\n    font-size: 10px;\r\n    color: #888888;\r\n}\r\n\r\n.message-content {\r\n    display: block;\r\n}\r\n\r\n.chat-discussion {\r\n    background: #eee;\r\n    padding: 15px;\r\n    height: 400px;\r\n    overflow-y: auto;\r\n}\r\n\r\n.chat-users {\r\n    overflow-y: auto;\r\n    height: 400px;\r\n}\r\n\r\n.chat-message-form .form-group {\r\n    margin-bottom: 0;\r\n}\r\n\r\n/* jsTree */\r\n.jstree-open>.jstree-anchor>.fa-folder:before {\r\n    content: \"\\f07c\";\r\n}\r\n\r\n.jstree-default .jstree-icon.none {\r\n    width: 0;\r\n}\r\n/* CLIENTS */\r\n.clients-list {\r\n    margin-top: 20px;\r\n}\r\n\r\n.clients-list .tab-pane {\r\n    position: relative;\r\n    height: 600px;\r\n}\r\n\r\n.client-detail {\r\n    position: relative;\r\n    height: 620px;\r\n}\r\n\r\n.clients-list table tr td {\r\n    height: 46px;\r\n    vertical-align: middle;\r\n    border: none;\r\n}\r\n\r\n.client-link {\r\n    font-weight: 600;\r\n    color: inherit;\r\n}\r\n\r\n.client-link:hover {\r\n    color: inherit;\r\n}\r\n\r\n.client-avatar {\r\n    width: 42px;\r\n}\r\n\r\n.client-avatar img {\r\n    width: 28px;\r\n    height: 28px;\r\n    border-radius: 50%;\r\n}\r\n\r\n.contact-type {\r\n    width: 20px;\r\n    color: #c1c3c4;\r\n}\r\n\r\n.client-status {\r\n    text-align: left;\r\n}\r\n\r\n.client-detail .vertical-timeline-content p {\r\n    margin: 0;\r\n}\r\n\r\n.client-detail .vertical-timeline-icon.gray-bg {\r\n    color: #a7aaab;\r\n}\r\n\r\n.clients-list .nav-tabs>li.active>a, .clients-list .nav-tabs>li.active>a:hover,  .clients-list .nav-tabs>li.active>a:focus {\r\n    border-bottom: 1px solid #fff;\r\n}\r\n/* BLOG ARTICLE */\r\n.blog h2 {\r\n    font-weight: 700;\r\n}\r\n\r\n.blog h5 {\r\n    margin: 0 0 5px 0;\r\n}\r\n\r\n.blog .btn {\r\n    margin: 0 0 5px 0;\r\n}\r\n\r\n.article h1 {\r\n    font-size: 48px;\r\n    font-weight: 700;\r\n    color: #2F4050;\r\n}\r\n\r\n.article p {\r\n    font-size: 15px;\r\n    line-height: 26px;\r\n}\r\n\r\n.article-title {\r\n    text-align: center;\r\n    margin: 60px 0 40px 0;\r\n}\r\n\r\n.article .ibox-content {\r\n    padding: 40px;\r\n}\r\n/* ISSUE TRACKER */\r\n.issue-tracker .btn-link {\r\n    color: #1ab394;\r\n}\r\n\r\ntable.issue-tracker tbody tr td {\r\n    vertical-align: middle;\r\n    height: 50px;\r\n}\r\n\r\n.issue-info {\r\n    width: 50%;\r\n}\r\n\r\n.issue-info a {\r\n    font-weight: 600;\r\n    color: #676a6c;\r\n}\r\n\r\n.issue-info small {\r\n    display: block;\r\n}\r\n/* TEAMS */\r\n.team-members {\r\n    margin: 10px 0;\r\n}\r\n\r\n.team-members img.img-circle {\r\n    width: 42px;\r\n    height: 42px;\r\n    margin-bottom: 5px;\r\n}\r\n/* AGILE BOARD */\r\n.sortable-list {\r\n    padding: 10px 0;\r\n}\r\n\r\n.agile-list {\r\n    list-style: none;\r\n    margin: 0;\r\n}\r\n\r\n.agile-list li {\r\n    background: #FAFAFB;\r\n    border: 1px solid #e7eaec;\r\n    margin: 0px 0 10px 0;\r\n    padding: 10px;\r\n    border-radius: 2px;\r\n}\r\n\r\n.agile-list li:hover {\r\n    cursor: pointer;\r\n    background: #fff;\r\n}\r\n\r\n.agile-list li.warning-element {\r\n    border-left: 3px solid #f8ac59;\r\n}\r\n\r\n.agile-list li.danger-element {\r\n    border-left: 3px solid #ed5565;\r\n}\r\n\r\n.agile-list li.info-element {\r\n    border-left: 3px solid #1c84c6;\r\n}\r\n\r\n.agile-list li.success-element {\r\n    border-left: 3px solid #1ab394;\r\n}\r\n\r\n.agile-detail {\r\n    margin-top: 5px;\r\n    font-size: 12px;\r\n}\r\n/* DIFF */\r\nins {\r\n    background-color: #c6ffc6;\r\n    text-decoration: none;\r\n}\r\n\r\ndel {\r\n    background-color: #ffc6c6;\r\n}\r\n\r\n#small-chat {\r\n    position: fixed;\r\n    bottom: 50px;\r\n    right: 26px;\r\n    z-index: 100;\r\n}\r\n\r\n#small-chat .badge {\r\n    position: absolute;\r\n    top: -3px;\r\n    right: -4px;\r\n}\r\n\r\n.open-small-chat {\r\n    height: 38px;\r\n    width: 38px;\r\n    display: block;\r\n    background: #1ab394;\r\n    padding: 9px 8px;\r\n    text-align: center;\r\n    color: #fff;\r\n    border-radius: 50%;\r\n}\r\n\r\n.open-small-chat:hover {\r\n    color: white;\r\n    background: #1ab394;\r\n}\r\n\r\n.small-chat-box {\r\n    display: none;\r\n    position: fixed;\r\n    bottom: 50px;\r\n    right: 80px;\r\n    background: #fff;\r\n    border: 1px solid #e7eaec;\r\n    width: 230px;\r\n    height: 320px;\r\n    border-radius: 4px;\r\n}\r\n\r\n.small-chat-box.ng-small-chat {\r\n    display: block;\r\n}\r\n\r\n.body-small .small-chat-box {\r\n    bottom: 70px;\r\n    right: 20px;\r\n}\r\n\r\n.small-chat-box.active {\r\n    display: block;\r\n}\r\n\r\n.small-chat-box .heading {\r\n    background: #2f4050;\r\n    padding: 8px 15px;\r\n    font-weight: bold;\r\n    color: #fff;\r\n}\r\n\r\n.small-chat-box .chat-date {\r\n    opacity: 0.6;\r\n    font-size: 10px;\r\n    font-weight: normal;\r\n}\r\n\r\n.small-chat-box .content {\r\n    padding: 15px 15px;\r\n}\r\n\r\n.small-chat-box .content .author-name {\r\n    font-weight: bold;\r\n    margin-bottom: 3px;\r\n    font-size: 11px;\r\n}\r\n\r\n.small-chat-box .content>div {\r\n    padding-bottom: 20px;\r\n}\r\n\r\n.small-chat-box .content .chat-message {\r\n    padding: 5px 10px;\r\n    border-radius: 6px;\r\n    font-size: 11px;\r\n    line-height: 14px;\r\n    max-width: 80%;\r\n    background: #f3f3f4;\r\n    margin-bottom: 10px;\r\n}\r\n\r\n.small-chat-box .content .chat-message.active {\r\n    background: #1ab394;\r\n    color: #fff;\r\n}\r\n\r\n.small-chat-box .content .left {\r\n    text-align: left;\r\n    clear: both;\r\n}\r\n\r\n.small-chat-box .content .left .chat-message {\r\n    float: left;\r\n}\r\n\r\n.small-chat-box .content .right {\r\n    text-align: right;\r\n    clear: both;\r\n}\r\n\r\n.small-chat-box .content .right .chat-message {\r\n    float: right;\r\n}\r\n\r\n.small-chat-box .form-chat {\r\n    padding: 10px 10px;\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-rotating-plane\"></div>\r\n *\r\n */\r\n.sk-spinner-rotating-plane.sk-spinner {\r\n    width: 30px;\r\n    height: 30px;\r\n    background-color: #1ab394;\r\n    margin: 0 auto;\r\n    -webkit-animation: sk-rotatePlane 1.2s infinite ease-in-out;\r\n    animation: sk-rotatePlane 1.2s infinite ease-in-out;\r\n}\r\n\r\n@-webkit-keyframes sk-rotatePlane {\r\n    0% {\r\n        -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);\r\n        transform: perspective(120px) rotateX(0deg) rotateY(0deg);\r\n    }\r\n\r\n    50% {\r\n        -webkit-transform: perspective(120px)  rotateX(-180 .1deg )  rotateY(0deg);\r\n        transform: perspective(120px)  rotateX(-180 .1deg )  rotateY(0deg);\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: perspective(120px)  rotateX(-180deg)  rotateY(-180deg);\r\n        transform: perspective(120px)  rotateX(-180deg)  rotateY(-180deg);\r\n    }\r\n}\r\n\r\n@keyframes sk-rotatePlane {\r\n    0% {\r\n        -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);\r\n        transform: perspective(120px) rotateX(0deg) rotateY(0deg);\r\n    }\r\n\r\n    50% {\r\n        -webkit-transform: perspective(120px)  rotateX(-180 .1deg)  rotateY(0deg);\r\n        transform: perspective(120px)  rotateX(-180 .1deg)  rotateY(0deg);\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: perspective(120px)  rotateX(-180deg)  rotateY(-179 .9deg );\r\n        transform: perspective(120px)  rotateX(-180deg)  rotateY(-179 .9deg );\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-double-bounce\">\r\n *      <div class=\"sk-double-bounce1\"></div>\r\n *      <div class=\"sk-double-bounce2\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-double-bounce.sk-spinner {\r\n    width: 40px;\r\n    height: 40px;\r\n    position: relative;\r\n    margin: 0 auto;\r\n}\r\n\r\n.sk-spinner-double-bounce .sk-double-bounce1, .sk-spinner-double-bounce .sk-double-bounce2 {\r\n    width: 100%;\r\n    height: 100%;\r\n    border-radius: 50%;\r\n    background-color: #1ab394;\r\n    opacity: 0.6;\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    -webkit-animation: sk-doubleBounce 2s infinite ease-in-out;\r\n    animation: sk-doubleBounce 2s infinite ease-in-out;\r\n}\r\n\r\n.sk-spinner-double-bounce .sk-double-bounce2 {\r\n    -webkit-animation-delay: -1s;\r\n    animation-delay: -1s;\r\n}\r\n\r\n@-webkit-keyframes sk-doubleBounce {\r\n    0%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    50% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n\r\n@keyframes sk-doubleBounce {\r\n    0%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    50% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-wave\">\r\n *      <div class=\"sk-rect1\"></div>\r\n *      <div class=\"sk-rect2\"></div>\r\n *      <div class=\"sk-rect3\"></div>\r\n *      <div class=\"sk-rect4\"></div>\r\n *      <div class=\"sk-rect5\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-wave.sk-spinner {\r\n    margin: 0 auto;\r\n    width: 50px;\r\n    height: 30px;\r\n    text-align: center;\r\n    font-size: 10px;\r\n}\r\n\r\n.sk-spinner-wave div {\r\n    background-color: #1ab394;\r\n    height: 100%;\r\n    width: 6px;\r\n    display: inline-block;\r\n    -webkit-animation: sk-waveStretchDelay 1.2s infinite ease-in-out;\r\n    animation: sk-waveStretchDelay 1.2s infinite ease-in-out;\r\n}\r\n\r\n.sk-spinner-wave .sk-rect2 {\r\n    -webkit-animation-delay: -1.1s;\r\n    animation-delay: -1.1s;\r\n}\r\n\r\n.sk-spinner-wave .sk-rect3 {\r\n    -webkit-animation-delay: -1s;\r\n    animation-delay: -1s;\r\n}\r\n\r\n.sk-spinner-wave .sk-rect4 {\r\n    -webkit-animation-delay: -0.9s;\r\n    animation-delay: -0.9s;\r\n}\r\n\r\n.sk-spinner-wave .sk-rect5 {\r\n    -webkit-animation-delay: -0.8s;\r\n    animation-delay: -0.8s;\r\n}\r\n\r\n@-webkit-keyframes sk-waveStretchDelay {\r\n    0%, 40%, 100% {\r\n        -webkit-transform: scaleY(0.4);\r\n        transform: scaleY(0.4);\r\n    }\r\n\r\n    20% {\r\n        -webkit-transform: scaleY(1);\r\n        transform: scaleY(1);\r\n    }\r\n}\r\n\r\n@keyframes sk-waveStretchDelay {\r\n    0%, 40%, 100% {\r\n        -webkit-transform: scaleY(0.4);\r\n        transform: scaleY(0.4);\r\n    }\r\n\r\n    20% {\r\n        -webkit-transform: scaleY(1);\r\n        transform: scaleY(1);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-wandering-cubes\">\r\n *      <div class=\"sk-cube1\"></div>\r\n *      <div class=\"sk-cube2\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-wandering-cubes.sk-spinner {\r\n    margin: 0 auto;\r\n    width: 32px;\r\n    height: 32px;\r\n    position: relative;\r\n}\r\n\r\n.sk-spinner-wandering-cubes .sk-cube1, .sk-spinner-wandering-cubes .sk-cube2 {\r\n    background-color: #1ab394;\r\n    width: 10px;\r\n    height: 10px;\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    -webkit-animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;\r\n    animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;\r\n}\r\n\r\n.sk-spinner-wandering-cubes .sk-cube2 {\r\n    -webkit-animation-delay: -0.9s;\r\n    animation-delay: -0.9s;\r\n}\r\n\r\n@-webkit-keyframes sk-wanderingCubeMove {\r\n    25% {\r\n        -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);\r\n        transform: translateX(42px) rotate(-90deg) scale(0.5);\r\n    }\r\n\r\n    50% {\r\n        /* Hack to make FF rotate in the right direction */\r\n        -webkit-transform: translateX(42px)  translateY(42px)  rotate(-179deg);\r\n        transform: translateX(42px)  translateY(42px)  rotate(-179deg);\r\n    }\r\n\r\n    50.1% {\r\n        -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);\r\n        transform: translateX(42px) translateY(42px) rotate(-180deg);\r\n    }\r\n\r\n    75% {\r\n        -webkit-transform: translateX(0px)  translateY(42px)  rotate(-270deg)  scale(0 .5 );\r\n        transform: translateX(0px)  translateY(42px)  rotate(-270deg)  scale(0 .5 );\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: rotate(-360deg);\r\n        transform: rotate(-360deg);\r\n    }\r\n}\r\n\r\n@keyframes sk-wanderingCubeMove {\r\n    25% {\r\n        -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);\r\n        transform: translateX(42px) rotate(-90deg) scale(0.5);\r\n    }\r\n\r\n    50% {\r\n        /* Hack to make FF rotate in the right direction */\r\n        -webkit-transform: translateX(42px)  translateY(42px)  rotate(-179deg);\r\n        transform: translateX(42px)  translateY(42px)  rotate(-179deg);\r\n    }\r\n\r\n    50.1%{\r\n        -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);\r\n        transform: translateX(42px) translateY(42px) rotate(-180deg);\r\n    }\r\n\r\n    75% {\r\n        -webkit-transform: translateX(0px)  translateY(42px)  rotate(-270deg)  scale(0 .5 );\r\n        transform: translateX(0px)  translateY(42px)  rotate(-270deg)  scale(0 .5 );\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: rotate(-360deg);\r\n        transform: rotate(-360deg);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-pulse\"></div>\r\n *\r\n */\r\n.sk-spinner-pulse.sk-spinner {\r\n    width: 40px;\r\n    height: 40px;\r\n    margin: 0 auto;\r\n    background-color: #1ab394;\r\n    border-radius: 100%;\r\n    -webkit-animation: sk-pulseScaleOut 1s infinite ease-in-out;\r\n    animation: sk-pulseScaleOut 1s infinite ease-in-out;\r\n}\r\n\r\n@-webkit-keyframes sk-pulseScaleOut {\r\n    0% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n        opacity: 0;\r\n    }\r\n}\r\n\r\n@keyframes sk-pulseScaleOut {\r\n    0% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n        opacity: 0;\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-chasing-dots\">\r\n *      <div class=\"sk-dot1\"></div>\r\n *      <div class=\"sk-dot2\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-chasing-dots.sk-spinner {\r\n    margin: 0 auto;\r\n    width: 40px;\r\n    height: 40px;\r\n    position: relative;\r\n    text-align: center;\r\n    -webkit-animation: sk-chasingDotsRotate 2s infinite linear;\r\n    animation: sk-chasingDotsRotate 2s infinite linear;\r\n}\r\n\r\n.sk-spinner-chasing-dots .sk-dot1, .sk-spinner-chasing-dots .sk-dot2 {\r\n    width: 60%;\r\n    height: 60%;\r\n    display: inline-block;\r\n    position: absolute;\r\n    top: 0;\r\n    background-color: #1ab394;\r\n    border-radius: 100%;\r\n    -webkit-animation: sk-chasingDotsBounce 2s infinite ease-in-out;\r\n    animation: sk-chasingDotsBounce 2s infinite ease-in-out;\r\n}\r\n\r\n.sk-spinner-chasing-dots .sk-dot2 {\r\n    top: auto;\r\n    bottom: 0px;\r\n    -webkit-animation-delay: -1s;\r\n    animation-delay: -1s;\r\n}\r\n\r\n@-webkit-keyframes sk-chasingDotsRotate {\r\n    100% {\r\n        -webkit-transform: rotate(360deg);\r\n        transform: rotate(360deg);\r\n    }\r\n}\r\n\r\n@keyframes sk-chasingDotsRotate {\r\n    100% {\r\n        -webkit-transform: rotate(360deg);\r\n        transform: rotate(360deg);\r\n    }\r\n}\r\n\r\n@-webkit-keyframes sk-chasingDotsBounce {\r\n    0%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    50% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n\r\n@keyframes sk-chasingDotsBounce {\r\n    0%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    50% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-three-bounce\">\r\n *      <div class=\"sk-bounce1\"></div>\r\n *      <div class=\"sk-bounce2\"></div>\r\n *      <div class=\"sk-bounce3\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-three-bounce.sk-spinner {\r\n    margin: 0 auto;\r\n    width: 70px;\r\n    text-align: center;\r\n}\r\n\r\n.sk-spinner-three-bounce div {\r\n    width: 18px;\r\n    height: 18px;\r\n    background-color: #1ab394;\r\n    border-radius: 100%;\r\n    display: inline-block;\r\n    -webkit-animation: sk-threeBounceDelay 1.4s infinite ease-in-out;\r\n    animation: sk-threeBounceDelay 1.4s infinite ease-in-out;\r\n    /* Prevent first frame from flickering when animation starts */\r\n    -webkit-animation-fill-mode: both;\r\n    animation-fill-mode: both;\r\n}\r\n\r\n.sk-spinner-three-bounce .sk-bounce1 {\r\n    -webkit-animation-delay: -0.32s;\r\n    animation-delay: -0.32s;\r\n}\r\n\r\n.sk-spinner-three-bounce .sk-bounce2 {\r\n    -webkit-animation-delay: -0.16s;\r\n    animation-delay: -0.16s;\r\n}\r\n\r\n@-webkit-keyframes sk-threeBounceDelay {\r\n    0%, 80%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    40% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n\r\n@keyframes sk-threeBounceDelay {\r\n    0%, 80%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    40% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-circle\">\r\n *      <div class=\"sk-circle1 sk-circle\"></div>\r\n *      <div class=\"sk-circle2 sk-circle\"></div>\r\n *      <div class=\"sk-circle3 sk-circle\"></div>\r\n *      <div class=\"sk-circle4 sk-circle\"></div>\r\n *      <div class=\"sk-circle5 sk-circle\"></div>\r\n *      <div class=\"sk-circle6 sk-circle\"></div>\r\n *      <div class=\"sk-circle7 sk-circle\"></div>\r\n *      <div class=\"sk-circle8 sk-circle\"></div>\r\n *      <div class=\"sk-circle9 sk-circle\"></div>\r\n *      <div class=\"sk-circle10 sk-circle\"></div>\r\n *      <div class=\"sk-circle11 sk-circle\"></div>\r\n *      <div class=\"sk-circle12 sk-circle\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-circle.sk-spinner {\r\n    margin: 0 auto;\r\n    width: 22px;\r\n    height: 22px;\r\n    position: relative;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle {\r\n    width: 100%;\r\n    height: 100%;\r\n    position: absolute;\r\n    left: 0;\r\n    top: 0;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle:before {\r\n    content: '';\r\n    display: block;\r\n    margin: 0 auto;\r\n    width: 20%;\r\n    height: 20%;\r\n    background-color: #1ab394;\r\n    border-radius: 100%;\r\n    -webkit-animation: sk-circleBounceDelay 1.2s infinite ease-in-out;\r\n    animation: sk-circleBounceDelay 1.2s infinite ease-in-out;\r\n    /* Prevent first frame from flickering when animation starts */\r\n    -webkit-animation-fill-mode: both;\r\n    animation-fill-mode: both;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle2 {\r\n    -webkit-transform: rotate(30deg);\r\n    -ms-transform: rotate(30deg);\r\n    transform: rotate(30deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle3 {\r\n    -webkit-transform: rotate(60deg);\r\n    -ms-transform: rotate(60deg);\r\n    transform: rotate(60deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle4 {\r\n    -webkit-transform: rotate(90deg);\r\n    -ms-transform: rotate(90deg);\r\n    transform: rotate(90deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle5 {\r\n    -webkit-transform: rotate(120deg);\r\n    -ms-transform: rotate(120deg);\r\n    transform: rotate(120deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle6 {\r\n    -webkit-transform: rotate(150deg);\r\n    -ms-transform: rotate(150deg);\r\n    transform: rotate(150deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle7 {\r\n    -webkit-transform: rotate(180deg);\r\n    -ms-transform: rotate(180deg);\r\n    transform: rotate(180deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle8 {\r\n    -webkit-transform: rotate(210deg);\r\n    -ms-transform: rotate(210deg);\r\n    transform: rotate(210deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle9 {\r\n    -webkit-transform: rotate(240deg);\r\n    -ms-transform: rotate(240deg);\r\n    transform: rotate(240deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle10 {\r\n    -webkit-transform: rotate(270deg);\r\n    -ms-transform: rotate(270deg);\r\n    transform: rotate(270deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle11 {\r\n    -webkit-transform: rotate(300deg);\r\n    -ms-transform: rotate(300deg);\r\n    transform: rotate(300deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle12 {\r\n    -webkit-transform: rotate(330deg);\r\n    -ms-transform: rotate(330deg);\r\n    transform: rotate(330deg);\r\n}\r\n\r\n.sk-spinner-circle .sk-circle2:before {\r\n    -webkit-animation-delay: -1.1s;\r\n    animation-delay: -1.1s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle3:before {\r\n    -webkit-animation-delay: -1s;\r\n    animation-delay: -1s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle4:before {\r\n    -webkit-animation-delay: -0.9s;\r\n    animation-delay: -0.9s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle5:before {\r\n    -webkit-animation-delay: -0.8s;\r\n    animation-delay: -0.8s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle6:before {\r\n    -webkit-animation-delay: -0.7s;\r\n    animation-delay: -0.7s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle7:before {\r\n    -webkit-animation-delay: -0.6s;\r\n    animation-delay: -0.6s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle8:before {\r\n    -webkit-animation-delay: -0.5s;\r\n    animation-delay: -0.5s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle9:before {\r\n    -webkit-animation-delay: -0.4s;\r\n    animation-delay: -0.4s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle10:before {\r\n    -webkit-animation-delay: -0.3s;\r\n    animation-delay: -0.3s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle11:before {\r\n    -webkit-animation-delay: -0.2s;\r\n    animation-delay: -0.2s;\r\n}\r\n\r\n.sk-spinner-circle .sk-circle12:before {\r\n    -webkit-animation-delay: -0.1s;\r\n    animation-delay: -0.1s;\r\n}\r\n\r\n@-webkit-keyframes sk-circleBounceDelay {\r\n    0%, 80%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    40% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n\r\n@keyframes sk-circleBounceDelay {\r\n    0%, 80%, 100% {\r\n        -webkit-transform: scale(0);\r\n        transform: scale(0);\r\n    }\r\n\r\n    40% {\r\n        -webkit-transform: scale(1);\r\n        transform: scale(1);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-cube-grid\">\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *      <div class=\"sk-cube\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-cube-grid {\r\n    /*\r\n       * Spinner positions\r\n       * 1 2 3\r\n       * 4 5 6\r\n       * 7 8 9\r\n       */\r\n}\r\n\r\n.sk-spinner-cube-grid.sk-spinner {\r\n    width: 30px;\r\n    height: 30px;\r\n    margin: 0 auto;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube {\r\n    width: 33%;\r\n    height: 33%;\r\n    background-color: #1ab394;\r\n    float: left;\r\n    -webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;\r\n    animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(1) {\r\n    -webkit-animation-delay: 0.2s;\r\n    animation-delay: 0.2s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(2) {\r\n    -webkit-animation-delay: 0.3s;\r\n    animation-delay: 0.3s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(3) {\r\n    -webkit-animation-delay: 0.4s;\r\n    animation-delay: 0.4s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(4) {\r\n    -webkit-animation-delay: 0.1s;\r\n    animation-delay: 0.1s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(5) {\r\n    -webkit-animation-delay: 0.2s;\r\n    animation-delay: 0.2s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(6) {\r\n    -webkit-animation-delay: 0.3s;\r\n    animation-delay: 0.3s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(7) {\r\n    -webkit-animation-delay: 0s;\r\n    animation-delay: 0s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(8) {\r\n    -webkit-animation-delay: 0.1s;\r\n    animation-delay: 0.1s;\r\n}\r\n\r\n.sk-spinner-cube-grid .sk-cube:nth-child(9) {\r\n    -webkit-animation-delay: 0.2s;\r\n    animation-delay: 0.2s;\r\n}\r\n\r\n@-webkit-keyframes sk-cubeGridScaleDelay {\r\n    0%, 70%, 100% {\r\n        -webkit-transform: scale3D(1, 1, 1);\r\n        transform: scale3D(1, 1, 1);\r\n    }\r\n\r\n    35% {\r\n        -webkit-transform: scale3D(0, 0, 1);\r\n        transform: scale3D(0, 0, 1);\r\n    }\r\n}\r\n\r\n@keyframes sk-cubeGridScaleDelay {\r\n    0%, 70%, 100% {\r\n        -webkit-transform: scale3D(1, 1, 1);\r\n        transform: scale3D(1, 1, 1);\r\n    }\r\n\r\n    35% {\r\n        -webkit-transform: scale3D(0, 0, 1);\r\n        transform: scale3D(0, 0, 1);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-wordpress\">\r\n *      <span class=\"sk-inner-circle\"></span>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-wordpress.sk-spinner {\r\n    background-color: #1ab394;\r\n    width: 30px;\r\n    height: 30px;\r\n    border-radius: 30px;\r\n    position: relative;\r\n    margin: 0 auto;\r\n    -webkit-animation: sk-innerCircle 1s linear infinite;\r\n    animation: sk-innerCircle 1s linear infinite;\r\n}\r\n\r\n.sk-spinner-wordpress .sk-inner-circle {\r\n    display: block;\r\n    background-color: #fff;\r\n    width: 8px;\r\n    height: 8px;\r\n    position: absolute;\r\n    border-radius: 8px;\r\n    top: 5px;\r\n    left: 5px;\r\n}\r\n\r\n@-webkit-keyframes sk-innerCircle {\r\n    0% {\r\n        -webkit-transform: rotate(0);\r\n        transform: rotate(0);\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: rotate(360deg);\r\n        transform: rotate(360deg);\r\n    }\r\n}\r\n\r\n@keyframes sk-innerCircle {\r\n    0% {\r\n        -webkit-transform: rotate(0);\r\n        transform: rotate(0);\r\n    }\r\n\r\n    100% {\r\n        -webkit-transform: rotate(360deg);\r\n        transform: rotate(360deg);\r\n    }\r\n}\r\n/*\r\n *  Usage:\r\n *\r\n *    <div class=\"sk-spinner sk-spinner-fading-circle\">\r\n *      <div class=\"sk-circle1 sk-circle\"></div>\r\n *      <div class=\"sk-circle2 sk-circle\"></div>\r\n *      <div class=\"sk-circle3 sk-circle\"></div>\r\n *      <div class=\"sk-circle4 sk-circle\"></div>\r\n *      <div class=\"sk-circle5 sk-circle\"></div>\r\n *      <div class=\"sk-circle6 sk-circle\"></div>\r\n *      <div class=\"sk-circle7 sk-circle\"></div>\r\n *      <div class=\"sk-circle8 sk-circle\"></div>\r\n *      <div class=\"sk-circle9 sk-circle\"></div>\r\n *      <div class=\"sk-circle10 sk-circle\"></div>\r\n *      <div class=\"sk-circle11 sk-circle\"></div>\r\n *      <div class=\"sk-circle12 sk-circle\"></div>\r\n *    </div>\r\n *\r\n */\r\n.sk-spinner-fading-circle.sk-spinner {\r\n    margin: 0 auto;\r\n    width: 22px;\r\n    height: 22px;\r\n    position: relative;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle {\r\n    width: 100%;\r\n    height: 100%;\r\n    position: absolute;\r\n    left: 0;\r\n    top: 0;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle:before {\r\n    content: '';\r\n    display: block;\r\n    margin: 0 auto;\r\n    width: 18%;\r\n    height: 18%;\r\n    background-color: #1ab394;\r\n    border-radius: 100%;\r\n    -webkit-animation: sk-circleFadeDelay 1.2s infinite ease-in-out;\r\n    animation: sk-circleFadeDelay 1.2s infinite ease-in-out;\r\n    /* Prevent first frame from flickering when animation starts */\r\n    -webkit-animation-fill-mode: both;\r\n    animation-fill-mode: both;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle2 {\r\n    -webkit-transform: rotate(30deg);\r\n    -ms-transform: rotate(30deg);\r\n    transform: rotate(30deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle3 {\r\n    -webkit-transform: rotate(60deg);\r\n    -ms-transform: rotate(60deg);\r\n    transform: rotate(60deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle4 {\r\n    -webkit-transform: rotate(90deg);\r\n    -ms-transform: rotate(90deg);\r\n    transform: rotate(90deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle5 {\r\n    -webkit-transform: rotate(120deg);\r\n    -ms-transform: rotate(120deg);\r\n    transform: rotate(120deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle6 {\r\n    -webkit-transform: rotate(150deg);\r\n    -ms-transform: rotate(150deg);\r\n    transform: rotate(150deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle7 {\r\n    -webkit-transform: rotate(180deg);\r\n    -ms-transform: rotate(180deg);\r\n    transform: rotate(180deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle8 {\r\n    -webkit-transform: rotate(210deg);\r\n    -ms-transform: rotate(210deg);\r\n    transform: rotate(210deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle9 {\r\n    -webkit-transform: rotate(240deg);\r\n    -ms-transform: rotate(240deg);\r\n    transform: rotate(240deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle10 {\r\n    -webkit-transform: rotate(270deg);\r\n    -ms-transform: rotate(270deg);\r\n    transform: rotate(270deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle11 {\r\n    -webkit-transform: rotate(300deg);\r\n    -ms-transform: rotate(300deg);\r\n    transform: rotate(300deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle12 {\r\n    -webkit-transform: rotate(330deg);\r\n    -ms-transform: rotate(330deg);\r\n    transform: rotate(330deg);\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle2:before {\r\n    -webkit-animation-delay: -1.1s;\r\n    animation-delay: -1.1s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle3:before {\r\n    -webkit-animation-delay: -1s;\r\n    animation-delay: -1s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle4:before {\r\n    -webkit-animation-delay: -0.9s;\r\n    animation-delay: -0.9s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle5:before {\r\n    -webkit-animation-delay: -0.8s;\r\n    animation-delay: -0.8s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle6:before {\r\n    -webkit-animation-delay: -0.7s;\r\n    animation-delay: -0.7s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle7:before {\r\n    -webkit-animation-delay: -0.6s;\r\n    animation-delay: -0.6s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle8:before {\r\n    -webkit-animation-delay: -0.5s;\r\n    animation-delay: -0.5s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle9:before {\r\n    -webkit-animation-delay: -0.4s;\r\n    animation-delay: -0.4s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle10:before {\r\n    -webkit-animation-delay: -0.3s;\r\n    animation-delay: -0.3s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle11:before {\r\n    -webkit-animation-delay: -0.2s;\r\n    animation-delay: -0.2s;\r\n}\r\n\r\n.sk-spinner-fading-circle .sk-circle12:before {\r\n    -webkit-animation-delay: -0.1s;\r\n    animation-delay: -0.1s;\r\n}\r\n\r\n@-webkit-keyframes sk-circleFadeDelay {\r\n    0%, 39%, 100% {\r\n        opacity: 0;\r\n    }\r\n\r\n    40% {\r\n        opacity: 1;\r\n    }\r\n}\r\n\r\n@keyframes sk-circleFadeDelay {\r\n    0%,39%,100% {\r\n        opacity: 0;\r\n    }\r\n\r\n    40% {\r\n        opacity: 1;\r\n    }\r\n}\r\n\r\nbody.rtls {\r\n    /* Theme config */\r\n}\r\n\r\nbody.rtls #page-wrapper {\r\n    margin: 0 220px 0 0;\r\n}\r\n\r\nbody.rtls .nav-second-level li a {\r\n    padding: 7px 35px 7px 10px;\r\n}\r\n\r\nbody.rtls .ibox-title h5 {\r\n    float: right;\r\n}\r\n\r\nbody.rtls .pull-right {\r\n    float: left !important;\r\n}\r\n\r\nbody.rtls .pull-left {\r\n    float: right !important;\r\n}\r\n\r\nbody.rtls .ibox-tools {\r\n    float: left;\r\n}\r\n\r\nbody.rtls .stat-percent {\r\n    float: left;\r\n}\r\n\r\nbody.rtls .navbar-right {\r\n    float: left !important;\r\n}\r\n\r\nbody.rtls .navbar-top-links li:last-child {\r\n    margin-left: 40px;\r\n    margin-right: 0;\r\n}\r\n\r\nbody.rtls .minimalize-styl-2 {\r\n    float: right;\r\n    margin: 14px 20px 5px 5px;\r\n}\r\n\r\nbody.rtls .feed-element>.pull-left {\r\n    margin-left: 10px;\r\n    margin-right: 0;\r\n}\r\n\r\nbody.rtls .timeline-item .date {\r\n    text-align: left;\r\n}\r\n\r\nbody.rtls .timeline-item .date i {\r\n    left: 0;\r\n    right: auto;\r\n}\r\n\r\nbody.rtls .timeline-item .content {\r\n    border-right: 1px solid #e7eaec;\r\n    border-left: none;\r\n}\r\n\r\nbody.rtls .toast-close-button {\r\n    float: left;\r\n}\r\n\r\nbody.rtls #toast-container>.toast:before {\r\n    margin: auto -1.5em auto 0.5em;\r\n}\r\n\r\nbody.rtls #toast-container>div {\r\n    padding: 15px 50px 15px 15px;\r\n}\r\n\r\nbody.rtls .center-orientation .vertical-timeline-icon i {\r\n    margin-left: 0;\r\n    margin-right: -12px;\r\n}\r\n\r\nbody.rtls .vertical-timeline-icon i {\r\n    right: 50%;\r\n    left: auto;\r\n    margin-left: auto;\r\n    margin-right: -12px;\r\n}\r\n\r\nbody.rtls .file-box {\r\n    float: right;\r\n}\r\n\r\nbody.rtls ul.notes li {\r\n    float: right;\r\n}\r\n\r\nbody.rtls .chat-users, body.rtls .chat-statistic {\r\n    margin-right: -30px;\r\n    margin-left: auto;\r\n}\r\n\r\nbody.rtls .dropdown-menu>li>a {\r\n    text-align: right;\r\n}\r\n\r\nbody.rtls .b-r {\r\n    border-left: 1px solid #e7eaec;\r\n    border-right: none;\r\n}\r\n\r\nbody.rtls .dd-list .dd-list {\r\n    padding-right: 30px;\r\n    padding-left: 0;\r\n}\r\n\r\nbody.rtls .dd-item>button {\r\n    float: right;\r\n}\r\n\r\nbody.rtls .skin-setttings {\r\n    margin-right: 40px;\r\n    margin-left: 0;\r\n}\r\n\r\nbody.rtls .skin-setttings {\r\n    direction: ltr;\r\n}\r\n\r\nbody.rtls .footer.fixed {\r\n    margin-right: 220px;\r\n    margin-left: 0;\r\n}\r\n\r\n@media ( max-width : 992px) {\r\n    body.rtls .chat-users, body.rtls .chat-statistic {\r\n        margin-right: 0px;\r\n    }\r\n}\r\n\r\nbody.rtls.mini-navbar .footer.fixed, body.body-small.mini-navbar .footer.fixed {\r\n    margin: 0 70px 0 0;\r\n}\r\n\r\nbody.rtls.mini-navbar.fixed-sidebar .footer.fixed, body.body-small.mini-navbar .footer.fixed {\r\n    margin: 0 0 0 0;\r\n}\r\n\r\nbody.rtls.top-navigation .navbar-toggle {\r\n    float: right;\r\n    margin-left: 15px;\r\n    margin-right: 15px;\r\n}\r\n\r\n.body-small.rtls.top-navigation .navbar-header {\r\n    float: none;\r\n}\r\n\r\nbody.rtls.top-navigation #page-wrapper {\r\n    margin: 0;\r\n}\r\n\r\nbody.rtls.mini-navbar #page-wrapper {\r\n    margin: 0 70px 0 0;\r\n}\r\n\r\nbody.rtls.mini-navbar.fixed-sidebar #page-wrapper {\r\n    margin: 0 0 0 0;\r\n}\r\n\r\nbody.rtls.body-small.fixed-sidebar.mini-navbar #page-wrapper {\r\n    margin: 0 220px 0 0;\r\n}\r\n\r\nbody.rtls.body-small.fixed-sidebar.mini-navbar .navbar-static-side {\r\n    width: 220px;\r\n}\r\n\r\n.body-small.rtls .navbar-fixed-top {\r\n    margin-right: 0px;\r\n}\r\n\r\n.body-small.rtls .navbar-header {\r\n    float: right;\r\n}\r\n\r\nbody.rtls .navbar-top-links li:last-child {\r\n    margin-left: 20px;\r\n}\r\n\r\nbody.rtls .top-navigation #page-wrapper, body.rtls.mini-navbar .top-navigation #page-wrapper,  body.rtls.mini-navbar.top-navigation #page-wrapper {\r\n    margin: 0;\r\n}\r\n\r\nbody.rtls .top-navigation .footer.fixed, body.rtls.top-navigation .footer.fixed {\r\n    margin: 0;\r\n}\r\n\r\n@media ( max-width : 768px) {\r\n    body.rtls .navbar-top-links li:last-child {\r\n        margin-left: 20px;\r\n    }\r\n\r\n    .body-small.rtls #page-wrapper {\r\n        position: inherit;\r\n        margin: 0 0 0 0px;\r\n        min-height: 1000px;\r\n    }\r\n\r\n    .body-small.rtls .navbar-static-side {\r\n        display: none;\r\n        z-index: 2001;\r\n        position: absolute;\r\n        width: 70px;\r\n    }\r\n\r\n    .body-small.rtls.mini-navbar .navbar-static-side {\r\n        display: block;\r\n    }\r\n\r\n    .rtls.fixed-sidebar.body-small .navbar-static-side {\r\n        display: none;\r\n        z-index: 2001;\r\n        position: fixed;\r\n        width: 220px;\r\n    }\r\n\r\n    .rtls.fixed-sidebar.body-small.mini-navbar .navbar-static-side {\r\n        display: block;\r\n    }\r\n}\r\n\r\n.rtls .ltr-support {\r\n    direction: ltr;\r\n}\r\n.page-tabs a {\r\n    color: #999;\r\n}\r\n\r\n.page-tabs a i {\r\n    color: #ccc;\r\n\tmargin-left: 2px;\r\n\tfont-size: 13px;\r\n}\r\n\r\n.page-tabs a.active {\r\n\tbackground: #eaedf1;\r\n\tcolor: #23508e;\r\n}\r\n.page-tabs a.active:hover,\r\n.page-tabs a.active i:hover {\r\n\tbackground: #eaedf1;\r\n\tcolor: #23508e;\r\n}\r\n\r\n@media ( min-width : 768px) {\r\n    .navbar-top-links .dropdown-messages, .navbar-top-links .dropdown-tasks,  .navbar-top-links .dropdown-alerts {\r\n        margin-left: auto;\r\n    }\r\n}\r\n\r\n@media ( max-width : 768px) {\r\n    body.fixed-sidebar .navbar-static-side {\r\n        display: none;\r\n    }\r\n\r\n    body.fixed-sidebar.mini-navbar .navbar-static-side {\r\n        width: 70px;\r\n    }\r\n\r\n    .lock-word {\r\n        display: none;\r\n    }\r\n\r\n    .navbar-form-custom {\r\n        display: none;\r\n    }\r\n\r\n    .navbar-header {\r\n        display: inline;\r\n        float: left;\r\n    }\r\n\r\n    .sidebard-panel {\r\n        z-index: 2;\r\n        position: relative;\r\n        width: auto;\r\n        min-height: 100% !important;\r\n    }\r\n\r\n    .sidebar-content .wrapper {\r\n        padding-right: 0px;\r\n        z-index: 1;\r\n    }\r\n\r\n    .fixed-sidebar.body-small .navbar-static-side {\r\n        display: none;\r\n        z-index: 2001;\r\n        position: fixed;\r\n        width: 220px;\r\n    }\r\n\r\n    .fixed-sidebar.body-small.mini-navbar .navbar-static-side {\r\n        display: block;\r\n    }\r\n\r\n    .ibox-tools {\r\n        float: none;\r\n        text-align: right;\r\n        display: block;\r\n    }\r\n\r\n    .content-tabs {\r\n        display: none;\r\n    }\r\n\r\n    #content-main {\r\n        height: calc(100% - 100px);\r\n    }\r\n\r\n    .fixed-nav #content-main {\r\n        height: calc(100% - 38px);\r\n    }\r\n}\r\n\r\n.navbar-static-side {\r\n    background: #2f4050;\r\n}\r\n\r\n.nav-close {\r\n    padding: 10px;\r\n    display: block;\r\n    position: absolute;\r\n    right: 5px;\r\n    top: 5px;\r\n    font-size: 1.4em;\r\n    cursor: pointer;\r\n    z-index: 10;\r\n    display: none;\r\n    color: rgba(255, 255, 255, .3);\r\n}\r\n\r\n@media ( max-width : 350px) {\r\n    body.fixed-sidebar.mini-navbar .navbar-static-side {\r\n        width: 0;\r\n    }\r\n\r\n    .nav-close {\r\n        display: block;\r\n    }\r\n\r\n    #page-wrapper {\r\n        margin-left: 0 !important;\r\n    }\r\n\r\n    .timeline-item .date {\r\n        text-align: left;\r\n        width: 110px;\r\n        position: relative;\r\n        padding-top: 30px;\r\n    }\r\n\r\n    .timeline-item .date i {\r\n        position: absolute;\r\n        top: 0;\r\n        left: 15px;\r\n        padding: 5px;\r\n        width: 30px;\r\n        text-align: center;\r\n        border: 1px solid #e7eaec;\r\n        background: #f8f8f8;\r\n    }\r\n\r\n    .timeline-item .content {\r\n        border-left: none;\r\n        border-top: 1px solid #e7eaec;\r\n        padding-top: 10px;\r\n        min-height: 100px;\r\n    }\r\n\r\n    .nav.navbar-top-links li.dropdown {\r\n        display: none;\r\n    }\r\n\r\n    .ibox-tools {\r\n        float: none;\r\n        text-align: left;\r\n        display: inline-block;\r\n    }\r\n}\r\n/*JQGRID*/\r\n.ui-jqgrid-titlebar {\r\n    height: 40px;\r\n    line-height: 24px;\r\n    color: #676a6c;\r\n    background-color: #F9F9F9;\r\n    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\r\n}\r\n\r\n.ui-jqgrid .ui-jqgrid-title {\r\n    float: left;\r\n    margin-left: 5px;\r\n    font-weight: 700;\r\n}\r\n\r\n.ui-jqgrid .ui-jqgrid-titlebar {\r\n    position: relative;\r\n    border-left: 0px solid;\r\n    border-right: 0px solid;\r\n    border-top: 0px solid;\r\n}\r\n/* Social feed */\r\n.social-feed-separated .social-feed-box {\r\n    margin-left: 62px;\r\n}\r\n\r\n.social-feed-separated .social-avatar {\r\n    float: left;\r\n    padding: 0;\r\n}\r\n\r\n.social-feed-separated .social-avatar img {\r\n    width: 52px;\r\n    height: 52px;\r\n    border: 1px solid #e7eaec;\r\n}\r\n\r\n.social-feed-separated .social-feed-box .social-avatar {\r\n    padding: 15px 15px 0 15px;\r\n    float: none;\r\n}\r\n\r\n.social-feed-box {\r\n    /*padding: 15px;*/\r\n    border: 1px solid #e7eaec;\r\n    background: #fff;\r\n    margin-bottom: 15px;\r\n}\r\n\r\n.article .social-feed-box {\r\n    margin-bottom: 0;\r\n    border-bottom: none;\r\n}\r\n\r\n.article .social-feed-box:last-child {\r\n    margin-bottom: 0;\r\n    border-bottom: 1px solid #e7eaec;\r\n}\r\n\r\n.article .social-feed-box p {\r\n    font-size: 13px;\r\n    line-height: 18px;\r\n}\r\n\r\n.social-action {\r\n    margin: 15px;\r\n}\r\n\r\n.social-avatar {\r\n    padding: 15px 15px 0 15px;\r\n}\r\n\r\n.social-comment .social-comment {\r\n    margin-left: 45px;\r\n}\r\n\r\n.social-avatar img {\r\n    height: 40px;\r\n    width: 40px;\r\n    margin-right: 10px;\r\n}\r\n\r\n.social-avatar .media-body a {\r\n    font-size: 14px;\r\n    display: block;\r\n}\r\n\r\n.social-body {\r\n    padding: 15px;\r\n}\r\n\r\n.social-body img {\r\n    margin-bottom: 10px;\r\n}\r\n\r\n.social-footer {\r\n    border-top: 1px solid #e7eaec;\r\n    padding: 10px 15px;\r\n    background: #f9f9f9;\r\n}\r\n\r\n.social-footer .social-comment img {\r\n    width: 32px;\r\n    margin-right: 10px;\r\n}\r\n\r\n.social-comment:first-child {\r\n    margin-top: 0;\r\n}\r\n\r\n.social-comment {\r\n    margin-top: 15px;\r\n}\r\n\r\n.social-comment textarea {\r\n    font-size: 12px;\r\n}\r\n\r\n.checkbox input[type=checkbox], .checkbox-inline input[type=checkbox],  .radio input[type=radio], .radio-inline input[type=radio] {\r\n    /* margin-top: -4px; */\r\n}\r\n\r\n/* Only demo */\r\n@media ( max-width : 1000px) {\r\n    .welcome-message {\r\n        display: none;\r\n    }\r\n}\r\n/* ECHARTS  */\r\n.echarts {\r\n    height: 240px;\r\n}\r\n\r\n.checkbox-inline, .radio-inline, .checkbox-inline+.checkbox-inline,  .radio-inline+.radio-inline {\r\n    margin: 0 15px 0 0;\r\n    font-size: 14px;\r\n}\r\n\r\n.navbar-toggle {\r\n    background-color: #fff;\r\n}\r\n\r\n.menuTab {\r\n    -webkit-transition: all .3s ease-out 0s;\r\n    transition: all .3s ease-out 0s;\r\n}\r\n\r\n@media only screen and (-webkit-min-device-pixel-ratio : 2) {\r\n    #content-main {\r\n        -webkit-overflow-scrolling: touch;\r\n    }\r\n}\r\n\r\n.navbar-header {\r\n\t/* width: 10%; */\r\n\theight: 50px;\r\n}\r\n\r\n.bs-glyphicons {\r\n    margin: 0 -10px 20px;\r\n    overflow: hidden\r\n}\r\n\r\n.bs-glyphicons-list {\r\n    padding-left: 0;\r\n    list-style: none\r\n}\r\n\r\n.bs-glyphicons li {\r\n    float: left;\r\n    width: 25%;\r\n    height: 115px;\r\n    padding: 10px;\r\n    font-size: 10px;\r\n    line-height: 1.4;\r\n    text-align: center;\r\n    background-color: #f9f9f9;\r\n    border: 1px solid #fff\r\n}\r\n\r\n.bs-glyphicons .glyphicon {\r\n    margin-top: 5px;\r\n    margin-bottom: 10px;\r\n    font-size: 24px\r\n}\r\n\r\n.bs-glyphicons .glyphicon-class {\r\n    display: block;\r\n    text-align: center;\r\n    word-wrap: break-word\r\n}\r\n\r\n.bs-glyphicons li:hover {\r\n    color: #fff;\r\n    background-color: #1ab394;\r\n}\r\n\r\n@media ( min-width : 768px) {\r\n    .bs-glyphicons {\r\n        margin-right: 0;\r\n        margin-left: 0\r\n    }\r\n\r\n    .bs-glyphicons li {\r\n        width: 12.5%;\r\n        font-size: 12px\r\n    }\r\n}\r\n\r\n.t-bar {\r\n    padding-bottom: 10px;\r\n}\r\n.nopadding{\r\n    padding:0;\r\n}\r\n\r\n/*编辑器按钮样式冲突*/\r\n.note-editor .btn-default {\r\n    color: #333333!important;\r\n    background-color: #ffffff!important;\r\n    border-color: #cccccc!important;\r\n}\r\n\r\n.folder-list li.active a {\r\n\tcolor: #2791df;\r\n\tbackground: #f5f5f5;\r\n}\r\n\r\nnav .logo {\r\n\tbackground-color: #367fa9;\r\n\tcolor: #fff;\r\n\tborder-bottom: 0 solid transparent;\r\n\t-webkit-transition: width .3s ease-in-out;\r\n\t-o-transition: width .3s ease-in-out;\r\n\ttransition: width .3s ease-in-out;\r\n\tdisplay: block;\r\n\theight: 50px;\r\n\tfont-size: 20px;\r\n\tline-height: 50px;\r\n\ttext-align: center;\r\n\twidth: 200px;\r\n\tfont-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\r\n\tpadding: 0 15px;\r\n\tfont-weight: 300;\r\n\toverflow: hidden\r\n}\r\n\r\n.logo-mini {\r\n\tdisplay: none;\r\n}\r\n\r\n.logo-lg {\r\n\tdisplay: block;\r\n}\r\n\r\n.roleList {\r\n\tcolor: #d5d5d5;\r\n\tmargin-right: 10px;\r\n\tpadding-top: 10px;\r\n\tline-height: 1;\r\n\twhite-space: nowrap;\r\n\toverflow: hidden;\r\n\twidth: 110px;\r\n}\r\n\r\n.sidebar-collapse .user-panel {\r\n\twhite-space: nowrap;\r\n\tposition: relative;\r\n\twidth: 100%;\r\n\tpadding: 15px;\r\n\toverflow: hidden;\r\n}\r\n\r\n.sidebar-collapse .user-panel .image>img {\r\n\twidth: 100%;\r\n\tmax-width: 45px;\r\n\theight: auto;\r\n}\r\n\r\n.sidebar-collapse .user-panel>.info {\r\n\tpadding: 5px 5px 5px 15px;\r\n\tline-height: 1;\r\n\tposition: absolute;\r\n\tleft: 55px;\r\n}\r\n\r\n.sidebar-collapse .user-panel>.info a {\r\n\tcolor: #fff;\r\n\tfont-size: 12px;\r\n}\r\n\r\n.sidebar-collapse .user-panel>.info>p {\r\n\tfont-weight: 600;\r\n\tmargin-bottom: 9px;\r\n\tcolor: #fff;\r\n\tfont-size: 12px;\r\n}\r\n\r\n.user-panel>.info>a>.fa,\r\n.user-panel>.info>a>.ion,\r\n.user-panel>.info>a>.glyphicon {\r\n\tmargin-right: 3px;\r\n}\r\n\r\n.nav>li:hover .dropdown-menu {\r\n\tdisplay: block;\r\n}\r\n\r\n#content-main.max {\r\n\theight: calc(100% - 110px);\r\n\toverflow: hidden;\r\n\twidth: 100%;\r\n\theight: 100%;\r\n\tleft: 0px;\r\n\tposition: absolute;\r\n\ttop: 0px;\r\n\tz-index: 9998;\r\n\tmargin: 0;\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/css/zen-checkbox.css",
    "content": "@font-face {\n\tfont-family:ZenIcon;src:url(../fonts/zenicon.woff?v=2.2.0) format('woff')\n}\n\n.checkbox-primary,.radio-primary {\n\tposition: relative;\n\tdisplay: block\n}\n\n.checkbox-primary>input,.radio-primary>input {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tz-index: 3;\n\twidth: 100%;\n\twidth: 20px;\n\theight: 100%;\n\tmargin: 0;\n\topacity: 0\n}\n\n.checkbox-primary>label,.radio-primary>label {\n\tpadding-left: 25px;\n\tfont-weight: 400;\n\tcursor: pointer\n}\n\n.checkbox-primary>label:after,.checkbox-primary>label:before,.radio-primary>label:after,.radio-primary>label:before {\n\tposition: absolute;\n\ttop: 2px;\n\tright: 0;\n\tleft: 0;\n\tdisplay: block;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 16px;\n\ttext-align: center;\n\tcontent: ' ';\n\tborder-radius: 2px\n}\n\n.checkbox-primary>label:after,.radio-primary>label:after {\n\tz-index: 1;\n\tborder: 1px solid gray;\n\t-webkit-transition: .4s cubic-bezier(.175,.885,.32,1);\n\t-o-transition: .4s cubic-bezier(.175,.885,.32,1);\n\ttransition: .4s cubic-bezier(.175,.885,.32,1);\n\t-webkit-transition-property: border,background-color;\n\t-o-transition-property: border,background-color;\n\ttransition-property: border,background-color\n}\n\n.checkbox-primary>label:before,.radio-primary>label:before {\n\ttop: 3px;\n\tz-index: 2;\n\tfont-family: ZenIcon;\n\tfont-size: 14px;\n\tfont-style: normal;\n\tfont-weight: 400;\n\tfont-variant: normal;\n\tline-height: 1;\n\ttext-transform: none;\n\tcontent: '\\e60d';\n\topacity: 0;\n\t-webkit-transition: .2s cubic-bezier(.175,.885,.32,1);\n\t-o-transition: .2s cubic-bezier(.175,.885,.32,1);\n\ttransition: .2s cubic-bezier(.175,.885,.32,1);\n\t-webkit-transition-property: opacity,-webkit-transform;\n\t-o-transition-property: opacity,-o-transform;\n\ttransition-property: opacity,-webkit-transform;\n\ttransition-property: opacity,transform;\n\ttransition-property: opacity,transform,-webkit-transform,-o-transform;\n\t-webkit-transform: scale(0);\n\t-ms-transform: scale(0);\n\t-o-transform: scale(0);\n\ttransform: scale(0);\n\tspeak: none;\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale\n}\n\n.checkbox-primary.checked>label:after,.checkbox-primary>input:checked+label:after,.radio-primary.checked>label:after,.radio-primary>input:checked+label:after {\n\tbackground-color: #3280fc;\n\tborder-color: #3280fc;\n\tborder-width: 4px\n}\n\n.checkbox-primary.checked>label:before,.checkbox-primary>input:checked+label:before,.radio-primary.checked>label:before,.radio-primary>input:checked+label:before {\n\tcolor: #fff;\n\topacity: 1;\n\t-webkit-transform: scale(1);\n\t-ms-transform: scale(1);\n\t-o-transform: scale(1);\n\ttransform: scale(1)\n}\n\n.checkbox-primary.focus>label:after,.checkbox-primary>input:focus+label:after,.radio-primary.focus>label:after,.radio-primary>input:focus+label:after {\n\tborder-color: #3280fc;\n\t-webkit-box-shadow: 0 0 8px #3280fc;\n\tbox-shadow: 0 0 8px #3280fc\n}\n\n.checkbox-primary input:disabled+label:after,.checkbox-primary.disabled>label:after,.radio-primary input:disabled+label:after,.radio-primary.disabled>label:after {\n\tbackground-color: #e5e5e5;\n\tborder-color: #bbb\n}\n\n.checkbox-primary input:disabled:checked+label:after,.checkbox-primary.checked.disabled>label:after,.radio-primary input:disabled:checked+label:after,.radio-primary.checked.disabled>label:after {\n\tbackground-color: #bbb\n}\n\n.radio-primary>label:after {\n\tborder-radius: 50%\n}\n\n.radio-primary>label:before {\n\ttop: 7px;\n\tleft: 5px;\n\twidth: 6px;\n\theight: 6px;\n\tcontent: ' ';\n\tborder: 0;\n\tborder-radius: 50%\n}\n\n.radio-primary.checked>label:after,.radio-primary>input:checked+label:after {\n\tbackground-color: transparent;\n\tborder-color: #3280fc;\n\tborder-width: 2px\n}\n\n.radio-primary.checked>label:before,.radio-primary>input:checked+label:before {\n\tbackground-color: #3280fc\n}\n\n.radio-primary input:disabled:checked+label:after,.radio-primary.checked.disabled>label:after {\n\tbackground-color: transparent;\n\tborder-color: #bbb\n}\n\n.radio-primary input:disabled:checked+label:before,.radio-primary.checked.disabled>label:before {\n\tbackground-color: #bbb\n}\n\n.tab-cron .tab-pane .tabsecondchk .checkbox-primary,.tab-qqskey .tab-pane .tabsecondchk .checkbox-primary {\n\twidth: 50px;\n\tdisplay: inline-block;\n\tmargin-bottom: 10px\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/file/rml.txt",
    "content": "下载临时目录"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/html/ie.html",
    "content": "\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n    <meta charset=\"UTF-8\" />\r\n    <title>请升级您的浏览器</title>\r\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge,chrome=1\" >\r\n    <meta name=\"renderer\" content=\"webkit\">\r\n    <base target=\"_blank\" />\r\n    <style type=\"text/css\">\r\n        html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}\r\n        a{text-decoration:none;color:#0072c6;}a:hover{text-decoration:none;color:#004d8c;}\r\n        body{width:960px;margin:0 auto;padding:10px;font-size:14px;line-height:24px;color:#454545;font-family:'Microsoft YaHei UI','Microsoft YaHei',DengXian,SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif;overflow-y:scroll}\r\n        h1{font-size:40px;line-height:80px;font-weight:100;margin-bottom:10px;}\r\n        h2{font-size:20px;line-height:25px;font-weight:100;margin:10px 0;}\r\n        em{color:red}\r\n        p{margin-bottom:10px;}\r\n        hr{margin:20px 0;border:0;border-top:1px solid #dadada}\r\n        span{display:block;font-size:12px;line-height:12px;}\r\n        .clean{clear:both;}\r\n        .browser{padding:10px 10px;}\r\n        .browser li{width:auto;padding:0 80px;margin-top:30px;height:34px;line-height:22px;float:left;list-style:none;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAADMCAYAAAAWCXEwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAC7ESURBVHja5Lx5dFRV1rBfgHwYRQQVtB26ZWhtabtfeUGxGxFbUGZF8RMHGkVbRkekVYiKisicVhE0gEwBokgDAhEMMSSQkAECwcxkrlRSqVTqJqnxzs/vj5t7qUyAvr9e37fWV2vtleSm6p6n9t5nn733OVU2RaUaEP5PiqJSbeMXPBTA5/Xhzk9Vnd9vo3HFx21E2LYJX9IRgh6npvyCe9uaqS4K4C3IpXHFx9S99CTuJ8Z0KLVjRlA7ZgTuJ8ZgXxmJL+kIlwAkXBQk6HFq9pWRVA8fSvXwodYgdS892a6EA1UNvouqwXdR99KTeAtyfz2IL+kI1cOHYh9wqwVwKWJqpXbMCOv19gG3Imzb1JF2OgZxfr/NukH4jcNVfyEAE8IU+4BbKet1PfaVke3BtA/i/H6b8aIBt7a4mWmaC0nr55vmqRp8F5V33Mm5LhHtwbQF8SUdsSDCb1I1+K42g1xIWgOYYh9wK+e6RCBs29QxSIWus37aJM51iWjx4so77mwD1d5AHQ1eecedlN9yuyVlva6nrNf14Q7cEmRn4W7u3T2E9ME3UX7L7W1uZg5Weced1s3sA2613ql5LXzQjuRclwjcT4wxTXQeRHC7GLdnHPeensiCVwa3e0PznZk3EbZtwluQa0kofz8NcVNxr++Ce30XnNuv61Bcu7viXt8Fvyu7JYipjfGHxzD+8Bh2j+7fAiZcC+Y0zPDIbCyD6DyV6DyVeDcIQR2C39J4oieNJ3oSOnkVcnZ35Ozu6MVdDHF0N6S4C43OqJYg/0ydzb27hzDx0FjuPT2R+asfa6OVsl7X40s6QoWus/CQk6fWZPHChhxe3lbMCxtyrN9TyxSQSwidvMoC0XK6tRGybPjSRmOuNUKVo4Zxe8YxIu4+Jh4ay/jDY7j39MQWWjnXJYLGFR9Toes8tSaLiavTrIHDxfxfapkCwW8hy9YuhCmhk1fR1FRnaCS1NM4yy8RDYy2tjIkZRXq/HtYsCnqc2sJDTkYsTrU00J6YkEJQR7M/eEGY0MmrcOenqjZA2JmyzTJLuJiOe65LBHUvPUmGR2bE4lQmrk7jqTVZHcrE1WkMWpRIdJ4KnpUXBCHLRl3e16EWIOEaMU00/vAY9na/gsYVH/NdgYe+8w9bMBeSQYsSWXjICcFvL2ga+dhlFwcJ10rjio/ZklprgbSWiavTWvzdd/5hXt5W/OtATC201sq9u4eQ+PVijmSW0nf+YQYtSmTQosR2gUYsTmXQokT6zj9saeRCpmkJ0hxD2gOZeGgsI+Lu45+ps7FXlFmDmDDtSd/5h+k7/zCpZQpa9cwOQciyIR+77LyzFhXlMyZmFOP2jLP8orVWRsTdR2ppHFtSa+k6ZZM1WHvSdcomwyxySceayO4OWTY88TdirygzUkWf18eL2//RQiutYcwYE/Q4tagDOUQ8uo6uUzbRZ3qMJV2nbCLi0XU8tSbrolNXzu6OfOyylgEN4NOkaO5acw/j9ozr0ET37h5imehIZimPL91rAfSZHsOQBfuISS7E7vaTETeX0MmrOoQInbwK+dhlNKWsahni0zPSuGvNPW1M1BrI1NrOwt0WkCn2ijJSS+MYt2ccuQk3oxd36RCi8URPY+HLT1VbgGiSzPsx71laCddMe2Yygf6ZOtuScXvG0XfJn/n8YL+LQnjibyQ34WZ8Xl/bfKSoKL+FVi4EYwKZcu/uIQzaPoExMaPQcrq1ADFX33AI1+6u1OV9HVI6ShU/TYqm75I/dwjTHtDEQ2MZt2ccg7ZPaGGScIDWEBlxc42UoSMQ00StYdoDCgcbtH0Cbx+8p40ZTIBwiFM7RmB3+y+exZvT2YRpDdR6ZoVrw1xRWwN44m/Euf06A6Ki7NLrmnDNmH7TEdSg7RP4/GA/yLK1GdwEKNzSk1M7RlDlqPl1JefOlG2MXTGmXaAxMaMsB/XE34h4tH+7ANlrB7T2iV8OAlDlqOH9mPcsIBPKlF3R16Ad7GwlxoVberYAKCrKv1ghfmkg5sPldLIzZVsLqLErxpC9doAlp3aMICNurlGyVpRdSAu/HqS1Q58rd1JUlI87P1UtKsrHXlGG3e1HCOoov+x2wiX3RxT+o49L1IgutXxVUCfDIxNfLraQDI+M3e3/NdCXbhohqBNfLrIsVzZqmoT6dmXG0SBLTrmJLxd/CVRLECXcDGFaSC1TmHE0yKg4B0P2uxiy38WoOAePHaptAfHYoVqG7HcxcGc5o+IcfFfgsbQUPoYoSa213BbE78oGucTSwpJTbobFFjNgbQHdvi6g8/Z6Om+vZ8h+VxsQE7T/97UMWFvA+Og0UvIryfDIZBQ4CeXvt8a5IAhAY/RImlJWUaHrPHaolhuXFXHN+8e58qNcbomq5P6t3xG973WePLzPgnnsUG0LiP7f1zJwZzk3LisyctfSOFxOJ4lfLzYToQubxu/KpmpWBFWzInguOokrP8ql7/zDRMxLpFfUabasHwlZNnITbmbgznI6b6+3Bu7/fa2lrW5fF9Ar6jQD1hYwLLaYx5fupdi+EiGok748koa4qa010xKkKWUV2UM7kd6vB7tH9yfpnUFkLzQiZOGWnmgHO9N4oie9ok5bA4YPbkqvqNNc8/5xIuYl8tSaLOLLRXambENXF+PxNJD0ziAanVHhYaEliH1lJD/1iqD0qSsIzu2M/N550TZ3QjvYmS3rR1qDtwdhgpgwnabGMj46zRjQsxJdXYw7P1X1pY0GuaRjkMKxPah5qxuV8y6nct7l1LzVDfdyo6miHexM+ou9mblwKfdv/Y77t37HNe8fbwMQDhIxL5FOU2PZklqLJjUYdU7wWxBuN+ricBAF0KQG6pcNovZpw0fCQao/MEBcu7tSOLYHjnu7EZzbmeDczqyfNokrP8ptMXi4XDnzAJ0n72TIgn1oUoMB4VlpgIjj24I0payi9KkrqHj+Ssth2wM5c38f8p68D2nbHKRtc3h86d42A/eZHsOVMw9Y0nXKJmxDvyS1NA70z8Gz0qh5hNvbzpr6ZYMofzyiBUwLkOVdjfR/eVcao0dSl/d1aHx0GhHzEi0TXDnzAJ2mxtJpaixdp2yypM/0GLrcs5D3Y94ztNDsK7qjuxmzDBBz2rYGqZoVQc1b3dr4yfppk+g8eWeLd91aAxGPrqPbyKV0G7mUiEfXMWdz+nmQ0Jsgn1AbT/SkMXrkeZC6vK9DpU9d0S5I5bzLqf6gq6UV7WBn5q9+zDJBuEQ8us4SE6LLPQvpcs9CjmSW4ndlo1XPNBxWLiE34WbSX+wNapEBEsrfT/njERSO7WGBmDA1b3Wj9KkrSO/Xg1WjBjJl/CT+8sQ8a0BT/eGDhwN0uWchXe94ia07YkE+oSLc3gxyQt2yfiSrRg0E+YRqgRSO7UHh2B4UT7ragqmcdznFk67mp14ROO7txpTxk7AN/bLFgN1GLsU29EvrejiACdG59xQjKgu3GzVP9UwIvcmCVwYb102NmBHVBDFNVDUrgjP39yF98E0E5xox5Dcj5lsDhwOYQObg4dK59xR2RV8D4njEo/0NIEd3dkVfgy9t9HkfMTWSO6pXG63kjupF8aSrqXj+SoJzO1M573KmjJ/Eb0bM5y9PzGPBK4Mp3GKUEFvWj+Q3I+a3AOjcewp/eWKesUQ0T1mz2att7oSU9+F5EE2SqXvpSbKHdrIGNmHCoapmRVgh33LezZ3QNncyloGDnVnwyuA2IFvWj0Q+dplREzu6Wy0r9/KubVvg9pWRpPfrwZn7+1haMSHCxdSM/J4RWWufjiC9Xw/m9PgtN9w0uo1JbrhpNI0njAXTrAIbT/TEvb4LjdEj2641vqQjpPfrQfrgm1qYKHxKlz51BbmjerFj4G2WtAYwtWDKglcGG2ZoXrldu43AWDUrAmnbnLaRVZMayHvyPn7qZThoa38pfeoKap+OIDi3M6tGDeSGm0a3GTT82g03jeaGm0bj3H4d8rHLrN0I93LDpDsG3kb68si2a425hfZTrwjSB9/UBiZcM+YM6ghoyvhJpL/Ym+yFhknc67tYQVF+z3gjc3r8Fuf32zpOFTMeHXpRGDNfMYF2j+7PqlEDWTVqIOkv9rZ8SNvcCff6LlTOu9yK1Okv9mZOj9+S8ehQNKmBDhs17vxU9adeES1gwoHKH49oFyhcwhfKynmXWzOu4vkryR7aieyhnQjl7+84QzNNJGzbxN7uV1gw7WmntYZaLw2mmNdrn44ge2gnztzfx9od7zBnDa9t0pdHtgsTDhRustaaCndwEyLj0aG481PVS9r3FSUJj6eBrConMZHvnodpntrh2gkHCgcLl/TBN7G3+xXGLMlIo0LXjU7ixeoaUZIQ3C7OlTtJya8kJvJddgy8DctvWgGFaylcHPd2Y2/3K5jT47esGjWQrTtiyapy4nI6jUrvUmpfUytFRfmkZ6SxdUcs66dNYsfA2ywNtQBrJeb/dgy8jZjId/kx4YgF4fP6Ln1L3uyhhWvnSGYpOw6lEBP5LuunTWLDAw+x4YGHrAi74YGHWD9tEuunTSIm8l227ohtAyBK0i8/pNDagTVJxuf1YXf7OVfuJKvKMF16RhrpGWkcySwlJb+SrCqn1awRgjqaJP9nO0b/Zxo1v+ahS0ZqKJ9QCX5rJMyhN42aRj6h/udB5BKjiAp+i64uNrJ2M0Vs3rUiy4aU92G42X49iCYZDZjUMoX4ctFIcILfGgVU6E0LwEyCxKP98aWNxpc2GvFof+RjlyHlfdjxWnOxh93tJya5kIWHnDx2qJbnopP4NCmaYvtKC0LL6WYkQps70RA3laaUVbjzU1V7RRn2ijK8BbkWUJsM7VIAog7k8MyuPKtD1AJA/9zQQpYN9/oubFk/kpkLl7J4a0KbtrdZa/vSRrfMWS8GcSSzlGd25TH5VIjptTpR9T5SS+OMsrHZD3RHd7SDnTm1YwSzY2KsTtL46DSei07iSGZpm/tKeR8a5gnf0+vI8zfE5zAstpjptTrvifBJeeZ5LTQDkGXDtbsr0fte59mjDmaWaUyv1ZlZpvH3XJlRcQ6Grj5OTHJhy/t7VhrpwMVAog7kMCrOwcs+nZWaccak2L7S0oLpC6d2jGDJiUyWN8E6FVZqsLwJ5ruwYO5O9jFoUSIb4nPOT+/gtxf3kZjkQobFFreAaHRGGZoQbm+hhWd25fHsUQevHilgbo7bAmoNM2S/i6Grj3Mks9Tolcgn1Hb39MzHuXInw9edZrJd4z3xPISuLrYgCrf0ZOuOWKLzVFLLFDIKmlfr5EJmHMxhfoWvDczkUyELxl5RduFUUZNkIvdm8+BpkZd9eocQPyYc6XDnocpRQ+TebObmuFmptdTK5FMhBqwt4K1vMi4cWTMKnIyKczDZrvFJeWaHEBdrbVc5aphxMIflTR1rJaPA2TFI1IEc7k72tZwdYRCLtyZc6h4MMcmF7WrlwRSRAWsLiNyb3T6Iz+vjmV15jIpztIHwxN/I7JgY4svFS47CHk9DG62Y5hm4s5zx0Wntb0CnlikMiy3m06ToFpFSO9iZnSnbeGZXHkcyS8kocF6SHMksZc7m9AuaJyW/si3IltRaZsfEGNM09KZVs2bEzWV5EyzLlXn1SEG7MuNgTruy5JS73dlzd7IvPMi1BIlJLmRnyjbLJFawar7ZHi5NdrSS9jRyd7KPXlGnzQDXyjSlcYY2mk1SuKUnS05kslI7f9M9/HKgdaoh74nn/cR02NV7M9t2A9A/t/qf2uZOvB/zHvNdxk3Mm0bV+36VzK8wxHTWVutPmEbkE6q1hjQ3/yefCvGeeB7k1SPGlLsUeeubDOtnezJnczpvfZPBuXJnGEjzAqSri9FyulG4pSf3b/3OCvErNQNmxsEczpU70ST5kuWXJc9yiZXemQ3du5N9TK/VedmnW1qZm+M+v3r+gpTS42nA42nA5XRa4vE0hFd8zSDBb63cInvtAAYtSuTuZB+T7ZoFYy7tz+zK6+igQZtHRoGTyL3ZLab4M7vyGB+dxpAF+1i8NaEliLmWyNndsa+MZPi60/T/vpaJhTKT7ZqllZWaoZW3vsnA42m4IMS5cifPRScxN8fNeyK87NOZXqszsdDITa55/3i4dgVb0OPUTG2IR/vjzk9Vt6Qau5R3J/uYWCi3MJEJM2dzOkcyS80Q3WKrPia50IIIX2cmnwrxYIpIr6jTPBed1Mo0apFgpv0NcVMR3C5ESWLO5nS6fV3Ag6fFdmHmV/iYcTCHyL3ZRB3IsSRybzbP7MpjfoWvXYj+39cyZME+c7aEgTQ36smy0RA31dostrv9DF193IIJ9xcTxgSam+O2xAQwg9fMMo2JhTIPnjYgBi1KbC+RPq8REyR8iT9X7rRgWptpvssYLBwqHGB6rc7fc2ULYsh+F4MWJbLjUErH09c8ytcaxNTMCxtyGLC2oIUDT6/VO5TJdkMLJsTAneUMWpTYNotvE0eaj3rKxy6zun2t69mdKdt4fOley4lN35ls11pIOIC51D8XnWQu9xcGUQCteibyscuM5n31TKNqD5fm1H9DfA7PRScxdPVxhsUWMyy22Dq4MGS/i2GxxQxfd9oC2HEopb1WVcdtCU2Sqcv7OmTWpGbRLOV9SCh/P0GPUwvPvDIKnMQkFxK5N5s5m9N5LjqJ56KTeOubDFbvzSQlv7LN1P5FxzZ8Xp918v8SWk5WsWStLbr0a5oLHRdY/+GjPP8vtq7+0yCiJOHz+hDcLlxOJ2bzxeV0Irhdlk/9x0B8Xh9VjhoEt6s5rZTaFU1qQHC7qHLU/PpZ05EGqhw1uJxO0CVESSIlv5KoAznM2ZxufTJgzuZ0og7kkJJfaR1mcjmdVDlqflkc6ahSs1eUWdMzJrmQQYsSrYMJNy4raiHmYQWzD2IC2SvKLpa/dAzi8/qsc6cZBU6GLNjHlTMPcEtUJVMSdd45qRGdp7KxDOvDPu+c1JhxNMgtUZVcOfMAQxbss0K7vaLsQqbq+GCtCbEhPodOU2O58qNcZhwNsrMK4t0Xlp1VMONokCs/yqXT1FgrE7sATPvbJK0hblxWxDsnNWugvc7zcqFry3JlbomqbANzSdskpk9kFDjpOmWTpQnzne6sMgbbWWWYY8kpN0tOuYnOU1v8z9TcOyc1blxWRNcpmwwz6dLFjxr7vD5rY+eO13YSMS+Rh/co1iAby4wBluXKLDnl5rsCD1lVxk7FdwUelpxysyxXbvHcjWUwYb9CxLxE7nhtp7X10spELUHMMiHqQA6dJ+9k8KYaJh1u6ZRLTrnZklrb+hS3lURtSa1lySm39fyNZTAlUWfwpho6T95p1rqtS5LzICapJsmWNkbEBpiSqLMs1/gY3DsntfAuT4tDlkrYtci92bxzUmNjmaG9KYk6I2IDbbTStsBqjhma1EBKfiVdp2xiwNoCHt6jMOmwxjsnNev46KWUkaIksfCQk2W5Mu+c1Jh0WGPCfoUBawvoOmWT1d4Miy3nQczIuXpvJp2mxjJ4Uw0T9hsg09KM6fhcdBIxyYWXJM9FJzHjaJBpaTDpsAEzeFMNnabGGhVec+RtA1LlqAFd4vGley0Q8wZTEnWmpWGdWX3sUC3PHnW0K+b/n0qoZ1oaTEszfCQc5PGle0GXwv0k7PxI87S9EMjMMo35rvMdILPDbErrzlA4iOmw4SBh0/iXgUxLg8mnQvw9V2Zmmdau/D1XtpoxpiYe3qPw8B6FW6IqreOCvwpkWhqMinMwaFEi46PTfrFMXG38HLr6OHe8ttPykXZNYzrr4q0JdJoay4C1BS2cdfCmGuZsTrd6Hv/T5ozZJ7no9L1xWZE1fU0bD193unXx3GESFZNcyIb4nDazaUN8Dh6PkTy1O307CmgT9itM2K9YWnkuOumi26wTV6dZR43NXOXKj3LpPHknEY+us0DaDWiWnwCr92bSdcomBm+q4eE9ShsThTXh2jRn5mxOZ/CmmjYzZkRsgE5TY40Q33bhu/iiF66VcJjh604TuTfbUnnk3myGrzttQZgzZtJhzQrvfabHWGNccNELnz2tfSUcJjxADVhbwIC1BdYsMyOp+fyH9yhWGnAks/TS0gDTV4qK8q2NxU5TY7klqrIFTDhQ6+gZ/hwzdoSbpKgo/9LPj5hnR8yUwEwVw810MRkRG7BSRXPpLyrKv/RUsT2YI5mlLZLnEbEBK1q2lhGxASt5vuO1nZY5ioryL5TJX7icENwuioryjV1rr4+oAzkMWbDvouXEkAX7iDqQg8/rQ5MaLgZxaQWWJslWSWkWWBkFzl9UYP2PvgjFPNrj8/osM/2YcIQfE46QnpFmfL7K7SLocWpBj1Mz6+D0jLQWzzPb3b/6aI8SVnCbvXTTVOZxno6kqCjfKlPNUH4pIP9XPGz/N319UFnrf2iKLGi6LmggqCBoIOi6JuiqIqCrgqIrgqyrgoYu6JpiiK4LKgigCpquCCEdQdVVAU0VdP2iMGW29tplmtbcQNQ1QEXXNDQdQGsWHZBbvdQsKkTQfaiaBJrc/PyLPpQ2zqqbL9U10GV0TUbTZUCyQAoaJPaVinx5RmbVKZnVWRpf56r8WKlQFww2Q4bf8VdMXwsEtfkdGb97xSAb8yRG7df4zYYQ3deEsK2WsK1UsK1U6LIqxJWfKQzcEODVw0GS7KbG1F8Pout6C7WuL5Dpv1PBtlLEFgWXfyHTY61Ery91rvkiwLWfB7h6jcxV/5LoskLF9gl0+tjLI7FesuuxzKnrHeqneQdL143Bjacj6wqg4ZFUph8JYvusCdsXIldvhGvXi/T+SuS6dQrXrZO4fp3Ib76UuH5NiD6fi1z/mcgNnwa5epWMbbHG1StEvsoSjbeoq2i60h6MYNN1XTAhNF1vdlBoVFSG7/Nh+1Ti2o1Brl8v03uDyDVfN3DDVz5u+FKh15cKvdbp9FoHvT5X6PW5wjVr4LrPda6NkugTJdL1EwXbIpkVx5sdGaXZ8S9gGgNIJ6ipPHgghO3TED23h+ixTafXZpmb1ofos0ml+9dw1VcaV3wapMvKIF1WSVz+qULPzxV6faZw9Wc613yq0Xt1iN9Ehei+WMG2QObz03JHDtxsGk07P2XRmZ/hx7ZG5rqtMjdubqTHFonrNov8doPMZRvA9pmPqz8X+MNWhb/tkrg/VuGWaJXLPmmk85Imen6m0+sz6BMlcsNqP9etVujysU63jwIcrwy1N6UFm6Zrgma4KKBxrE7lyq999PnaT58dcMNWjV5bFa7d6sP2lcj/+szP6/FNHK2SqQtpSKqIKItUN2psyJH52yYXtkV+uq9UuP5fMj1XqVy9WuWGFSE6LQgxbHMQv6kVXW92B12wKZouSEjGNNMVJvwgYdugcGOsym+2q/TZqnD9dh3bVz5u3h4guVJtnpJa808zkJlBMMS7SQG6vB/gimUKvVdK9Fmu0nu5zLXLZGzvaWzLDhggmoysqwYIKoKqG+rKqVO5douP62JUfvutxg2xCn1iZTpv0rgpRuF0XQAIgRJElSUURUWWZWRZRpFlgrIKeIEg7yaC7X2FXkslei+XDVkmY1sQ4pFNDaA3hwcdNF0XbGjNZwNQWXZaxrZV5XexMjftFLnpW4ne34rYNvjZUywBQUJqEEkMoEk6oqIgySqipCCKEt6Qis8fRNEaAB+TtijYInV6Lwtx7VKRPstkIj5S6PGBRGFtwFCgApquCDYFTQANXZeZkiARsVPnlu9kfhcr0/cbiYivA4w94DM0oet4VQVJUQiJGiFRIiTKBEMSAX+QhoBIvU/C1SQCfpIKGrl8kZerFitcu0Tkuk9ErlsiYXtDYuMpYyobE0gVbIouC6DiDsgMiwtx406Z/rs0+u6WGPCNSI8tIZbnSoCCEvITkBRkWSMUkAgEJbz+EE2+IA3eAPUNjTR6fNTWSni9PuoFN/d8KtBpkcg1n3jp82GQ3h/6sc33seAHb/P6pYOmCTY0VQCNEkHhrgMhfrdL5k/fafT/XqT/boU+sRI/2r0AhESFYFDCF1TwBSWa/CE8TQHcjQFcDX6cdQGq63w43PWU1AoEmup4emMjtvl+enzop/d7Aa57N4Btvo/Z37jCHBzBpuqaAHDOHWDo/iD99in8+XuZO/er/H6fxsB/h0irDgGqoYGAhOAL0eALUd/oo87TRK2nCUddI3anQKXTTUl1DUVVNXga6nh2mwvb6066L3Bz3btOekU2YXtd5MVNDmuVVtEFm6brAmiUu4OMPODnjv0idx+UGHpQ4q6DEnf928+h0iCg0egN0OgXqW8MUCd4cXm81LgbqHIJlDs9lFd5KK90U1hWQ3GlgLOqlrs/rsQ2q45rFjq57q0yukc6sL3iYc62akBDR0fRNcGmq5oAQYSAyuQEibsPhnjgkMYD8T4ePOTnv/ZrfJrtBTWE4A3ibvRTJ3hx1jdRXddApbOeMoebEruL3Ao3p8vqOVVSR1JuDZkFtbywvgDb0zl0eqmanm+Wct2bFdhmlvP2Po/hH6qIrmiCTdNUAVVElTVeyfTz10My435UGHNE5JGfJIYf1ZiV4kFo8uILBKirD+LwBHC43Dhq6ymurqfAUU9ORS05RSU0NHmQVRW/JCMqOho6354U6DEri04z8+nxWim2fxSx8ZgLEAlJCqoiCzZZUwVZVECDjUVNDD8s8sRRlSmJOs8mwbPHZJ466iO2yI8aDNJU56a8tpGqaicOZx2FVfWcLa8lq7CMBn8IHfAGZQKSik/SQAoBOjEZtdiezqTTS/l0fzmPrFIBNB9CUCcoSYJN0TTBKymgS5TXBXn8pwCTj8lMT1WZmarx+nGR2Rk680+GOFleh9/bgMtZR3V1HYWVLvJKajiTV0pVjRsV8IVEgrLaLApeERSCAAx5/xS2+48zZvlZAmKIQFMTHq+PppAi2DRdFQIyyKIfRImoMz6ePO7lpUyJl08r/PN0iMjTEh9kS6zNEUgp92GvaaDAXstZh4DLG0JoChAMyviDMn5Jxi/K+EISIVnFr0h4JWPZ33a8mNteSCI6vhpZbMDhaqChyYfHHxRsmhYURBECoRDoMvkukVfTFN7IlHk7W+aDXIlVOSHW5ob4qhi2F4v8WNLIiSov5wLgkVVERSUYMqa2LyTjF1UCkkpQ1vGLImJAxCsai2SdKFJQ6aG0ooqK+gBuVxOCTxBsuq4IkqQSFCVCkgyqzg8lXt5J9/H+WViVJ7G+KMSOEoVdJSp77DJxdRrH3Rq5goLDJyMERRqCIt6QbPiHqBAQFSRJJSCrhGSZJklDUs/nIefsNRRXe3DWefE0NjUf21BURFEiGDRWVH9I5Nu8Rt7Pk/lXocbWIpFvKzT2VSr8YJdIcEqk1Svke2TsPhV3SMYTEmkISngDCr6QTFBSCUkqQUnFL2kEJUNLflFF1aGuyUepow6HuxG34DdyVkVRkCQFUVLxBWR0ScEfFPmuuIG1hTIxpSr/rpA46FBIqJHJdGmcqVPJa1Co9MrUBiTcQQlPQKYhoNAUUvCJCn5JJSApBCTZEr8oEVJU/IpKiaOOmnov9Q1+QyOqqiErGqKiIYk6/mAATQ4QalRItPvZU+EnvkrmxxqJRJdIVp1KTr1GQaNChVei2idTE9BwBRTqAzKeoEyjKNMkKvglhaCkNAMZogAeX4DS6npcDQE8jYHmM0aajqLqyLJOSNbwSTJev0woEKCxyU9OdZCEkgAJ1UGSBYWsBo3cRihq0qj0KVT5ZBwBjdqQRn1IRhBVGiWVRlklqOiIikZQ1hAV4ytjJE2n0ummqt6LU/AjNAYEm64jaBqoqo6iaEiKhiirBESVhkAQr9eH0ChSUu3nVGkdGY4mUmt8ZLoC5DWoFDUplHpVKnw6VT6ZWn+IuqCEJ6TQEFINzUgSflXFJ8nUe304XALVdQ3UNwaob/TT5A0ZILoO4TCyrBKSZHxBGcEfxNPgpdETwO32U+ZoIKesnrPlHrLtbn6urCfPXk+B3U2R3cO5qgbOVTVQUilwrkKgtEqguLKe4sp6yhwNlNg9VLkEhKYgjd4QTX6RYFA+X2Dpuo6maaiqiqqqKIqGKKn4QwrekERjIIC70YenMUBjk0S9EKK23our3ovb48Xj8SI0BfD4ROq9IdyNQeoa/Lg8AZxuPzV1PuobRASfguAN0egP4Q1KBEMykqwKNkAxMnpDNM1oSxhQGrKiI6oqTapIkyTiDYUIiDLBkEwoICOGjHghKxqKqqCoEooqEVJFgkqIkBIiKIsEpBB+MYA/FMAXkgiICiHRmK2KoilWo6bZRIKu61bjRdd1QdEQVBVBkzRBlVRBFhVBVTRBUXRBknVB1hAUECQQNF0XUHVB13RB0XRBVDRBUjRBUTVBUlRBlBRBlGQhJGuCJOuCouiCpuqCqqpl/7Eemqor5HnS2Ja/hPezpvCP1PuYlfo3vvo5EnfA0baH9qs+CKZpBIIh7DUuyuw1lNprqHDU4mnwoqoamq5xyn2YVTkv8cKJO3n+TH+eTB7Ao/H9eSr+TnbmrfyfgdiddZzKKaK0yklhuYN6oWVfvabay+6Tu3gzaSJPpPZm9E9XMmnvH1n60wKSanZypuEg35WuZlrCMLb9vPSXgzicdWTkFLX7vya5Dq/spk62s8v1AW+cu53ns29kSd6z/Fi9mZ/L8tpqVFfZeHYxBe7MSwdJy85v8Xd1oJwDFRtZlTeTD88+wcKsMSzMGsv8rL8wNbMnc7LuJN6xg6AcsF6TW1xBkzfQct9P8pDrSkfT1QuDKKrKz8UV1t+V3kKi89/m1YyhvHlyMPOz/ouFZ4fwYe59fJAzjLfO3s66wuep8p7jbF0iUTkzOe76/rzZ6jxUVteGtch06gL2C4PIikJFtcv6e3/ZeuamDOHNU//NivwxfFY8jnXlE/iyYiKflz/Eh4WD2Gv/CL/YQIJjI2+dvJvXTt7FtJS+LPt5OvVBY383KEoUlFaGzSz5wqb5ubC0WSsyG3PfZUbKnXzw8wOsKX6EdWUT+NI+nq8cY1nrGMnikjuJd0Xhld1sr3iTt37+IyuLHmZN0WMszxnPzLSBvJnxMMWNPxv7vUITLrdw8VlzMswnNud+xD+O3cGy3LF8ce5R1pZN4IuKsXzlGM0X1SP4uPJ2jgpraJAcfFb+CJHnbuOz8pF8UT6OL0om8nnRJFblPcrLaXfxxolROHzGd2idq7xIHBEavTQFQwAcLNvMP5Lu5JOcsawpmsRnJROIKnuYtVWjWVP9Vz6q7McRz0pUTSa2Zh6LSgeytOJPfGa/j3UVY1lTMoFPz01kdcEjLM95hNmp/8UHmU+j6MYnlrJyz3UMknHW0IbDW8rLyfexIGs4nxU8zqqi8Xx07gGiKkfyheN+ltnvJEFYGdYOFWlUqjniWcGK8iFElQ1jTek4Pi2awOqCR1iZ9wgfnx3Hs4l9+aHc+BqH2voGRFFqC+JpaEKSjOR2Y84iZqX8majcx1ieN57Xc+/hvXPD+aziAZaX30VGY0yH0/1s00E+KR7KquL7+ezceFbnT2BFzkSW5Uzg7VP38UbKQ3hCdc1aKWoLktHsG06/nbnJ9/H+6VGsyJnIC9l38kreMNaUPsKSkkHsdy26aABMcK3lw4L/5l9FY1mdP56lOeP55Ox4Psh+mOeT7+BAyUZj17O8qiWIKMkUlNoBOFQaw4zkQSw+M5bZp+7in7mPsKnkFVade4DPSsfTJNVeFCSk+lhbPIVl+Q+wMnccS8+OY/GZsXxwZjTTj9/OkqwXACi3O/H5A+dBKhy1lFQac33t2bf5R/KdvJnxFxadnkSyYzuf5j3BssIR/Kt4DBvLp/NF2dOsqXiSNRVPsKbyCeNnxZN8XjaFz4ufJrr4Bf5V8Agr8h5iWc5YPs4ey4enR/P+6YeYnfZn3kh9CAUfqgz2Gtd5kLOFpZTYjUMHH516jmlJA3jjxHCO2XexteBtFpwZyqqC0awo+huLCv7Eu4W38V7x73mvtD/vl/Xl/bJ+vFfye94tuo2F+X/g3dw/szT/b6zIHcMnZ0fz0ZmHWXT6ISKzRvJq5mBeSh5MSeNZyzyyrBggWTlFlNsNssiMKYz9oQe7i/9FmmM/r6bezZKfx7Is5yGW5f+NFYUjWHXuflaXDmN12V+JKhtGVNkwVpX9lZXFw1lRNILl+Q/ySc6DfHRmFIuyRhF5ciRvZ/6NNzPvZ3baIJ5N+AM/1xsfXcg9V47XH2wLMidpFE/9eAcVQg7Lsp7j9fShfHTmIT4+M4rIrKG8ljGAeSf78eaZfszP7sc/z/bln9n9mH+mH29m9eO1jP7MPfF7ZibfxvSE3zP1UD+eiruVxw/cxIT9fRj+764Mje3M6bqjAOQVl+MPhgyQvHPllFQapnkhfgRf5y7haNV3PJvwe945+QDvnnyAf2bcQ0zR22S7fySzbj+Z7n2cdO/jZP1eTtbvI9O9j8y6fWS49pHm3Edq9T6OV+0luXIPRyt2k1C+i/jybzhYupUfSrfjV40wX1zhQNN0A8RR66bEbjjr5p+Xc9IRz9snJvJ88h94O/N+3s64j1dS7mJLXuT/v0e/vT6qa93nnVXXdXLOlRtJi6qSWLmL8Yd682rGvcxLG8qbJ4byRuoQXj56L+UNuRcdoDHk5kDJNvaXbuZA2Rb2l21hX9nX7C3byNaCKJKr4pqnbw3+QLBlQDttxn4dPsh4hseP3sjcjP/m5dRBvJYymNdTBjMtvh8rT865KMja0wsZvqsr4/f3ZNyBnjx88CpGxV3BiAM2bt5iY8PPKwz/KKlsG1lDooTgCRJAYPKR/jyb2pcZaQOZdfyPzDn+J145/l/MSfojU364lW05yzuE2F30FU/80JcZSQN5+fifmH38Tmam3MGM1Dt4LOE6pv90DyHFCGLZ+SXtL3pn88rJCR5hbPy1TEq6jqnJv2XGsduZdfwPzD52By8n/5FZSX9g8sGbeDflGU7VHMUTqKMhVM/Z2hMsSZ/JY3G38I/E25l77I/MOv4HZhy/nRkptzE1+Rbu+beNhMrvjLEKSi+cj0T+8AaPZfTi2eQ/8Gj89fz96C3MSB7AjOTfMzPpNmYn3c7MowN4/IdrmXKoPy8l3MtLP/2Fpw7fxiMHr+HFxH7MTrqNmUm/56XkAbyY3I/pyb/jr/tsRJ542hqnOGydaRdkxv6J/DXBxvflX/Fd0Rru2W3jmYTrmZnUnxlJ/ZhxtB+zjg5g1tH+vJBwM1Pjr+fZ+Ot5PuFmZiX2Y9ZR43kvJfXlpeR+PJ90M3/da2Nm4gME5MZ2c5F2QV5OeYA/7rZxrOYgANE/f8S933ViTFxXZiX1ZfbRvsxK7MusxFuZnXgrs8JkZuKtzEi8lZlHf8espL48Gd+Lu3fbeDVpLA1BY+kvc7T7ZTktQUQlyLQjg/nzv20cyo+zrsdX7OKR/bcybLeNp368hpd+uok5ib9lbuKtzfI75ib+jtmJv2PGT7fwfMJveOj7zty/O4JPs+YjKsYUdTc04Wloav/YRusLz/04lAeTIsgsPENewfnc0is1EH32Qx47MICH913F+O//F+O/t/H4wW7877gIHtnfhXHfd2Hs91cyZl9v3k19lgLPaev15TV1NDR6Oz4/0vrC26ceYVhcL45X/GB4d2Eljf7Q+cJI9pHqiGPVqVeZd+wRZicOZ0bCvbyS9DAfpD3PnnNfUuO3ny9NVI2T+eVI8oVPGrUB2ZsfzX1HehJTtMK6FgyJZOYW0+gXf1EIz8wro9LhvKTn2lrugkMoFOS5n/7C0APXYK8tb3GepMrh5HB8Cmknz5JbXEpBSQVlFbVU2N0UlVWRW1RK1s95/JCQzMkzPyPLMpqm4ff7CQQChEIhJElCURQ0TcPsVOm6fn6tCT+oUOkq4bGE27n/qzv4KeMIwVCQQCBAbV0ttXW1VFRWkJ19lrS0DJKSj5F4NInk5OOcPHmK/Px8amtrcbvd1NTU4HQ6cbvdNDU1WTCyLKOqaguYDmvfgNzE4bIYdpWv4UT5EezuMkQl9B877PT/DQC7cLwx8LR3hQAAAABJRU5ErkJggg==) no-repeat;padding-left:40px}\r\n        .browser .browser-firefox{background-position:0 -34px}\r\n        .browser .browser-ie{background-position:0 -68px;margin-left:0px}\r\n        .browser .browser-360{background-position:0 -170px;margin-left: -27px}\r\n    </style>\r\n</head>\r\n<body style=\"margin-top:50px\">\r\n<h1>请升级您的浏览器，以便我们更好的为您提供服务！</h1>\r\n<p>您正在使用 Internet Explorer 的早期版本（IE9以下版本或使用该内核的浏览器）。这意味着在升级浏览器前，您将无法访问此网站。</p>\r\n<hr>\r\n<h2>请注意：微软公司对Windows XP 及 Internet Explorer 早期版本的支持已经结束</h2>\r\n<p>自 2016 年 1 月 12 日起，Microsoft 不再为 IE 11 以下版本提供相应支持和更新。没有关键的浏览器安全更新，您的电脑可能易受有害病毒、间谍软件和其他恶意软件的攻击，它们可以窃取或损害您的业务数据和信息。请参阅 <a href=\"https://www.microsoft.com/zh-cn/WindowsForBusiness/End-of-IE-support\">微软对 Internet Explorer 早期版本的支持将于 2016 年 1 月 12 日结束的说明</a> 。</p>\r\n<hr>\r\n<h2>您可以选择更先进的浏览器</h2>\r\n<p>推荐使用以下浏览器的最新版本。如果您的电脑已有以下浏览器的最新版本则直接使用该浏览器访问即可。</p>\r\n<ul class=\"browser\">\r\n    <li class=\"browser-chrome\"><a href=\"https://www.google.cn/chrome/browser/desktop/index.html?hl=zh-CN&standalone=1\"> 谷歌浏览器<span>Google Chrome</span></a></li>\r\n    <li class=\"browser-firefox\"><a href=\"https://www.mozilla.org/zh-CN/firefox/new/\"> 火狐浏览器<span>Mozilla Firefox</span></a></li>\r\n    <li class=\"browser-ie\"><a href=\"https://windows.microsoft.com/zh-cn/internet-explorer/download-ie\"> IE 11 浏览器<span>Internet Explorer</span></a></li>\r\n    <li class=\"browser-360\"><a href=\"http://se.360.cn/\"> 360安全浏览器<span>360 Chrome</span></a></li>\r\n    <div class=\"clean\"></div>\r\n</ul>\r\n<hr>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/i18n/messages.properties",
    "content": "#错误消息\r\nnot.null=* 必须填写\r\nuser.jcaptcha.error=验证码错误\r\nuser.not.exists=用户不存在/密码错误\r\nuser.password.not.match=用户不存在/密码错误\r\nuser.password.retry.limit.count=密码输入错误{0}次\r\nuser.password.retry.limit.exceed=密码输入错误{0}次，帐户锁定10分钟\r\nuser.password.delete=对不起，您的账号已被删除\r\nuser.blocked=用户已封禁，请联系管理员\r\nrole.blocked=角色已封禁，请联系管理员\r\nlogin.blocked=很遗憾，访问IP已被列入系统黑名单\r\nuser.logout.success=退出成功\r\n\r\nlength.not.valid=长度必须在{min}到{max}个字符之间\r\n\r\nuser.username.not.valid=* 2到20个汉字、字母、数字或下划线组成，且必须以非数字开头\r\nuser.password.not.valid=* 5-50个字符\r\n \r\nuser.email.not.valid=邮箱格式错误\r\nuser.mobile.phone.number.not.valid=手机号格式错误\r\nuser.login.success=登录成功\r\nuser.register.success=注册成功\r\nuser.notfound=请重新登录\r\nuser.forcelogout=管理员强制退出，请重新登录\r\nuser.unknown.error=未知错误，请重新登录\r\n\r\n##文件上传消息\r\nupload.exceed.maxSize=上传的文件大小超出限制的文件大小！<br/>允许的文件最大大小是：{0}MB！\r\nupload.filename.exceed.length=上传的文件名最长{0}个字符\r\n\r\n##权限\r\nno.permission=您没有数据的权限，请联系管理员添加权限 [{0}]\r\nno.create.permission=您没有创建数据的权限，请联系管理员添加权限 [{0}]\r\nno.update.permission=您没有修改数据的权限，请联系管理员添加权限 [{0}]\r\nno.delete.permission=您没有删除数据的权限，请联系管理员添加权限 [{0}]\r\nno.export.permission=您没有导出数据的权限，请联系管理员添加权限 [{0}]\r\nno.view.permission=您没有查看数据的权限，请联系管理员添加权限 [{0}]\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/js/cron.js",
    "content": "$().ready(function () {\r\n    $(\"#unrunBtn\").click(function () {\r\n        var str = $(\"#cron\").val();\r\n        var str_arr = str.split(\" \");\r\n        try {\r\n            $(\"#v_second\").val(str_arr[0])\r\n            $(\"#v_min\").val(str_arr[1])\r\n            $(\"#v_hour\").val(str_arr[2])\r\n            $(\"#v_day\").val(str_arr[3])\r\n            $(\"#v_month\").val(str_arr[4])\r\n            $(\"#v_week\").val(str_arr[5])\r\n            $(\"#v_year\").val(str_arr[6])\r\n        } catch (e) {\r\n        }\r\n    });\r\n    //second\r\n    $(\"#sec_all\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_second\").val(\"*\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#sec_circle\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_sec_circle();\r\n        }\r\n    });\r\n    $(\"#sec_circle1\").change(function () {\r\n        if ($(\"#sec_circle\").prop('checked')) {\r\n            change_sec_circle();\r\n        }\r\n    });\r\n    $(\"#sec_circle2\").change(function () {\r\n        if ($(\"#sec_circle\").prop('checked')) {\r\n            change_sec_circle();\r\n        }\r\n    });\r\n    $(\"#sec_per\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_sec_per();\r\n        }\r\n    });\r\n    $(\"#sec_per1\").change(function () {\r\n        if ($(\"#sec_per\").prop('checked')) {\r\n            change_sec_per();\r\n        }\r\n    });\r\n    $(\"#sec_per2\").change(function () {\r\n        if ($(\"#sec_per\").prop('checked')) {\r\n            change_sec_per();\r\n        }\r\n    });\r\n    $(\"#sec_assign\").click(function () {\r\n        if ($(\"#sec_assign\").prop('checked')) {\r\n            change_sec_assign();\r\n        }\r\n    });\r\n    $(\"input[name='zd_second']\").click(function () {\r\n        if ($(\"#sec_assign\").prop('checked')) {\r\n            change_sec_assign();\r\n        }\r\n    });\r\n\r\n    //minute\r\n    $(\"#min_all\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_min\").val(\"*\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#min_circle\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_min_circle();\r\n        }\r\n    });\r\n    $(\"#min_circle1\").change(function () {\r\n        if ($(\"#min_circle\").prop('checked')) {\r\n            change_min_circle();\r\n        }\r\n    });\r\n    $(\"#min_circle2\").change(function () {\r\n        if ($(\"#min_circle\").prop('checked')) {\r\n            change_min_circle();\r\n        }\r\n    });\r\n    $(\"#min_per\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_min_per();\r\n        }\r\n    });\r\n    $(\"#min_per1\").change(function () {\r\n        if ($(\"#min_per\").prop('checked')) {\r\n            change_min_per();\r\n        }\r\n    });\r\n    $(\"#min_per2\").change(function () {\r\n        if ($(\"#min_per\").prop('checked')) {\r\n            change_min_per();\r\n        }\r\n    });\r\n    $(\"#min_assign\").click(function () {\r\n        if ($(\"#min_assign\").prop('checked')) {\r\n            change_min_assign();\r\n        }\r\n    });\r\n    $(\"input[name='zd_minute']\").click(function () {\r\n        if ($(\"#min_assign\").prop('checked')) {\r\n            change_min_assign();\r\n        }\r\n    });\r\n\r\n    //hour\r\n    $(\"#hour_all\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_hour\").val(\"*\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#hour_circle\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_hour_circle();\r\n        }\r\n    });\r\n    $(\"#hour_circle1\").change(function () {\r\n        if ($(\"#hour_circle\").prop('checked')) {\r\n            change_hour_circle();\r\n        }\r\n    });\r\n    $(\"#hour_circle2\").change(function () {\r\n        if ($(\"#hour_circle\").prop('checked')) {\r\n            change_hour_circle();\r\n        }\r\n    });\r\n    $(\"#hour_per\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_hour_per();\r\n        }\r\n    });\r\n    $(\"#hour_per1\").change(function () {\r\n        if ($(\"#hour_per\").prop('checked')) {\r\n            change_hour_per();\r\n        }\r\n    });\r\n    $(\"#hour_per2\").change(function () {\r\n        if ($(\"#hour_per\").prop('checked')) {\r\n            change_hour_per();\r\n        }\r\n    });\r\n    $(\"#hour_assign\").click(function () {\r\n        if ($(\"#hour_assign\").prop('checked')) {\r\n            change_hour_assign();\r\n        }\r\n    });\r\n    $(\"input[name='zd_hour']\").click(function () {\r\n        if ($(\"#hour_assign\").prop('checked')) {\r\n            change_hour_assign();\r\n        }\r\n    });\r\n\r\n    //day\r\n    $(\"#day_all\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_day\").val(\"*\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#day_no\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_day\").val(\"?\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#day_last\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_day\").val(\"L\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#day_circle\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_day_circle();\r\n        }\r\n    });\r\n    $(\"#day_circle1\").change(function () {\r\n        if ($(\"#day_circle\").prop('checked')) {\r\n            change_day_circle();\r\n        }\r\n    });\r\n    $(\"#day_circle2\").change(function () {\r\n        if ($(\"#day_circle\").prop('checked')) {\r\n            change_day_circle();\r\n        }\r\n    });\r\n    $(\"#day_per\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_day_per();\r\n        }\r\n    });\r\n    $(\"#day_per1\").change(function () {\r\n        if ($(\"#day_per\").prop('checked')) {\r\n            change_day_per();\r\n        }\r\n    });\r\n    $(\"#day_per2\").change(function () {\r\n        if ($(\"#day_per\").prop('checked')) {\r\n            change_day_per();\r\n        }\r\n    });\r\n    $(\"#day_work\").click(function () {\r\n        if ($(\"#day_work\").prop('checked')) {\r\n            change_day_work();\r\n        }\r\n    });\r\n    $(\"#day_work1\").change(function () {\r\n        if ($(\"#day_work\").prop('checked')) {\r\n            change_day_work();\r\n        }\r\n    });\r\n    $(\"#day_assign\").click(function () {\r\n        if ($(\"#day_assign\").prop('checked')) {\r\n            change_day_assign();\r\n        }\r\n    });\r\n    $(\"input[name='zd_day']\").click(function () {\r\n        if ($(\"#day_assign\").prop('checked')) {\r\n            change_day_assign();\r\n        }\r\n    });\r\n\r\n    //month\r\n    $(\"#month_all\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_month\").val(\"*\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#month_no\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_month\").val(\"?\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#month_last\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_month\").val(\"L\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#month_circle\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_month_circle();\r\n        }\r\n    });\r\n    $(\"#month_circle1\").change(function () {\r\n        if ($(\"#month_circle\").prop('checked')) {\r\n            change_month_circle();\r\n        }\r\n    });\r\n    $(\"#month_circle2\").change(function () {\r\n        if ($(\"#month_circle\").prop('checked')) {\r\n            change_month_circle();\r\n        }\r\n    });\r\n    $(\"#month_per\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_month_per();\r\n        }\r\n    });\r\n    $(\"#month_per1\").change(function () {\r\n        if ($(\"#month_per\").prop('checked')) {\r\n            change_month_per();\r\n        }\r\n    });\r\n    $(\"#month_per2\").change(function () {\r\n        if ($(\"#month_per\").prop('checked')) {\r\n            change_month_per();\r\n        }\r\n    });\r\n    $(\"#month_assign\").click(function () {\r\n        if ($(\"#month_assign\").prop('checked')) {\r\n            change_month_assign();\r\n        }\r\n    });\r\n    $(\"input[name='zd_month']\").click(function () {\r\n        if ($(\"#month_assign\").prop('checked')) {\r\n            change_month_assign();\r\n        }\r\n    });\r\n    \r\n    //week\r\n    $(\"#week_all\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_week\").val(\"*\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#week_no\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_week\").val(\"?\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#week_circle\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_week_circle();\r\n        }\r\n    });\r\n    $(\"#week_circle1\").change(function () {\r\n        if ($(\"#week_circle\").prop('checked')) {\r\n            change_week_circle();\r\n        }\r\n    });\r\n    $(\"#week_circle2\").change(function () {\r\n        if ($(\"#week_circle\").prop('checked')) {\r\n            change_week_circle();\r\n        }\r\n    });\r\n    $(\"#week_last\").click(function () {\r\n        if ($(\"#week_last\").prop('checked')) {\r\n            change_week_last();\r\n        }\r\n    });\r\n    $(\"#week_last1\").change(function () {\r\n        if ($(\"#week_last\").prop('checked')) {\r\n            change_week_last();\r\n        }\r\n    });\r\n    $(\"#week_num\").click(function () {\r\n        if ($(\"#week_num\").prop('checked')) {\r\n            change_week_num();\r\n        }\r\n    });\r\n    $(\"#week_num1\").change(function () {\r\n        if ($(\"#week_num\").prop('checked')) {\r\n            change_week_num();\r\n        }\r\n    });\r\n    $(\"#week_num2\").change(function () {\r\n        if ($(\"#week_num\").prop('checked')) {\r\n            change_week_num();\r\n        }\r\n    });\r\n    $(\"#week_assign\").click(function () {\r\n        if ($(\"#week_assign\").prop('checked')) {\r\n            change_week_assign();\r\n        }\r\n    });\r\n    $(\"input[name='zd_week']\").click(function () {\r\n        if ($(\"#week_assign\").prop('checked')) {\r\n            change_week_assign();\r\n        }\r\n    });\r\n    \r\n    //year\r\n    $(\"#year_all\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_year\").val(\"*\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#year_no\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            $(\"#v_year\").val(\"\");\r\n            gen_cron();\r\n        }\r\n    });\r\n    $(\"#year_circle\").click(function () {\r\n        if ($(this).prop('checked')) {\r\n            change_year_circle();\r\n        }\r\n    });\r\n    $(\"#year_circle1\").change(function () {\r\n        if ($(\"#year_circle\").prop('checked')) {\r\n            change_year_circle();\r\n        }\r\n    });\r\n    $(\"#year_circle2\").change(function () {\r\n        if ($(\"#year_circle\").prop('checked')) {\r\n            change_year_circle();\r\n        }\r\n    });\r\n});\r\n\r\nfunction change_sec_assign() {\r\n    var sec_array = new Array();\r\n    $(\"input[name='zd_second']:checked\").each(function () {\r\n        sec_array[sec_array.length] = $(this).val();\r\n    });\r\n    sec_array = sec_array.join(\",\");\r\n    if (sec_array == null || sec_array == '') {\r\n        $(\"#v_second\").val(\"*\");\r\n    } else {\r\n        $(\"#v_second\").val(sec_array);\r\n    }\r\n    gen_cron();\r\n}\r\n\r\nfunction change_sec_circle() {\r\n    var v1 = $(\"#sec_circle1\").val();\r\n    var v2 = $(\"#sec_circle2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#sec_circle1\").val(v1);\r\n    }\r\n    if (v2 < 2) {\r\n        v2 = 2;\r\n        $(\"#sec_circle2\").val(v2);\r\n    }\r\n    if (v2 > 59) {\r\n        v2 = 59;\r\n        $(\"#sec_circle2\").val(v2);\r\n    }\r\n    if (v1 > 59) {\r\n        v1 = 59;\r\n        $(\"#sec_circle1\").val(v1);\r\n    }\r\n    if (v1 >= v2) {\r\n        v1 = v2 - 1;\r\n        $(\"#sec_circle1\").val(v1);\r\n    }\r\n    if (v1 > 60 || v2 > 60) {\r\n        return;\r\n    }\r\n    if (v1 > v2) {\r\n        return;\r\n    }\r\n    $(\"#v_second\").val(v1 + \"-\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction change_sec_per() {\r\n    var v1 = $(\"#sec_per1\").val();\r\n    var v2 = $(\"#sec_per2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 0) {\r\n        v1 = 0;\r\n        $(\"#sec_per1\").val(v1);\r\n    }\r\n    if (v1 > 59) {\r\n        v1 = 59;\r\n        $(\"#sec_per1\").val(v1);\r\n    }\r\n    if (v2 < 1) {\r\n        v2 = 1;\r\n        $(\"#sec_per2\").val(v2);\r\n    }\r\n    if (v2 > 59) {\r\n        v2 = 59;\r\n        $(\"#sec_per2\").val(v2);\r\n    }\r\n    $(\"#v_second\").val(v1 + \"/\" + v2);\r\n    gen_cron()\r\n}\r\n\r\nfunction change_min_assign() {\r\n    var sec_array = new Array();\r\n    $(\"input[name='zd_minute']:checked\").each(function () {\r\n        sec_array[sec_array.length] = $(this).val();\r\n    });\r\n    sec_array = sec_array.join(\",\");\r\n    if (sec_array == null || sec_array == '') {\r\n        $(\"#v_min\").val(\"*\");\r\n    } else {\r\n        $(\"#v_min\").val(sec_array);\r\n    }\r\n    gen_cron();\r\n}\r\n\r\nfunction change_min_circle() {\r\n    var v1 = $(\"#min_circle1\").val();\r\n    var v2 = $(\"#min_circle2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#min_circle1\").val(v1);\r\n    }\r\n    if (v2 < 2) {\r\n        v2 = 2;\r\n        $(\"#min_circle2\").val(v2);\r\n    }\r\n    if (v2 > 59) {\r\n        v2 = 59;\r\n        $(\"#min_circle2\").val(v2);\r\n    }\r\n    if (v1 > 59) {\r\n        v1 = 59;\r\n        $(\"#min_circle1\").val(v1);\r\n    }\r\n    if (v1 >= v2) {\r\n        v1 = v2 - 1;\r\n        $(\"#min_circle1\").val(v1);\r\n    }\r\n    if (v1 > 60 || v2 > 60) {\r\n        return;\r\n    }\r\n    if (v1 > v2) {\r\n        return;\r\n    }\r\n    $(\"#v_min\").val(v1 + \"-\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction change_min_per() {\r\n    var v1 = $(\"#min_per1\").val();\r\n    var v2 = $(\"#min_per2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 0) {\r\n        v1 = 0;\r\n        $(\"#min_per1\").val(v1);\r\n    }\r\n    if (v1 > 59) {\r\n        v1 = 59;\r\n        $(\"#min_per1\").val(v1);\r\n    }\r\n    if (v2 < 1) {\r\n        v2 = 1;\r\n        $(\"#min_per2\").val(v2);\r\n    }\r\n    if (v2 > 59) {\r\n        v2 = 59;\r\n        $(\"#min_per2\").val(v2);\r\n    }\r\n\r\n    $(\"#v_min\").val(v1 + \"/\" + v2);\r\n    gen_cron()\r\n}\r\n\r\nfunction change_hour_assign() {\r\n    var sec_array = new Array();\r\n    $(\"input[name='zd_hour']:checked\").each(function () {\r\n        sec_array[sec_array.length] = $(this).val();\r\n    });\r\n    sec_array = sec_array.join(\",\");\r\n    if (sec_array == null || sec_array == '') {\r\n        $(\"#v_hour\").val(\"*\");\r\n    } else {\r\n        $(\"#v_hour\").val(sec_array);\r\n    }\r\n    gen_cron();\r\n}\r\n\r\nfunction change_hour_circle() {\r\n    var v1 = $(\"#hour_circle1\").val();\r\n    var v2 = $(\"#hour_circle2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#hour_circle1\").val(v1);\r\n    }\r\n    if (v2 < 2) {\r\n        v2 = 2;\r\n        $(\"#hour_circle2\").val(v2);\r\n    }\r\n    if (v2 > 23) {\r\n        v2 = 23;\r\n        $(\"#hour_circle2\").val(v2);\r\n    }\r\n    if (v1 > 23) {\r\n        v1 = 23;\r\n        $(\"#hour_circle1\").val(v1);\r\n    }\r\n    if (v1 >= v2) {\r\n        v1 = v2 - 1;\r\n        $(\"#hour_circle1\").val(v1);\r\n    }\r\n    if (v1 > 23 || v2 > 23) {\r\n        return;\r\n    }\r\n    if (v1 > v2) {\r\n        return;\r\n    }\r\n    $(\"#v_hour\").val(v1 + \"-\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction change_hour_per() {\r\n    var v1 = $(\"#hour_per1\").val();\r\n    var v2 = $(\"#hour_per2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 0) {\r\n        v1 = 0;\r\n        $(\"#hour_per1\").val(v1);\r\n    }\r\n    if (v1 > 23) {\r\n        v1 = 23;\r\n        $(\"#hour_per1\").val(v1);\r\n    }\r\n    if (v2 < 1) {\r\n        v2 = 1;\r\n        $(\"#hour_per2\").val(v2);\r\n    }\r\n    if (v2 > 23) {\r\n        v2 = 23;\r\n        $(\"#hour_per2\").val(v2);\r\n    }\r\n\r\n    $(\"#v_hour\").val(v1 + \"/\" + v2);\r\n    gen_cron()\r\n}\r\n\r\nfunction change_day_assign() {\r\n    var sec_array = new Array();\r\n    $(\"input[name='zd_day']:checked\").each(function () {\r\n        sec_array[sec_array.length] = $(this).val();\r\n    });\r\n    sec_array = sec_array.join(\",\");\r\n    if (sec_array == null || sec_array == '') {\r\n        $(\"#v_day\").val(\"*\");\r\n    } else {\r\n        $(\"#v_day\").val(sec_array);\r\n    }\r\n    gen_cron();\r\n}\r\n\r\nfunction change_day_circle() {\r\n    var v1 = $(\"#day_circle1\").val();\r\n    var v2 = $(\"#day_circle2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#day_circle1\").val(v1);\r\n    }\r\n    if (v2 < 2) {\r\n        v2 = 2;\r\n        $(\"#day_circle2\").val(v2);\r\n    }\r\n    if (v2 > 31) {\r\n        v2 = 31;\r\n        $(\"#day_circle2\").val(v2);\r\n    }\r\n    if (v1 > 31) {\r\n        v1 = 31;\r\n        $(\"#day_circle1\").val(v1);\r\n    }\r\n    if (v1 >= v2) {\r\n        v1 = v2 - 1;\r\n        $(\"#day_circle1\").val(v1);\r\n    }\r\n    if (v1 > 31 || v2 > 31) {\r\n        return;\r\n    }\r\n    if (v1 > v2) {\r\n        return;\r\n    }\r\n    $(\"#v_day\").val(v1 + \"-\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction change_day_per() {\r\n    var v1 = $(\"#day_per1\").val();\r\n    var v2 = $(\"#day_per2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#day_per1\").val(v1);\r\n    }\r\n    if (v1 > 31) {\r\n        v1 = 31;\r\n        $(\"#day_per1\").val(v1);\r\n    }\r\n    if (v2 < 1) {\r\n        v2 = 1;\r\n        $(\"#day_per2\").val(v2);\r\n    }\r\n    if (v2 > 31) {\r\n        v2 = 31;\r\n        $(\"#day_per2\").val(v2);\r\n    }\r\n\r\n    $(\"#v_day\").val(v1 + \"/\" + v2);\r\n    gen_cron()\r\n}\r\n\r\nfunction change_day_work() {\r\n    var v1 = $(\"#day_work1\").val();\r\n\r\n    if (v1 == null || v1 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#day_work1\").val(v1);\r\n    }\r\n    if (v1 > 31) {\r\n        v1 = 31;\r\n        $(\"#day_work1\").val(v1);\r\n    }\r\n    $(\"#v_day\").val(v1 + \"W\");\r\n    gen_cron()\r\n}\r\n\r\nfunction change_month_assign() {\r\n    var sec_array = new Array();\r\n    $(\"input[name='zd_month']:checked\").each(function () {\r\n        sec_array[sec_array.length] = $(this).val();\r\n    });\r\n    sec_array = sec_array.join(\",\");\r\n    if (sec_array == null || sec_array == '') {\r\n        $(\"#v_month\").val(\"*\");\r\n    } else {\r\n        $(\"#v_month\").val(sec_array);\r\n    }\r\n    gen_cron();\r\n}\r\n\r\nfunction change_month_circle() {\r\n    var v1 = $(\"#month_circle1\").val();\r\n    var v2 = $(\"#month_circle2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#month_circle1\").val(v1);\r\n    }\r\n    if (v2 < 2) {\r\n        v2 = 2;\r\n        $(\"#month_circle2\").val(v2);\r\n    }\r\n    if (v2 > 12) {\r\n        v2 = 12;\r\n        $(\"#month_circle2\").val(v2);\r\n    }\r\n    if (v1 > 12) {\r\n        v1 = 12;\r\n        $(\"#month_circle1\").val(v1);\r\n    }\r\n    if (v1 >= v2) {\r\n        v1 = v2 - 1;\r\n        $(\"#month_circle1\").val(v1);\r\n    }\r\n    if (v1 > 12 || v2 > 12) {\r\n        return;\r\n    }\r\n    if (v1 > v2) {\r\n        return;\r\n    }\r\n    $(\"#v_month\").val(v1 + \"-\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction change_month_per() {\r\n    var v1 = $(\"#month_per1\").val();\r\n    var v2 = $(\"#month_per2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#month_per1\").val(v1);\r\n    }\r\n    if (v1 > 12) {\r\n        v1 = 12;\r\n        $(\"#month_per1\").val(v1);\r\n    }\r\n    if (v2 < 1) {\r\n        v2 = 1;\r\n        $(\"#month_per2\").val(v2);\r\n    }\r\n    if (v2 > 12) {\r\n        v2 = 12;\r\n        $(\"#month_per2\").val(v2);\r\n    }\r\n\r\n    $(\"#v_month\").val(v1 + \"/\" + v2);\r\n    gen_cron()\r\n}\r\n\r\nfunction change_week_assign() {\r\n    var sec_array = new Array();\r\n    $(\"input[name='zd_week']:checked\").each(function () {\r\n        sec_array[sec_array.length] = $(this).val();\r\n    });\r\n    sec_array = sec_array.join(\",\");\r\n    if (sec_array == null || sec_array == '') {\r\n        $(\"#v_week\").val(\"*\");\r\n    } else {\r\n        $(\"#v_week\").val(sec_array);\r\n    }\r\n    gen_cron();\r\n}\r\n\r\nfunction change_week_circle() {\r\n    var v1 = $(\"#week_circle1\").val();\r\n    var v2 = $(\"#week_circle2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#week_circle1\").val(v1);\r\n    }\r\n    if (v2 < 2) {\r\n        v2 = 2;\r\n        $(\"#week_circle2\").val(v2);\r\n    }\r\n    if (v2 > 7) {\r\n        v2 = 7;\r\n        $(\"#week_circle2\").val(v2);\r\n    }\r\n    if (v1 > 7) {\r\n        v1 = 7;\r\n        $(\"#week_circle1\").val(v1);\r\n    }\r\n    if (v1 >= v2) {\r\n        v1 = v2 - 1;\r\n        $(\"#week_circle1\").val(v1);\r\n    }\r\n    if (v1 > 7 || v2 > 7) {\r\n        return;\r\n    }\r\n    if (v1 > v2) {\r\n        return;\r\n    }\r\n    $(\"#v_week\").val(v1 + \"-\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction change_week_last() {\r\n    var v1 = $(\"#week_last1\").val();\r\n\r\n    if (v1 == null || v1 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#week_last1\").val(v1);\r\n    }\r\n    if (v1 > 7) {\r\n        v1 = 7;\r\n        $(\"#week_last1\").val(v1);\r\n    }\r\n    $(\"#v_week\").val(v1 + \"L\");\r\n    gen_cron()\r\n}\r\n\r\nfunction change_week_num() {\r\n    var v1 = $(\"#week_num1\").val();\r\n    var v2 = $(\"#week_num2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 1) {\r\n        v1 = 1;\r\n        $(\"#week_num1\").val(v1);\r\n    }\r\n    if (v2 < 1) {\r\n        v2 = 1;\r\n        $(\"#week_num2\").val(v2);\r\n    }\r\n    if (v2 > 7) {\r\n        v2 = 7;\r\n        $(\"#week_num2\").val(v2);\r\n    }\r\n    if (v1 > 4) {\r\n        v1 = 4;\r\n        $(\"#week_num1\").val(v1);\r\n    }\r\n\r\n    $(\"#v_week\").val(v1 + \"#\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction change_year_circle() {\r\n    var v1 = $(\"#year_circle1\").val();\r\n    var v2 = $(\"#year_circle2\").val();\r\n    if (v1 == null || v1 == '' || v2 == null || v2 == '') {\r\n        return;\r\n    }\r\n    if (v1 < 2000) {\r\n        v1 = 2000;\r\n        $(\"#year_circle1\").val(v1);\r\n    }\r\n    if (v2 < 2000) {\r\n        v2 = 2000;\r\n        $(\"#year_circle2\").val(v2);\r\n    }\r\n    if (v2 > 3000) {\r\n        v2 = 3000;\r\n        $(\"#year_circle2\").val(v2);\r\n    }\r\n    if (v1 > 3000) {\r\n        v1 = 3000;\r\n        $(\"#year_circle1\").val(v1);\r\n    }\r\n    if (v1 >= v2) {\r\n        v1 = v2 - 1;\r\n        $(\"#year_circle1\").val(v1);\r\n    }\r\n    if (v1 > 3000 || v2 > 3000) {\r\n        return;\r\n    }\r\n    if (v1 > v2) {\r\n        return;\r\n    }\r\n    $(\"#v_year\").val(v1 + \"-\" + v2);\r\n    gen_cron();\r\n}\r\n\r\nfunction gen_cron() {\r\n    var str = $(\"#v_second\").val() + \" \"\r\n        + $(\"#v_min\").val() + \" \"\r\n        + $(\"#v_hour\").val() + \" \"\r\n        + $(\"#v_day\").val() + \" \"\r\n        + $(\"#v_month\").val() + \" \"\r\n        + $(\"#v_week\").val() + \" \"\r\n        + $(\"#v_year\").val();\r\n    $(\"#cron\").val(str);\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/js/jquery.tmpl.js",
    "content": "/*!\r\n * jQuery Templates Plugin 1.0.0pre\r\n * http://github.com/jquery/jquery-tmpl\r\n * Requires jQuery 1.4.2\r\n *\r\n * Copyright 2011, Software Freedom Conservancy, Inc.\r\n * Dual licensed under the MIT or GPL Version 2 licenses.\r\n * http://jquery.org/license\r\n */\r\n(function( factory ) {\r\n\tif (typeof define === 'function' && define.amd) {\r\n\t\t// Loading from AMD script loader. Register as an anonymous module.\r\n\t\tdefine( ['jquery'], factory );\r\n\t} else {\r\n\t\t// Browser using plain <script> tag\r\n\t\tfactory( jQuery );\r\n\t}\r\n}(function( jQuery ){\r\n\tvar oldManip = jQuery.fn.domManip, tmplItmAtt = \"_tmplitem\", htmlExpr = /^[^<]*(<[\\w\\W]+>)[^>]*$|\\{\\{\\! /,\r\n\t\tnewTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = [];\r\n\r\n\tfunction newTmplItem( options, parentItem, fn, data ) {\r\n\t\t// Returns a template item data structure for a new rendered instance of a template (a 'template item').\r\n\t\t// The content field is a hierarchical array of strings and nested items (to be\r\n\t\t// removed and replaced by nodes field of dom elements, once inserted in DOM).\r\n\t\tvar newItem = {\r\n\t\t\tdata: data || (data === 0 || data === false) ? data : (parentItem ? parentItem.data : {}),\r\n\t\t\t_wrap: parentItem ? parentItem._wrap : null,\r\n\t\t\ttmpl: null,\r\n\t\t\tparent: parentItem || null,\r\n\t\t\tnodes: [],\r\n\t\t\tcalls: tiCalls,\r\n\t\t\tnest: tiNest,\r\n\t\t\twrap: tiWrap,\r\n\t\t\thtml: tiHtml,\r\n\t\t\tupdate: tiUpdate\r\n\t\t};\r\n\t\tif ( options ) {\r\n\t\t\tjQuery.extend( newItem, options, { nodes: [], parent: parentItem });\r\n\t\t}\r\n\t\tif ( fn ) {\r\n\t\t\t// Build the hierarchical content to be used during insertion into DOM\r\n\t\t\tnewItem.tmpl = fn;\r\n\t\t\tnewItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem );\r\n\t\t\tnewItem.key = ++itemKey;\r\n\t\t\t// Keep track of new template item, until it is stored as jQuery Data on DOM element\r\n\t\t\t(stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem;\r\n\t\t}\r\n\t\treturn newItem;\r\n\t}\r\n\r\n\t// Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core).\r\n\tjQuery.each({\r\n\t\tappendTo: \"append\",\r\n\t\tprependTo: \"prepend\",\r\n\t\tinsertBefore: \"before\",\r\n\t\tinsertAfter: \"after\",\r\n\t\treplaceAll: \"replaceWith\"\r\n\t}, function( name, original ) {\r\n\t\tjQuery.fn[ name ] = function( selector ) {\r\n\t\t\tvar ret = [], insert = jQuery( selector ), elems, i, l, tmplItems,\r\n\t\t\t\tparent = this.length === 1 && this[0].parentNode;\r\n\r\n\t\t\tappendToTmplItems = newTmplItems || {};\r\n\t\t\tif ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {\r\n\t\t\t\tinsert[ original ]( this[0] );\r\n\t\t\t\tret = this;\r\n\t\t\t} else {\r\n\t\t\t\tfor ( i = 0, l = insert.length; i < l; i++ ) {\r\n\t\t\t\t\tcloneIndex = i;\r\n\t\t\t\t\telems = (i > 0 ? this.clone(true) : this).get();\r\n\t\t\t\t\tjQuery( insert[i] )[ original ]( elems );\r\n\t\t\t\t\tret = ret.concat( elems );\r\n\t\t\t\t}\r\n\t\t\t\tcloneIndex = 0;\r\n\t\t\t\tret = this.pushStack( ret, name, insert.selector );\r\n\t\t\t}\r\n\t\t\ttmplItems = appendToTmplItems;\r\n\t\t\tappendToTmplItems = null;\r\n\t\t\tjQuery.tmpl.complete( tmplItems );\r\n\t\t\treturn ret;\r\n\t\t};\r\n\t});\r\n\r\n\tjQuery.fn.extend({\r\n\t\t// Use first wrapped element as template markup.\r\n\t\t// Return wrapped set of template items, obtained by rendering template against data.\r\n\t\ttmpl: function( data, options, parentItem ) {\r\n\t\t\treturn jQuery.tmpl( this[0], data, options, parentItem );\r\n\t\t},\r\n\r\n\t\t// Find which rendered template item the first wrapped DOM element belongs to\r\n\t\ttmplItem: function() {\r\n\t\t\treturn jQuery.tmplItem( this[0] );\r\n\t\t},\r\n\r\n\t\t// Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template.\r\n\t\ttemplate: function( name ) {\r\n\t\t\treturn jQuery.template( name, this[0] );\r\n\t\t},\r\n\r\n\t\tdomManip: function( args, table, callback, options ) {\r\n\t\t\tif ( args[0] && jQuery.isArray( args[0] )) {\r\n\t\t\t\tvar dmArgs = jQuery.makeArray( arguments ), elems = args[0], elemsLength = elems.length, i = 0, tmplItem;\r\n\t\t\t\twhile ( i < elemsLength && !(tmplItem = jQuery.data( elems[i++], \"tmplItem\" ))) {}\r\n\t\t\t\tif ( tmplItem && cloneIndex ) {\r\n\t\t\t\t\tdmArgs[2] = function( fragClone ) {\r\n\t\t\t\t\t\t// Handler called by oldManip when rendered template has been inserted into DOM.\r\n\t\t\t\t\t\tjQuery.tmpl.afterManip( this, fragClone, callback );\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t\toldManip.apply( this, dmArgs );\r\n\t\t\t} else {\r\n\t\t\t\toldManip.apply( this, arguments );\r\n\t\t\t}\r\n\t\t\tcloneIndex = 0;\r\n\t\t\tif ( !appendToTmplItems ) {\r\n\t\t\t\tjQuery.tmpl.complete( newTmplItems );\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t}\r\n\t});\r\n\r\n\tjQuery.extend({\r\n\t\t// Return wrapped set of template items, obtained by rendering template against data.\r\n\t\ttmpl: function( tmpl, data, options, parentItem ) {\r\n\t\t\tvar ret, topLevel = !parentItem;\r\n\t\t\tif ( topLevel ) {\r\n\t\t\t\t// This is a top-level tmpl call (not from a nested template using {{tmpl}})\r\n\t\t\t\tparentItem = topTmplItem;\r\n\t\t\t\ttmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl );\r\n\t\t\t\twrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level\r\n\t\t\t} else if ( !tmpl ) {\r\n\t\t\t\t// The template item is already associated with DOM - this is a refresh.\r\n\t\t\t\t// Re-evaluate rendered template for the parentItem\r\n\t\t\t\ttmpl = parentItem.tmpl;\r\n\t\t\t\tnewTmplItems[parentItem.key] = parentItem;\r\n\t\t\t\tparentItem.nodes = [];\r\n\t\t\t\tif ( parentItem.wrapped ) {\r\n\t\t\t\t\tupdateWrapped( parentItem, parentItem.wrapped );\r\n\t\t\t\t}\r\n\t\t\t\t// Rebuild, without creating a new template item\r\n\t\t\t\treturn jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) ));\r\n\t\t\t}\r\n\t\t\tif ( !tmpl ) {\r\n\t\t\t\treturn []; // Could throw...\r\n\t\t\t}\r\n\t\t\tif ( typeof data === \"function\" ) {\r\n\t\t\t\tdata = data.call( parentItem || {} );\r\n\t\t\t}\r\n\t\t\tif ( options && options.wrapped ) {\r\n\t\t\t\tupdateWrapped( options, options.wrapped );\r\n\t\t\t}\r\n\t\t\tret = jQuery.isArray( data ) ?\r\n\t\t\t\tjQuery.map( data, function( dataItem ) {\r\n\t\t\t\t\treturn dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null;\r\n\t\t\t\t}) :\r\n\t\t\t\t[ newTmplItem( options, parentItem, tmpl, data ) ];\r\n\t\t\treturn topLevel ? jQuery( build( parentItem, null, ret ) ) : ret;\r\n\t\t},\r\n\r\n\t\t// Return rendered template item for an element.\r\n\t\ttmplItem: function( elem ) {\r\n\t\t\tvar tmplItem;\r\n\t\t\tif ( elem instanceof jQuery ) {\r\n\t\t\t\telem = elem[0];\r\n\t\t\t}\r\n\t\t\twhile ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, \"tmplItem\" )) && (elem = elem.parentNode) ) {}\r\n\t\t\treturn tmplItem || topTmplItem;\r\n\t\t},\r\n\r\n\t\t// Set:\r\n\t\t// Use $.template( name, tmpl ) to cache a named template,\r\n\t\t// where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc.\r\n\t\t// Use $( \"selector\" ).template( name ) to provide access by name to a script block template declaration.\r\n\r\n\t\t// Get:\r\n\t\t// Use $.template( name ) to access a cached template.\r\n\t\t// Also $( selectorToScriptBlock ).template(), or $.template( null, templateString )\r\n\t\t// will return the compiled template, without adding a name reference.\r\n\t\t// If templateString includes at least one HTML tag, $.template( templateString ) is equivalent\r\n\t\t// to $.template( null, templateString )\r\n\t\ttemplate: function( name, tmpl ) {\r\n\t\t\tif (tmpl) {\r\n\t\t\t\t// Compile template and associate with name\r\n\t\t\t\tif ( typeof tmpl === \"string\" ) {\r\n\t\t\t\t\t// This is an HTML string being passed directly in.\r\n\t\t\t\t\ttmpl = buildTmplFn( tmpl );\r\n\t\t\t\t} else if ( tmpl instanceof jQuery ) {\r\n\t\t\t\t\ttmpl = tmpl[0] || {};\r\n\t\t\t\t}\r\n\t\t\t\tif ( tmpl.nodeType ) {\r\n\t\t\t\t\t// If this is a template block, use cached copy, or generate tmpl function and cache.\r\n\t\t\t\t\ttmpl = jQuery.data( tmpl, \"tmpl\" ) || jQuery.data( tmpl, \"tmpl\", buildTmplFn( tmpl.innerHTML ));\r\n\t\t\t\t\t// Issue: In IE, if the container element is not a script block, the innerHTML will remove quotes from attribute values whenever the value does not include white space.\r\n\t\t\t\t\t// This means that foo=\"${x}\" will not work if the value of x includes white space: foo=\"${x}\" -> foo=value of x.\r\n\t\t\t\t\t// To correct this, include space in tag: foo=\"${ x }\" -> foo=\"value of x\"\r\n\t\t\t\t}\r\n\t\t\t\treturn typeof name === \"string\" ? (jQuery.template[name] = tmpl) : tmpl;\r\n\t\t\t}\r\n\t\t\t// Return named compiled template\r\n\t\t\treturn name ? (typeof name !== \"string\" ? jQuery.template( null, name ):\r\n\t\t\t\t(jQuery.template[name] ||\r\n\t\t\t\t\t// If not in map, and not containing at least on HTML tag, treat as a selector.\r\n\t\t\t\t\t// (If integrated with core, use quickExpr.exec)\r\n\t\t\t\t\tjQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null;\r\n\t\t},\r\n\r\n\t\tencode: function( text ) {\r\n\t\t\t// Do HTML encoding replacing < > & and ' and \" by corresponding entities.\r\n\t\t\treturn (\"\" + text).split(\"<\").join(\"&lt;\").split(\">\").join(\"&gt;\").split('\"').join(\"&#34;\").split(\"'\").join(\"&#39;\");\r\n\t\t}\r\n\t});\r\n\r\n\tjQuery.extend( jQuery.tmpl, {\r\n\t\ttag: {\r\n\t\t\t\"tmpl\": {\r\n\t\t\t\t_default: { $2: \"null\" },\r\n\t\t\t\topen: \"if($notnull_1){__=__.concat($item.nest($1,$2));}\"\r\n\t\t\t\t// tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions)\r\n\t\t\t\t// This means that {{tmpl foo}} treats foo as a template (which IS a function).\r\n\t\t\t\t// Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}.\r\n\t\t\t},\r\n\t\t\t\"wrap\": {\r\n\t\t\t\t_default: { $2: \"null\" },\r\n\t\t\t\topen: \"$item.calls(__,$1,$2);__=[];\",\r\n\t\t\t\tclose: \"call=$item.calls();__=call._.concat($item.wrap(call,__));\"\r\n\t\t\t},\r\n\t\t\t\"each\": {\r\n\t\t\t\t_default: { $2: \"$index, $value\" },\r\n\t\t\t\topen: \"if($notnull_1){$.each($1a,function($2){with(this){\",\r\n\t\t\t\tclose: \"}});}\"\r\n\t\t\t},\r\n\t\t\t\"if\": {\r\n\t\t\t\topen: \"if(($notnull_1) && $1a){\",\r\n\t\t\t\tclose: \"}\"\r\n\t\t\t},\r\n\t\t\t\"else\": {\r\n\t\t\t\t_default: { $1: \"true\" },\r\n\t\t\t\topen: \"}else if(($notnull_1) && $1a){\"\r\n\t\t\t},\r\n\t\t\t\"html\": {\r\n\t\t\t\t// Unecoded expression evaluation.\r\n\t\t\t\topen: \"if($notnull_1){__.push($1a);}\"\r\n\t\t\t},\r\n\t\t\t\"=\": {\r\n\t\t\t\t// Encoded expression evaluation. Abbreviated form is ${}.\r\n\t\t\t\t_default: { $1: \"$data\" },\r\n\t\t\t\topen: \"if($notnull_1){__.push($.encode($1a));}\"\r\n\t\t\t},\r\n\t\t\t\"!\": {\r\n\t\t\t\t// Comment tag. Skipped by parser\r\n\t\t\t\topen: \"\"\r\n\t\t\t}\r\n\t\t},\r\n\r\n\t\t// This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events\r\n\t\tcomplete: function( items ) {\r\n\t\t\tnewTmplItems = {};\r\n\t\t},\r\n\r\n\t\t// Call this from code which overrides domManip, or equivalent\r\n\t\t// Manage cloning/storing template items etc.\r\n\t\tafterManip: function afterManip( elem, fragClone, callback ) {\r\n\t\t\t// Provides cloned fragment ready for fixup prior to and after insertion into DOM\r\n\t\t\tvar content = fragClone.nodeType === 11 ?\r\n\t\t\t\tjQuery.makeArray(fragClone.childNodes) :\r\n\t\t\t\tfragClone.nodeType === 1 ? [fragClone] : [];\r\n\r\n\t\t\t// Return fragment to original caller (e.g. append) for DOM insertion\r\n\t\t\tcallback.call( elem, fragClone );\r\n\r\n\t\t\t// Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data.\r\n\t\t\tstoreTmplItems( content );\r\n\t\t\tcloneIndex++;\r\n\t\t}\r\n\t});\r\n\r\n\t//========================== Private helper functions, used by code above ==========================\r\n\r\n\tfunction build( tmplItem, nested, content ) {\r\n\t\t// Convert hierarchical content into flat string array\r\n\t\t// and finally return array of fragments ready for DOM insertion\r\n\t\tvar frag, ret = content ? jQuery.map( content, function( item ) {\r\n\t\t\treturn (typeof item === \"string\") ?\r\n\t\t\t\t// Insert template item annotations, to be converted to jQuery.data( \"tmplItem\" ) when elems are inserted into DOM.\r\n\t\t\t\t(tmplItem.key ? item.replace( /(<\\w+)(?=[\\s>])(?![^>]*_tmplitem)([^>]*)/g, \"$1 \" + tmplItmAtt + \"=\\\"\" + tmplItem.key + \"\\\" $2\" ) : item) :\r\n\t\t\t\t// This is a child template item. Build nested template.\r\n\t\t\t\tbuild( item, tmplItem, item._ctnt );\r\n\t\t}) :\r\n\t\t// If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}.\r\n\t\ttmplItem;\r\n\t\tif ( nested ) {\r\n\t\t\treturn ret;\r\n\t\t}\r\n\r\n\t\t// top-level template\r\n\t\tret = ret.join(\"\");\r\n\r\n\t\t// Support templates which have initial or final text nodes, or consist only of text\r\n\t\t// Also support HTML entities within the HTML markup.\r\n\t\tret.replace( /^\\s*([^<\\s][^<]*)?(<[\\w\\W]+>)([^>]*[^>\\s])?\\s*$/, function( all, before, middle, after) {\r\n\t\t\tfrag = jQuery( middle ).get();\r\n\r\n\t\t\tstoreTmplItems( frag );\r\n\t\t\tif ( before ) {\r\n\t\t\t\tfrag = unencode( before ).concat(frag);\r\n\t\t\t}\r\n\t\t\tif ( after ) {\r\n\t\t\t\tfrag = frag.concat(unencode( after ));\r\n\t\t\t}\r\n\t\t});\r\n\t\treturn frag ? frag : unencode( ret );\r\n\t}\r\n\r\n\tfunction unencode( text ) {\r\n\t\t// Use createElement, since createTextNode will not render HTML entities correctly\r\n\t\tvar el = document.createElement( \"div\" );\r\n\t\tel.innerHTML = text;\r\n\t\treturn jQuery.makeArray(el.childNodes);\r\n\t}\r\n\r\n\t// Generate a reusable function that will serve to render a template against data\r\n\tfunction buildTmplFn( markup ) {\r\n\t\treturn new Function(\"jQuery\",\"$item\",\r\n\t\t\t// Use the variable __ to hold a string array while building the compiled template. (See https://github.com/jquery/jquery-tmpl/issues#issue/10).\r\n\t\t\t\"var $=jQuery,call,__=[],$data=$item.data;\" +\r\n\r\n\t\t\t// Introduce the data as local variables using with(){}\r\n\t\t\t\"with($data){__.push('\" +\r\n\r\n\t\t\t// Convert the template into pure JavaScript\r\n\t\t\tjQuery.trim(markup)\r\n\t\t\t\t.replace( /([\\\\'])/g, \"\\\\$1\" )\r\n\t\t\t\t.replace( /[\\r\\t\\n]/g, \" \" )\r\n\t\t\t\t.replace( /\\$\\{([^\\}]*)\\}/g, \"{{= $1}}\" )\r\n\t\t\t\t.replace( /\\{\\{(\\/?)(\\w+|.)(?:\\(((?:[^\\}]|\\}(?!\\}))*?)?\\))?(?:\\s+(.*?)?)?(\\(((?:[^\\}]|\\}(?!\\}))*?)\\))?\\s*\\}\\}/g,\r\n\t\t\t\tfunction( all, slash, type, fnargs, target, parens, args ) {\r\n\t\t\t\t\tvar tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect;\r\n\t\t\t\t\tif ( !tag ) {\r\n\t\t\t\t\t\tthrow \"Unknown template tag: \" + type;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tdef = tag._default || [];\r\n\t\t\t\t\tif ( parens && !/\\w$/.test(target)) {\r\n\t\t\t\t\t\ttarget += parens;\r\n\t\t\t\t\t\tparens = \"\";\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif ( target ) {\r\n\t\t\t\t\t\ttarget = unescape( target );\r\n\t\t\t\t\t\targs = args ? (\",\" + unescape( args ) + \")\") : (parens ? \")\" : \"\");\r\n\t\t\t\t\t\t// Support for target being things like a.toLowerCase();\r\n\t\t\t\t\t\t// In that case don't call with template item as 'this' pointer. Just evaluate...\r\n\t\t\t\t\t\texpr = parens ? (target.indexOf(\".\") > -1 ? target + unescape( parens ) : (\"(\" + target + \").call($item\" + args)) : target;\r\n\t\t\t\t\t\texprAutoFnDetect = parens ? expr : \"(typeof(\" + target + \")==='function'?(\" + target + \").call($item):(\" + target + \"))\";\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\texprAutoFnDetect = expr = def.$1 || \"null\";\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfnargs = unescape( fnargs );\r\n\t\t\t\t\treturn \"');\" +\r\n\t\t\t\t\t\ttag[ slash ? \"close\" : \"open\" ]\r\n\t\t\t\t\t\t\t.split( \"$notnull_1\" ).join( target ? \"typeof(\" + target + \")!=='undefined' && (\" + target + \")!=null\" : \"true\" )\r\n\t\t\t\t\t\t\t.split( \"$1a\" ).join( exprAutoFnDetect )\r\n\t\t\t\t\t\t\t.split( \"$1\" ).join( expr )\r\n\t\t\t\t\t\t\t.split( \"$2\" ).join( fnargs || def.$2 || \"\" ) +\r\n\t\t\t\t\t\t\"__.push('\";\r\n\t\t\t\t}) +\r\n\t\t\t\"');}return __;\"\r\n\t\t);\r\n\t}\r\n\tfunction updateWrapped( options, wrapped ) {\r\n\t\t// Build the wrapped content.\r\n\t\toptions._wrap = build( options, true,\r\n\t\t\t// Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string.\r\n\t\t\tjQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()]\r\n\t\t).join(\"\");\r\n\t}\r\n\r\n\tfunction unescape( args ) {\r\n\t\treturn args ? args.replace( /\\\\'/g, \"'\").replace(/\\\\\\\\/g, \"\\\\\" ) : null;\r\n\t}\r\n\tfunction outerHtml( elem ) {\r\n\t\tvar div = document.createElement(\"div\");\r\n\t\tdiv.appendChild( elem.cloneNode(true) );\r\n\t\treturn div.innerHTML;\r\n\t}\r\n\r\n\t// Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance.\r\n\tfunction storeTmplItems( content ) {\r\n\t\tvar keySuffix = \"_\" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m;\r\n\t\tfor ( i = 0, l = content.length; i < l; i++ ) {\r\n\t\t\tif ( (elem = content[i]).nodeType !== 1 ) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\telems = elem.getElementsByTagName(\"*\");\r\n\t\t\tfor ( m = elems.length - 1; m >= 0; m-- ) {\r\n\t\t\t\tprocessItemKey( elems[m] );\r\n\t\t\t}\r\n\t\t\tprocessItemKey( elem );\r\n\t\t}\r\n\t\tfunction processItemKey( el ) {\r\n\t\t\tvar pntKey, pntNode = el, pntItem, tmplItem, key;\r\n\t\t\t// Ensure that each rendered template inserted into the DOM has its own template item,\r\n\t\t\tif ( (key = el.getAttribute( tmplItmAtt ))) {\r\n\t\t\t\twhile ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { }\r\n\t\t\t\tif ( pntKey !== key ) {\r\n\t\t\t\t\t// The next ancestor with a _tmplitem expando is on a different key than this one.\r\n\t\t\t\t\t// So this is a top-level element within this template item\r\n\t\t\t\t\t// Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment.\r\n\t\t\t\t\tpntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0;\r\n\t\t\t\t\tif ( !(tmplItem = newTmplItems[key]) ) {\r\n\t\t\t\t\t\t// The item is for wrapped content, and was copied from the temporary parent wrappedItem.\r\n\t\t\t\t\t\ttmplItem = wrappedItems[key];\r\n\t\t\t\t\t\ttmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode] );\r\n\t\t\t\t\t\ttmplItem.key = ++itemKey;\r\n\t\t\t\t\t\tnewTmplItems[itemKey] = tmplItem;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif ( cloneIndex ) {\r\n\t\t\t\t\t\tcloneTmplItem( key );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tel.removeAttribute( tmplItmAtt );\r\n\t\t\t} else if ( cloneIndex && (tmplItem = jQuery.data( el, \"tmplItem\" )) ) {\r\n\t\t\t\t// This was a rendered element, cloned during append or appendTo etc.\r\n\t\t\t\t// TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem.\r\n\t\t\t\tcloneTmplItem( tmplItem.key );\r\n\t\t\t\tnewTmplItems[tmplItem.key] = tmplItem;\r\n\t\t\t\tpntNode = jQuery.data( el.parentNode, \"tmplItem\" );\r\n\t\t\t\tpntNode = pntNode ? pntNode.key : 0;\r\n\t\t\t}\r\n\t\t\tif ( tmplItem ) {\r\n\t\t\t\tpntItem = tmplItem;\r\n\t\t\t\t// Find the template item of the parent element.\r\n\t\t\t\t// (Using !=, not !==, since pntItem.key is number, and pntNode may be a string)\r\n\t\t\t\twhile ( pntItem && pntItem.key != pntNode ) {\r\n\t\t\t\t\t// Add this element as a top-level node for this rendered template item, as well as for any\r\n\t\t\t\t\t// ancestor items between this item and the item of its parent element\r\n\t\t\t\t\tpntItem.nodes.push( el );\r\n\t\t\t\t\tpntItem = pntItem.parent;\r\n\t\t\t\t}\r\n\t\t\t\t// Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering...\r\n\t\t\t\tdelete tmplItem._ctnt;\r\n\t\t\t\tdelete tmplItem._wrap;\r\n\t\t\t\t// Store template item as jQuery data on the element\r\n\t\t\t\tjQuery.data( el, \"tmplItem\", tmplItem );\r\n\t\t\t}\r\n\t\t\tfunction cloneTmplItem( key ) {\r\n\t\t\t\tkey = key + keySuffix;\r\n\t\t\t\ttmplItem = newClonedItems[key] =\r\n\t\t\t\t\t(newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent ));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t//---- Helper functions for template item ----\r\n\r\n\tfunction tiCalls( content, tmpl, data, options ) {\r\n\t\tif ( !content ) {\r\n\t\t\treturn stack.pop();\r\n\t\t}\r\n\t\tstack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options });\r\n\t}\r\n\r\n\tfunction tiNest( tmpl, data, options ) {\r\n\t\t// nested template, using {{tmpl}} tag\r\n\t\treturn jQuery.tmpl( jQuery.template( tmpl ), data, options, this );\r\n\t}\r\n\r\n\tfunction tiWrap( call, wrapped ) {\r\n\t\t// nested template, using {{wrap}} tag\r\n\t\tvar options = call.options || {};\r\n\t\toptions.wrapped = wrapped;\r\n\t\t// Apply the template, which may incorporate wrapped content,\r\n\t\treturn jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item );\r\n\t}\r\n\r\n\tfunction tiHtml( filter, textOnly ) {\r\n\t\tvar wrapped = this._wrap;\r\n\t\treturn jQuery.map(\r\n\t\t\tjQuery( jQuery.isArray( wrapped ) ? wrapped.join(\"\") : wrapped ).filter( filter || \"*\" ),\r\n\t\t\tfunction(e) {\r\n\t\t\t\treturn textOnly ?\r\n\t\t\t\t\te.innerText || e.textContent :\r\n\t\t\t\t\te.outerHTML || outerHtml(e);\r\n\t\t\t});\r\n\t}\r\n\r\n\tfunction tiUpdate() {\r\n\t\tvar coll = this.nodes;\r\n\t\tjQuery.tmpl( null, null, null, this).insertBefore( coll[0] );\r\n\t\tjQuery( coll ).remove();\r\n\t}\r\n}));\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/js/plugins/metisMenu/jquery.metisMenu.js",
    "content": "/*\r\n * metismenu - v2.0.2\r\n * A jQuery menu plugin\r\n * https://github.com/onokumus/metisMenu\r\n *\r\n * Made by Osman Nuri Okumus\r\n * Under MIT License\r\n */\r\n\r\n!function(a){\"use strict\";function b(){var a=document.createElement(\"mm\"),b={WebkitTransition:\"webkitTransitionEnd\",MozTransition:\"transitionend\",OTransition:\"oTransitionEnd otransitionend\",transition:\"transitionend\"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}function c(b){return this.each(function(){var c=a(this),d=c.data(\"mm\"),f=a.extend({},e.DEFAULTS,c.data(),\"object\"==typeof b&&b);d||c.data(\"mm\",d=new e(this,f)),\"string\"==typeof b&&d[b]()})}a.fn.emulateTransitionEnd=function(b){var c=!1,e=this;a(this).one(\"mmTransitionEnd\",function(){c=!0});var f=function(){c||a(e).trigger(d.end)};return setTimeout(f,b),this};var d=b();d&&(a.event.special.mmTransitionEnd={bindType:d.end,delegateType:d.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}});var e=function(b,c){this.$element=a(b),this.options=a.extend({},e.DEFAULTS,c),this.transitioning=null,this.init()};e.TRANSITION_DURATION=350,e.DEFAULTS={toggle:!0,doubleTapToGo:!1,activeClass:\"active\"},e.prototype.init=function(){var b=this,c=this.options.activeClass;this.$element.find(\"li.\"+c).has(\"ul\").children(\"ul\").addClass(\"collapse in\"),this.$element.find(\"li\").not(\".\"+c).has(\"ul\").children(\"ul\").addClass(\"collapse\"),this.options.doubleTapToGo&&this.$element.find(\"li.\"+c).has(\"ul\").children(\"a\").addClass(\"doubleTapToGo\"),this.$element.find(\"li\").has(\"ul\").children(\"a\").on(\"click.metisMenu\",function(d){var e=a(this),f=e.parent(\"li\"),g=f.children(\"ul\");return d.preventDefault(),f.hasClass(c)?b.hide(g):b.show(g),b.options.doubleTapToGo&&b.doubleTapToGo(e)&&\"#\"!==e.attr(\"href\")&&\"\"!==e.attr(\"href\")?(d.stopPropagation(),void(document.location=e.attr(\"href\"))):void 0})},e.prototype.doubleTapToGo=function(a){var b=this.$element;return a.hasClass(\"doubleTapToGo\")?(a.removeClass(\"doubleTapToGo\"),!0):a.parent().children(\"ul\").length?(b.find(\".doubleTapToGo\").removeClass(\"doubleTapToGo\"),a.addClass(\"doubleTapToGo\"),!1):void 0},e.prototype.show=function(b){var c=this.options.activeClass,f=a(b),g=f.parent(\"li\");if(!this.transitioning&&!f.hasClass(\"in\")){g.addClass(c),this.options.toggle&&this.hide(g.siblings().children(\"ul.in\")),f.removeClass(\"collapse\").addClass(\"collapsing\").height(0),this.transitioning=1;var h=function(){f.removeClass(\"collapsing\").addClass(\"collapse in\").height(\"\"),this.transitioning=0};return d?void f.one(\"mmTransitionEnd\",a.proxy(h,this)).emulateTransitionEnd(e.TRANSITION_DURATION).height(f[0].scrollHeight):h.call(this)}},e.prototype.hide=function(b){var c=this.options.activeClass,f=a(b);if(!this.transitioning&&f.hasClass(\"in\")){f.parent(\"li\").removeClass(c),f.height(f.height())[0].offsetHeight,f.addClass(\"collapsing\").removeClass(\"collapse\").removeClass(\"in\"),this.transitioning=1;var g=function(){this.transitioning=0,f.removeClass(\"collapsing\").addClass(\"collapse\")};return d?void f.height(0).one(\"mmTransitionEnd\",a.proxy(g,this)).emulateTransitionEnd(e.TRANSITION_DURATION):g.call(this)}};var f=a.fn.metisMenu;a.fn.metisMenu=c,a.fn.metisMenu.Constructor=e,a.fn.metisMenu.noConflict=function(){return a.fn.metisMenu=f,this}}(jQuery);"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/js/resize-tabs.js",
    "content": "(function(c,a,e){var b,d=\"resizeTabs\",f={navSelector:\".nav-tabs\",itemSelector:\">li\",dropdownSelector:\">.dropdown\",dropdownItemSelector:\"li\",tabParentSelector:\"\",tabSelector:\".tab-pane\",activeClassName:\"active\",noNavClassName:\".no-menu\",fnCallback:\"\"};b=function(j,i){var h=this.$tabs=e(j),k=this.options=e.extend(true,{},f,i),g=this.$nav=h.find(k.navSelector),l=this.$dropdown=g.find(k.dropdownSelector);this.$items=g.find(k.itemSelector).filter(function(){return !e(this).is(l)});this.$dropdownItems=l.find(k.dropdownItemSelector);if(k.tabParentSelector!==\"\"){this.$tabPanel=e(k.tabParentSelector).find(k.tabSelector)}else{this.$tabPanel=h.find(k.tabSelector)}this.init()};b.prototype={init:function(){var j=this.itemsLenth=this.$items.length,h;if(j===0){throw\"There should be some tags here \"}if(this.$dropdown.length===0){this.flag=true;this.$nav.append('<li class=\"dropdown\" role=\"presentation\">'+'<a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"#\" aria-expanded=\"false\">'+'<i class=\"glyphicon glyphicon-align-justify\"></i> <b class=\"caret\"></b></a><ul class=\"dropdown-menu\" role=\"menu\"></ul></li>');this.$dropdown=this.$nav.find(this.options.dropdownSelector);this.$dropdown.css(\"opacity\",0);h=this.$dropdown.width();h=h===0?90:h;this.$dropdown.addClass(\"hidden\").css(\"opacity\",1)}else{h=this.$dropdown.width()}this.breakpoints=[];for(var g=0;g<j+1;g++){var k=this.$items.eq(g).width(),l=0;switch(g){case 0:l=k+h;break;case j-1:l=this.breakpoints[g-1]+k-h;break;case j:l=this.breakpoints[g-1]+h;break;default:l=this.breakpoints[g-1]+k}this.breakpoints.push(l)}if(typeof this.options.fnCallback===\"function\"){this.options.fnCallback(this.$tabs)}this.bind();this.layout()},layout:function(){if(this.breakpoints.length<=0){return}var l=this.$tabs.width()-500,j=0,h=this,g=this.options.activeClassName,m=this.$tabPanel.filter(\".\"+g).index(),k=function(p){var o=p;if(p===h.itemsLenth){o=p-1}for(;o<h.itemsLenth;o++){if(h.flag){h.$dropdown.find(\"ul\").append(h.$items.eq(o).prop(\"outerHTML\"))}else{h.$dropdown.find(\"ul>li\"+h.options.noNavClassName+\":first\").before(h.$items.eq(o).prop(\"outerHTML\"))}h.$items.eq(o).hide()}},n=function(p){for(var o=0;o<h.itemsLenth+1;o++){if(o<p){h.$items.eq(o).show()}else{k(p);h.$dropdown.find(\"ul>li\").show();break}}h.$dropdownItems=h.$dropdown.find(h.options.dropdownItemSelector)};for(;j<this.breakpoints.length;j++){if(this.breakpoints[j]>l){break}}this.$items.removeClass(g);this.$dropdownItems.removeClass(g);this.$dropdown.removeClass(g);if(j===this.breakpoints.length){if(this.flag){this.$dropdown.addClass(\"hidden\")}else{this.$dropdown.find(\"ul>li:not(li\"+this.options.noNavClassName+\")\").remove()}this.$items.show();if(m!=-1){this.$items.eq(m-1).addClass(g)}}else{this.$dropdown.removeClass(\"hidden\");if(this.flag){this.$dropdown.find(\"ul>li\").remove()}else{this.$dropdown.find(\"ul>li:not(li\"+this.options.noNavClassName+\")\").remove()}n(j);if(m<j){if(m!=-1){this.$items.eq(m-1).addClass(g)}}else{this.$dropdown.addClass(g);this.$dropdownItems.eq(m-j).addClass(g)}}},throttle:function(h,g){var k=h,j,i=true;return function(){var m=arguments,l=this;if(i){k.apply(l,m);i=false}if(j){return false}j=setInterval(function(){clearInterval(j);j=null;k.apply(l,m)},g||500)}},bind:function(){var g=this;e(c).resize(function(){g.throttle(function(){g.layout()},1000)()})}};e.fn[d]=function(g){if(typeof g===\"string\"){var i=g,h=Array.prototype.slice.call(arguments,1);if(/^_/.test(i)){console.error(\"No such method : \"+g)}else{return this.each(function(){var j=e.data(this,d);if(j&&typeof j[i]===\"function\"){j[i].apply(j,h)}})}}else{return this.each(function(){if(!e.data(this,d)){e.data(this,d,new b(this,g))}else{e.data(this,d).init()}})}}})(window,document,jQuery);$(\"#navMenu\").resizeTabs({tabParentSelector:\"#side-menu\"});"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ruoyi/css/ry-ui.css",
    "content": "/**\r\n * 通用css样式布局处理\r\n * Copyright (c) 2019 ruoyi\r\n */\r\n\r\n/** 基础通用 **/\r\n.pt5 {\r\n\tpadding-top: 5px;\r\n}\r\n.pr5 {\r\n\tpadding-right: 5px;\r\n}\r\n.pb5 {\r\n\tpadding-bottom: 5px;\r\n}\r\n.mt5 {\r\n\tmargin-top: 5px;\r\n}\r\n.mr5 {\r\n\tmargin-right: 5px;\r\n}\r\n.mb5 {\r\n\tmargin-bottom: 5px;\r\n}\r\n.ml5 {\r\n\tmargin-left: 5px;\r\n}\r\n.mt10 {\r\n\tmargin-top: 10px;\r\n}\r\n.mr10 {\r\n\tmargin-right: 10px;\r\n}\r\n.mb10 {\r\n\tmargin-bottom: 10px;\r\n}\r\n.ml0 {\r\n\tmargin-left: 10px;\r\n}\r\n.mt20 {\r\n\tmargin-top: 20px;\r\n}\r\n.mr20 {\r\n\tmargin-right: 20px;\r\n}\r\n.mb20 {\r\n\tmargin-bottom: 20px;\r\n}\r\n.m20 {\r\n\tmargin-left: 20px;\r\n}\r\n.m50 {\r\n\tmargin-left: 50px;\r\n}\r\n.img-xs {\r\n  width: 32px;\r\n  height: 32px;\r\n}\r\n.img-sm {\r\n  width: 64px;\r\n  height: 64px;\r\n}\r\n.img-md {\r\n  width: 96px;\r\n  height: 96px;\r\n}\r\n.img-lg {\r\n  width: 120px;\r\n  height: 120px;\r\n}\r\n.section-content {\r\n    min-height: 250px;\r\n    margin-right: auto;\r\n    margin-left: auto;\r\n    padding: 5px 5px 5px 5px;\r\n    width: 100%;\r\n    height: 100%;\r\n    position: absolute;\r\n}\r\n\r\n.ibox {\r\n    margin-bottom: 25px;\r\n    background-color: #fff;\r\n    border: 1px solid #ddd;\r\n    border-radius: 4px;\r\n    height: 100%;\r\n    -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\r\n}\r\n\r\n.list-group-striped > .list-group-item {\r\n\tborder-left: 0;\r\n\tborder-right: 0;\r\n\tborder-radius: 0;\r\n\tpadding-left: 0;\r\n\tpadding-right: 0\r\n}\r\n\r\n.ibox-title-gray {\r\n    height: 41px;\r\n    background-color: #f0f3f4;\r\n    color: #333;\r\n    font-weight: 700;\r\n    border-radius: 2px 2px 0 0;\r\n    padding: 13px !important;\r\n    border-bottom: 1px solid #eee;\r\n    display: block;\r\n    clear: both;\r\n}\r\n\r\n.dashboard-header h5 {\r\n    padding: 8px 0 0 0;\r\n    display: inline-block;\r\n    font-size: 14px;\r\n    text-overflow: ellipsis;\r\n    float: left;\r\n    font-weight: 400;\r\n}\r\n\r\n.ibox-title-gray h5 {\r\n    display: inline-block;\r\n    font-size: 14px;\r\n    margin: 0 0 7px;\r\n    padding: 0;\r\n    text-overflow: ellipsis;\r\n    float: left;\r\n}\r\n\r\n/* 导航页签 */\r\n.nav-tabs-custom {\r\n\tmargin-bottom: 20px;\r\n\tbackground: #fff;\r\n\tbox-shadow: 0 1px 1px rgba(0,0,0,0.1);\r\n\tborder-radius: 3px\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs {\r\n\tmargin: 0;\r\n\tborder-bottom-color: #f4f4f4;\r\n\tborder-top-right-radius: 3px;\r\n\tborder-top-left-radius: 3px\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li {\r\n\tborder-top: 3px solid transparent;\r\n\tmargin-bottom: -2px;\r\n\tmargin-right: 5px\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li.header {\r\n\tpadding-left: 5px;\r\n\tfont-size: 16px;\r\n\tline-height: 30px;\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li.disabled>a {\r\n\tcolor: #777\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li>a {\r\n\tcolor: #444;\r\n\tfont-weight: normal;\r\n\tborder-radius: 0\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li>a,.nav-tabs-custom>.nav-tabs>li>a:hover {\r\n\tbackground: transparent;\r\n\tmargin: 0\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li>a:hover {\r\n\tcolor: #999\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li:not(.active)>a:hover,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:focus,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:active {\r\n\tborder-color: transparent\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li.active {\r\n\tborder-top-color: #1890ff\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li.active>a,.nav-tabs-custom>.nav-tabs>li.active:hover>a {\r\n\tbackground-color: #fff;\r\n\tcolor: #444\r\n}\r\n\r\n.nav-tabs-custom>.nav-tabs>li.active>a {\r\n\tborder-top-color: transparent;\r\n\tborder-bottom-color: transparent;\r\n\tborder-left-color: #f4f4f4;\r\n\tborder-right-color: #f4f4f4\r\n}\r\n\r\n.nav-tabs-custom>.tab-content {\r\n\tbackground: #fff;\r\n\tpadding: 10px;\r\n\tborder-bottom-right-radius: 3px;\r\n\tborder-bottom-left-radius: 3px\r\n}\r\n\r\n/** 弹层组件 禁用样式 **/\r\n.layer-disabled {\r\n\tborder: 1px #dedede solid !important;\r\n\tbackground-color: #f1f1f1 !important;\r\n\tcolor: #333 !important;\r\n\tpointer-events: none;\r\n}\r\n\r\n/** 用户管理 样式布局 **/\r\n.box {\r\n\tposition: relative;\r\n\tborder-radius: 3px;\r\n\tbackground: #ffffff;\r\n\tborder-top: 3px solid #d2d6de;\r\n\tmargin-bottom: 20px;\r\n\twidth: 100%;\r\n\tbox-shadow: 0 1px 1px rgba(0,0,0,0.1)\r\n}\r\n\r\n.box-header:before,.box-body:before,.box-footer:before,.box-header:after,.box-body:after,.box-footer:after {\r\n\tcontent: \" \";\r\n\tdisplay: table\r\n}\r\n\r\n.box-header:after,.box-body:after,.box-footer:after {\r\n\tclear: both\r\n}\r\n\r\n.btn-box-tool {\r\n\tpadding: 5px;\r\n\tfont-size: 12px;\r\n\tbackground: transparent;\r\n\tcolor: #97a0b3;\r\n}\r\n\r\n.open .btn-box-tool,\r\n.btn-box-tool:hover {\r\n\tcolor: #606c84;\r\n}\r\n\r\n.box-main {\r\n\tmargin: 0;\r\n\tborder: 0;\r\n\tpadding-top: 2px;\r\n\tborder-radius: 0;\r\n\tbox-shadow: none\r\n}\r\n\r\n.box-main>.box-header {\r\n\tborder-bottom: 1px solid #eee;\r\n\tpadding: 12px 10px 2px 15px\r\n}\r\n\r\n.box-header .box-title {\r\n\tdisplay: inline-block;\r\n\tfont-size: 18px;\r\n\tmargin: 0;\r\n\tline-height: 1;\r\n}\r\n\r\n.box-main>.box-header .box-title {\r\n\tfont-size: 16px;\r\n\tmargin-bottom: 13px;\r\n\tfloat: left\r\n}\r\n\r\n.box-main>.box-header .box-title .fa {\r\n\tfont-size: 14px;\r\n\tpadding-right: 3px;\r\n\tmargin-top: -2px\r\n}\r\n\r\n.box-main>.box-header .box-tools {\r\n\tposition: relative;\r\n\ttop: -5px;\r\n\tright: 0\r\n}\r\n\r\n.box-main>.box-header .box-tools .btn {\r\n\tpadding: 3px 10px 5px 10px;\r\n\tfont-size: 14px;\r\n\tmargin-bottom: 2px\r\n}\r\n\r\n.box-main>.box-header .box-tools .btn-box-tool {\r\n\tpadding: 4px 2px\r\n}\r\n\r\n.box-main form>.box-footer,.nav-main form>.box-footer {\r\n\tbackground: #fafafa\r\n}\r\n\r\n.box-main form>.box-footer .row,.nav-main form>.box-footer .row {\r\n\tmargin: 5px 0 5px -25px\r\n}\r\n\r\n@media ( min-width : 768px) {\r\n\t.section-content .about {\r\n\t\tpadding-left: 0px\r\n\t}\r\n}\r\n\r\n/** select2 样式修改 **/\r\n.select2-container--default .select2-selection--multiple .select2-selection__choice {\r\n\tbackground-color: #1AB394;\r\n\tborder-color: #1AB394;\r\n\tpadding: 1px 10px;\r\n\tcolor: #fff\r\n}\r\n\r\n.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {\r\n\tmargin-right: 5px;\r\n\tcolor: rgba(255,255,255,0.7)\r\n}\r\n\r\n.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {\r\n\tcolor: #fff\r\n}\r\n\r\n.select2-container .select2-selection--single .select2-selection__rendered {\r\n\tpadding-right: 10px\r\n}\r\n\r\n/** 表单验证 样式布局 **/\r\n.control-label.is-required:before {\r\n  content: '* ';\r\n  color: red;\r\n}\r\n\r\nlabel.error {\r\n\tposition: absolute;\r\n\tright: 18px;\r\n\ttop: 6px;\r\n\tcolor: #ef392b;\r\n\tfont-size: 12px;\r\n\tz-index:99;\r\n}\r\n\r\n.input-group label.error {\r\n\tz-index:99;\r\n\tright: 42px;\r\n}\r\n\r\n.input-group input.error + label.error + .input-group-addon>i {\r\n\tcolor: #ed5565;\r\n}\r\n\r\n.input-group.date label.error {\r\n\tz-index:99;\r\n\tright: 42px;\r\n}\r\n\r\n.select2-hidden-accessible + label.error, select.error + label.error {\r\n\tright: 38px;\r\n}\r\n\r\n.Validform_error,input.error,textarea.error,select.error,select.error+label.error+.select2-container--bootstrap .select2-selection--single {\r\n\tbackground-color: #fbe2e2;\r\n\tborder-color: #c66161;\r\n\tcolor: #c00\r\n}\r\n\r\n.Validform_wrong,.Validform_right,.Validform_warning {\r\n\tdisplay: inline-block;\r\n\theight: 20px;\r\n\tfont-size: 12px;\r\n\tvertical-align: middle;\r\n\tpadding-left: 25px\r\n}\r\n\r\n.i-checks label.error, .check-box label.error, .radio-box label.error {\r\n\tright: auto;\r\n\twidth: 150px;\r\n\tleft: 210px;\r\n\ttop: 1px;\r\n\tmax-width: none;\r\n}\r\n\r\n/** 复选框&单选框  **/\r\n.check-box,.radio-box {\r\n\tdisplay: inline-block;\r\n\tbox-sizing: border-box;\r\n\tcursor: pointer;\r\n\tposition: relative;\r\n\tpadding-left: 25px;\r\n\tpadding-right: 15px;\r\n\tpadding-top: 7px;\r\n}\r\n\r\n.icheckbox, .icheckbox-blue, .iradio, .iradio-blue, .iradio-purple {\r\n\tposition: absolute;\r\n\ttop: 7px;\r\n\tleft: 0\r\n}\r\n\r\n/** iCheck **/\r\n.icheckbox-blue,.iradio-blue {\r\n\tdisplay: block;\r\n\tmargin: 0;\r\n\tpadding: 0;\r\n\twidth: 18px;\r\n\theight: 18px;\r\n\tbackground: url(../../img/blue.png) no-repeat;\r\n\tborder: none;\r\n\tcursor: pointer\r\n}\r\n\r\n.icheckbox-blue,.icheckbox-blue.static:hover {\r\n\tbackground-position: 0 0\r\n}\r\n\r\n.icheckbox-blue.hover,.icheckbox-blue:hover {\r\n\tbackground-position: -20px 0\r\n}\r\n\r\n.icheckbox-blue.checked {\r\n\tbackground-position: -40px 0\r\n}\r\n\r\n.icheckbox-blue.disabled {\r\n\tbackground-position: -60px 0;\r\n\tcursor: default\r\n}\r\n\r\n.icheckbox-blue.checked.disabled {\r\n\tbackground-position: -80px 0\r\n}\r\n\r\n.iradio-blue,.iradio-blue.static:hover {\r\n\tbackground-position: -100px 0\r\n}\r\n\r\n.iradio-blue.hover,.iradio-blue:hover {\r\n\tbackground-position: -120px 0\r\n}\r\n\r\n.iradio-blue.checked {\r\n\tbackground-position: -140px 0\r\n}\r\n\r\n.iradio-blue.disabled {\r\n\tbackground-position: -160px 0;\r\n\tcursor: default\r\n}\r\n\r\n.iradio-blue.checked.disabled {\r\n\tbackground-position: -180px 0\r\n}\r\n\r\n/* ztree */\r\ndiv.ztree-border {\r\n    margin-top: 10px;\r\n    border: 1px solid #e5e6e7;\r\n    background: #FFFFFF none;\r\n    border-radius:4px;\r\n}\r\n\r\n/* 切换开关 */\r\n.toggle-switch {\r\n\tdisplay: -webkit-inline-box;\r\n\tdisplay: -webkit-inline-flex;\r\n\tdisplay: -ms-inline-flexbox;\r\n\tdisplay: inline-flex;\r\n\t-webkit-box-align: center;\r\n\t-webkit-align-items: center;\r\n\t-ms-flex-align: center;\r\n\talign-items: center;\r\n\tmargin-bottom: 0;\r\n\tpadding-top: 8px;\r\n}\r\n.toggle-switch input {\r\n    height: 0;\r\n    width: 0;\r\n    position: absolute;\r\n    opacity: 0;\r\n}\r\n.toggle-switch span {\r\n\tdisplay: inline-block;\r\n\tposition: relative;\r\n\twidth: 40px;\r\n\theight: 10px;\r\n\t-webkit-border-radius: 10px;\r\n\tborder-radius: 10px;\r\n\tbackground-color: #ebebeb;\r\n\tborder: 2px solid #ebebeb;\r\n\tcursor: pointer;\r\n\t-webkit-transition: all .1s ease;\r\n\t-o-transition: all .1s ease;\r\n\ttransition: all .1s ease\r\n}\r\n.toggle-switch span:after {\r\n\tcontent: '';\r\n\theight: 20px;\r\n\twidth: 20px;\r\n\t-webkit-border-radius: 50%;\r\n\tborder-radius: 50%;\r\n\tposition: absolute;\r\n\tleft: 1px;\r\n\ttop: -7px;\r\n\tcolor: #aaa;\r\n\t-webkit-transition: all .1s ease;\r\n\t-o-transition: all .1s ease;\r\n\ttransition: all .1s ease;\r\n\ttext-align: center;\r\n\tfont-size: 13px;\r\n\tbackground-color: #fff;\r\n\t-webkit-box-shadow: rgba(0,0,0,.12) 0 1px 6px,rgba(0,0,0,.12) 0 1px 4px;\r\n\tbox-shadow: rgba(0,0,0,.12) 0 1px 6px,rgba(0,0,0,.12) 0 1px 4px\r\n}\r\n.toggle-switch input:checked~span:after {\r\n\tleft: -webkit-calc(100% - 20px);\r\n\tleft: calc(100% - 20px);\r\n\tbackground-color: #33cabb\r\n}\r\n\r\n.toggle-switch.switch-solid span  {\r\n    height: 20px;\r\n}\r\n.toggle-switch.switch-solid span:after {\r\n    top: -2px;\r\n}\r\n.switch-solid input:checked~span {\r\n\tbackground-color: #33cabb;\r\n\tborder-color: #33cabb\r\n}\r\n.switch-solid input:checked~span:after {\r\n\tbackground-color: #fff;\r\n\tcolor: #33cabb\r\n}\r\n\r\n/** 遮罩层 **/\r\n.loaderbox {\r\n\tdisplay: inline-block;\r\n\tmin-width: 125px;\r\n\tpadding: 10px;\r\n\tmargin: 0 auto;\r\n\tcolor: #000 !important;\r\n\tfont-size: 13px;\r\n\tfont-weight: 400;\r\n\ttext-align: center;\r\n\tvertical-align: middle;\r\n\tborder: 1px solid #ddd;\r\n\tbackground-color: #eee;\r\n\t-webkit-border-radius: 2px;\r\n\t-moz-border-radius: 2px;\r\n\t-ms-border-radius: 2px;\r\n\t-o-border-radius: 2px;\r\n\tborder-radius: 2px;\r\n\t-webkit-box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);\r\n\t-moz-box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);\r\n\tbox-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n.loaderbox .loading-activity {\r\n\tfloat: left;\r\n\twidth: 18px;\r\n\theight: 18px;\r\n\tborder: solid 2px transparent;\r\n\tborder-top-color: #000;\r\n\tborder-left-color: #000;\r\n\tborder-radius: 10px;\r\n\t-webkit-animation: pace-spinner 400ms linear infinite;\r\n\t-moz-animation: pace-spinner 400ms linear infinite;\r\n\t-ms-animation: pace-spinner 400ms linear infinite;\r\n\t-o-animation: pace-spinner 400ms linear infinite;\r\n\tanimation: pace-spinner 400ms linear infinite;\r\n}\r\n\r\n@media (max-width: 767px) {\r\n\t.loading-activity {\r\n\t\twidth: 18px;\r\n\t\theight: 18px;\r\n\t}\r\n}\r\n\r\n@-ms-keyframes pace-spinner {\r\n\t0% {\r\n\t\t-ms-transform: rotate(0deg);\r\n\t\ttransform: rotate(0deg);\r\n\t}\r\n\r\n\t100% {\r\n\t\t-ms-transform: rotate(360deg);\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n@keyframes pace-spinner {\r\n\t0% {\r\n\t\ttransform: rotate(0deg);\r\n\t}\r\n\r\n\t100% {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n/** 表单查询条件  **/\r\n.select-list ul, .layui-layer-content ul {\r\n\tmargin: 0;\r\n\tpadding: 0;\r\n\t-webkit-tap-highlight-color: rgba(0,0,0,0);\r\n}\r\n\r\n.select-list li, .layui-layer-content li {\r\n\tlist-style: none;\r\n}\r\n\r\n.select-time .time-input {\r\n\tdisplay: block;\r\n\twidth: 100%;\r\n\tpadding-left: 10px;\r\n}\r\n\r\nlabel {\r\n\tfont-weight: normal;\r\n}\r\n\r\n.container-div {\r\n\tpadding: 0px 28px;\r\n\theight: 100%;\r\n}\r\n\r\n.container-div .row {\r\n\theight: 100%;\r\n}\r\n\r\n.search-collapse,.select-table {\r\n\twidth: 100%;\r\n\tbackground: #fff;\r\n\tborder-radius: 6px;\r\n\tmargin-top: 10px;\r\n\tpadding-top: 5px;\r\n\tpadding-bottom: 13px;\r\n\tbox-shadow: 1px 1px 3px rgba(0,0,0,.2);\r\n}\r\n\r\n.search-collapse {\r\n\tposition: relative;\r\n}\r\n\r\n.search-collapse .col-sm-6 .control-label {\r\n\tcolor: #333;\r\n}\r\n\r\n@media ( max-width : 768px) {\r\n\t.search-collapse {\r\n\t\tdisplay: none;\r\n\t}\r\n}\r\n\r\n@media ( min-width : 768px) {\r\n\t.select-list li {\r\n\t\tfloat: left;\r\n\t}\r\n}\r\n\r\n.select-list li {\r\n\tcolor: #333;\r\n\tmargin: 5px 15px 5px 0px;\r\n}\r\n\r\n.select-list li p, .select-list li label:not(.radio-box){\r\n\tfloat: left;\r\n\twidth: 65px;\r\n\tmargin: 5px 0px 0px 0px;\r\n\ttext-align:right;\r\n}\r\n\r\n.select-list li input {\r\n\tborder: 1px solid #ddd;\r\n\tborder-radius: 4px;\r\n\tbackground: transparent;\r\n\toutline: none;\r\n\theight: 30px;\r\n\twidth: 200px;\r\n\tpadding-left: 5px;\r\n}\r\n\r\n.select-list li .submit-btn {\r\n\tborder: 0px;\r\n\tborder-radius: 4px;\r\n\tbackground: transparent;\r\n\toutline: none;\r\n\twidth: 40px;\r\n\theight: 23px;\r\n}\r\n\r\n.select-list li select {\r\n\tborder: 1px solid #ddd;\r\n\tborder-radius: 4px;\r\n\tbackground: transparent;\r\n\toutline: none;\r\n\theight: 30px;\r\n    width: 200px;\r\n}\r\n\r\n.bootstrap-select.form-control .btn-default {\r\n    color: inherit;\r\n    padding: 4px 6px 4px;\r\n    border-radius: 4px;\r\n    border: 1px solid #e5e6e7;\r\n\toutline: none;\r\n\theight: 31px;\r\n\tbackground: #FFFFFF none\r\n}\r\n\r\n.file-input .btn-default {\r\n    color: inherit;\r\n    background: white;\r\n    border: 1px solid #e7eaec;\r\n}\r\n\r\n.select-list .btn-default {\r\n    color: #555;\r\n    padding: 5px 5px;\r\n    border: 1px solid #ddd;\r\n\tborder-radius: 4px;\r\n\tbackground: transparent;\r\n\toutline: none;\r\n\theight: 30px;\r\n\twidth: 200px;\r\n}\r\n\r\n.select-list .btn-default:hover,.select-list .btn-default:focus,.select-list .btn-default:active,.select-list .btn-default.active,.open .dropdown-toggle.btn-default {\r\n\tcolor: #555;\r\n\tbackground-color: #e4e4e4;\r\n\tborder-color: #b2b2b2\r\n}\r\n\r\n.select-list .bootstrap-select:not([class*=\"col-\"]):not([class*=\"form-control\"]):not(.input-group-btn) {\r\n  height: 30px;\r\n  width: 200px;\r\n}\r\n\r\n.select-list .bootstrap-select > .dropdown-toggle.bs-placeholder,\r\n.select-list .bootstrap-select > .dropdown-toggle.bs-placeholder:hover,\r\n.select-list .bootstrap-select > .dropdown-toggle.bs-placeholder:focus,\r\n.select-list .bootstrap-select > .dropdown-toggle.bs-placeholder:active {\r\n  color: inherit;\r\n  font-size: 13px;\r\n}\r\n\r\n.select-list .bootstrap-select .dropdown-toggle .caret {\r\n  position: inherit;\r\n}\r\n\r\n.select-list .select-selectpicker li {\r\n\tfloat: none;\r\n}\r\n\r\n.select-list .dropdown-menu>li>a,.bootstrap-select.form-control .dropdown-menu>li>a {\r\n    line-height: inherit;\r\n}\r\n\r\n.select-list .dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a,.bootstrap-select.form-control .dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{\r\n\tcolor: #fff;\r\n\ttext-decoration: none;\r\n\tbackground-color: #12889a\r\n}\r\n\r\n.select-list .select2-container--bootstrap {\r\n\twidth: 200px!important;\r\n\tdisplay: inline-block;\r\n}\r\n\r\n.select-list .select2-container--bootstrap .select2-selection {\r\n\tborder-radius: 6px;\r\n}\r\n\r\n.select-list .select2-container--bootstrap .select2-selection--single {\r\n\theight: 30px!important;\r\n\tpadding: 5px 10px;\r\n}\r\n\r\n.select-list .select-time input {\r\n\twidth: 93px;\r\n}\r\n\r\n.select-time label,.select-time span,.select-time input {\r\n\tfloat: left;\r\n}\r\n\r\n@media (max-width:767px) {\r\n    .select-time label,.select-time span,.select-time input {\r\n\t    float: none;\r\n    }\r\n    .select-list .select-time input {\r\n\t    width: 200px;\r\n    }\r\n}\r\n\r\n.select-time label {\r\n\tmargin-top: 5px;\r\n}\r\n\r\n.select-time span {\r\n\tdisplay: block;\r\n\tmargin: 5px 5px;\r\n}\r\n\r\n.search-btn {\r\n\tbackground-color: #1ab394;\r\n\tborder-color: #1ab394;\r\n\tcolor: #FFF;\r\n\tmargin-bottom: 5px;\r\n\tdisplay: inline-block;\r\n\tpadding: 6px 12px;\r\n\tmargin-bottom: 0;\r\n\tfont-size: 14px;\r\n\tfont-weight: 400;\r\n\tline-height: 1.42857143;\r\n\ttext-align: center;\r\n\twhite-space: nowrap;\r\n\tborder-radius: 3px;\r\n\tvertical-align: middle;\r\n\tcursor: pointer;\r\n}\r\n\r\n.select-title{\r\n\tcolor:#3d5266;\r\n\tfont-size:15px;\r\n\tpadding:10px 0px;\r\n\tfont-weight: normal;\r\n}\r\n\r\n/** 表格查询数据 **/\r\n.table-striped {\r\n\tmin-height: 75%;\r\n}\r\n\r\n.table-striped .bootstrap-table, .table-striped .table-bordered {\r\n\tborder: 0px!important;\r\n}\r\n\r\n.table-bordered .table>thead>tr>th, .table-bordered .table>tbody>tr>th {\r\n\tfont-weight: normal;\r\n\tfont-size: 13px\r\n}\r\n\r\n.table-striped table>thead>tr>th, .table-striped table>tbody>tr>th, .table-striped table>tfoot>tr>th, .table-striped table>thead>tr>td, .table-striped table>tbody>tr>td, .table-striped table>tfoot>tr>td {\r\n\tborder-bottom: 1px solid #e7eaec!important;\r\n\tbackground-color: transparent;\r\n\tborder: 0px;\r\n}\r\n\r\n.table-bordered table>thead>tr>th:first-child, .table-bordered table>tbody>tr>td:first-child {\r\n    border-left: 1px solid #ddd;\r\n}\r\n\r\n.table-bordered table>thead>tr>th:last-child, .table-bordered table>tbody>tr>td:last-child {\r\n\tborder-right: 1px solid #ddd;\r\n}\r\n\r\n.table-bordered table>thead>tr>th, .table-bordered table>tbody>tr>td {\r\n    border-top: 1px solid #ddd!important;\r\n    border-bottom: 1px solid #ddd;\r\n}\r\n\r\n.fixed-table-footer {\r\n\tborder-top: 0px solid #ddd;\r\n}\r\n\r\n.fixed-table-container {\r\n\tborder: 0px solid #ddd;\r\n}\r\n\r\n.table-striped .table>thead>tr>th, .table-striped .table>tbody>tr>th {\r\n\tborder-bottom: 1px solid #ccc!important;\r\n\tborder-top: 0px!important;\r\n\tfont-weight: normal;\r\n\tfont-size: 13px\r\n}\r\n\r\n.table-striped table thead {\r\n    background-color: #eff3f8;\r\n}\r\n\r\n.fixed-table-container thead th  >.both{\r\n    display: inline-block\r\n}\r\n\r\n.editable-input .input-sm {\r\n\theight: 32px!important;\r\n}\r\n\r\n/** 表格列宽拖动样式 **/\r\n.rc-handle-container {\r\n  position: relative;\r\n}\r\n.rc-handle {\r\n  position: absolute;\r\n  width: 7px;\r\n  cursor: ew-resize;\r\n  margin-left: -3px;\r\n  z-index: 2;\r\n}\r\ntable.rc-table-resizing {\r\n  cursor: ew-resize;\r\n}\r\ntable.rc-table-resizing thead,\r\ntable.rc-table-resizing thead > th,\r\ntable.rc-table-resizing thead > th > a {\r\n  cursor: ew-resize;\r\n}\r\n\r\n/** 表格冻结列样式 **/\r\n.fixed-columns, .fixed-columns-right {\r\n  position: absolute;\r\n  top: 0;\r\n  height: 100%;\r\n  background-color: #fff;\r\n  box-sizing: border-box;\r\n  z-index: 1;\r\n  border-width: 0 0 0 1px;\r\n  -webkit-box-shadow: 0 0 10px rgba(0,0,0,.12);\r\n  box-shadow: 0 0 10px rgba(0,0,0,.12);\r\n}\r\n\r\n.fixed-columns {\r\n  left: 0;\r\n}\r\n\r\n.fixed-columns .fixed-table-body {\r\n  overflow: hidden !important;\r\n}\r\n\r\n.fixed-columns-right {\r\n  right: 0;\r\n}\r\n\r\n.fixed-columns-right .fixed-table-body {\r\n  overflow-x: hidden !important;\r\n}\r\n\r\n.bootstrap-table .table-hover > tbody > tr.hover > td {\r\n    background-color: #f5f5f5;\r\n}\r\n\r\n/** 表格树样式 **/\r\n.bootstrap-tree-table .treetable-indent {width:16px; height: 16px; display: inline-block; position: relative;}\r\n.bootstrap-tree-table .treetable-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;}\r\n.bootstrap-tree-table .treetable-selected{background: #f5f5f5 !important;}\r\n.bootstrap-tree-table .treetable-table{border:0 !important;margin-bottom:0}\r\n.bootstrap-tree-table .treetable-table tbody {display:block;height:auto;overflow-y:auto;}\r\n.bootstrap-tree-table .treetable-table thead, .treetable-table tbody tr {display:table;width:100%;table-layout:fixed;}\r\n.bootstrap-tree-table .treetable-thead th{line-height:24px;border: 0 !important;border-radius: 4px;border-left:0px solid #e7eaec !important;border-bottom:1px solid #ccc!important;text-align: left;}\r\n.bootstrap-tree-table .treetable-thead tr :first-child{border-left:0 !important}\r\n.bootstrap-tree-table .treetable-tbody td{border: 0 !important;border-left:0px solid #e7eaec !important;border-bottom:1px solid #e7eaec!important;white-space: nowrap; text-overflow: ellipsis;}\r\n.bootstrap-tree-table .treetable-tbody tr :first-child{border-left:0 !important}\r\n.bootstrap-tree-table .treetable-bars .tool-left, .bootstrap-tree-table .treetable-bars .tool-right{margin-top: 10px; margin-bottom: 10px;}\r\n.bootstrap-tree-table .treetable-bars .tool-left{float: left;}\r\n.bootstrap-tree-table .treetable-bars .tool-right{float: right;}\r\n.bootstrap-tree-table .treetable-bars .columns li label{display: block;padding: 3px 20px;clear: both;font-weight: 400;line-height: 1.428571429;max-width: 100%;margin-bottom: 5px;cursor:pointer;}\r\n.bootstrap-tree-table .table{border-bottom: 0px solid #e7eaec!important;}\r\n.bootstrap-tree-table .table-bordered .treetable-thead th {border-left: 1px solid #e7eaec!important;}\r\n.bootstrap-tree-table .table-bordered .treetable-tbody td {border-right: 1px solid #e7eaec!important;}\r\n.bootstrap-tree-table .fixed-table-pagination .pagination-detail {margin-top: 10px;margin-bottom: 10px;}\r\n\r\n/** 首页样式 **/\r\n.ax_close_max {\r\n\tposition: fixed;\r\n\ttop: 5px;\r\n\tleft: 5px;\r\n\tz-index: 9999;\r\n\tdisplay: none;\r\n\tcolor: #ccc;\r\n}\r\n.navbar-right > .user-menu > .dropdown-menu {\r\n\tborder-top-right-radius:0;\r\n\tborder-top-left-radius:0;\r\n\tpadding:1px 0 0 0;\r\n\tborder-top-width:0;\r\n\twidth:138px;\r\n}\r\n.navbar-right > .user-menu .user-image {\r\n\tfloat:left;\r\n\twidth:27px;\r\n\theight:27px;\r\n\tborder-radius:50%;\r\n\tmargin-right:8px;\r\n\tmargin-top:-3px;\r\n}\r\n@media (max-width:767px) {\r\n\t.navbar-right > .user-menu .user-image {\r\n\tfloat:none;\r\n\tmargin-right:0;\r\n\tmargin-top:-8px;\r\n\tline-height:10px;\r\n}\r\n}.dropdown-menu > li > a > .glyphicon,.dropdown-menu > li > a > .fa,.dropdown-menu > li > a > .ion {\r\n\tmargin-right:10px;\r\n}\r\n.dropdown-menu > li > a:hover {\r\n\tbackground-color:#e1e3e9;\r\n\tcolor:#333;\r\n}\r\n.dropdown-menu > .divider {\r\n\tbackground-color:#eee;\r\n}\r\n\r\n/** 表单布局 **/\r\n.form-header {\r\n    font-size:15px;\r\n\tcolor:#6379bb;\r\n\tborder-bottom:1px solid #ddd;\r\n\tmargin:8px 10px 25px 10px;\r\n\tpadding-bottom:5px\r\n}\r\n\r\n.form-control-plaintext {\r\n    display: block;\r\n    width: 100%;\r\n    padding-top: .286rem;\r\n    padding-bottom: .286rem;\r\n    margin-bottom: 0;\r\n    line-height: 1.57142857;\r\n    color: #212529;\r\n    background-color: transparent;\r\n    border: solid transparent;\r\n    border-width: 1px 0;\r\n    font-weight: 500;\r\n    border-bottom: 1px dashed #ccd5db;\r\n    min-height: 25px\r\n}\r\n\r\n.form-control-plaintext-no-content {\r\n    display: block;\r\n    width: 100%;\r\n    padding-top: .286rem;\r\n    padding-bottom: .286rem;\r\n    margin-bottom: 0;\r\n    line-height: 1.57142857;\r\n    color: #ddd !important;\r\n    background-color: transparent;\r\n    border: solid transparent;\r\n    border-width: 1px 0;\r\n    border-bottom: 1px dashed #ccd5db;\r\n    min-height: 25px\r\n}\r\n\r\n.main-content {\r\n    background-color: #ffffff;\r\n    color: inherit;\r\n    padding: 10px 15px 15px 15px;\r\n    border-color: #e7eaec;\r\n    -webkit-border-image: none;\r\n    -o-border-image: none;\r\n    border-image: none;\r\n    border-width: 1px 0px;\r\n}\r\n\r\n/** 表格跳转样式 **/\r\n.pageGo input {\r\n    height: 32px;\r\n    width: 50px;\r\n    margin-left: 5px;\r\n    margin-right: 5px;\r\n    text-align: center;\r\n    display: block;\r\n    float:left;\r\n}\r\n.pageGo button {\r\n    height: 32px;\r\n    display: block;\r\n    float:left;\r\n}\r\n\r\n/** 表格行拖拽样式 **/\r\n.reorder-rows-on-drag-class td {\r\n    color:yellow!important;\r\n\tbackground-color:#999!important;\r\n\ttext-shadow:0 0 10px black,0 0 10px black,0 0 8px black,0 0 6px black,0 0 6px black;\r\n\tbox-shadow:0 12px 14px -12px #111 inset,0 -2px 2px -1px #333 inset\r\n}\r\n\r\n/** 表格列拖拽样式 **/\r\n.dragtable-sortable {\r\n    list-style-type: none; margin: 0; padding: 0; -moz-user-select: none;\r\n}\r\n\r\n.dragtable-sortable li {\r\n    margin: 0; padding: 0; float: left; font-size: 1em; background: white;\r\n}\r\n\r\n.dragtable-sortable th, .dragtable-sortable td{\r\n    border-left: 0px;\r\n}\r\n\r\n.dragtable-sortable li:first-child th, .dragtable-sortable li:first-child td {\r\n    border-left: 1px solid #CCC;\r\n}\r\n\r\n.ui-sortable-helper {\r\n    opacity: 0.7;filter: alpha(opacity=70);\r\n}\r\n\r\n.ui-sortable-placeholder {\r\n    -moz-box-shadow: 4px 5px 4px #C6C6C6 inset;\r\n    -webkit-box-shadow: 4px 5px 4px #C6C6C6 inset;\r\n    box-shadow: 4px 5px 4px #C6C6C6 inset;\r\n    border-bottom: 1px solid #CCCCCC;\r\n    border-top: 1px solid #CCCCCC;\r\n    visibility: visible !important;\r\n    background: #EFEFEF !important;\r\n    visibility: visible !important;\r\n}\r\n\r\n.ui-sortable-placeholder * {\r\n    opacity: 0.0; visibility: hidden;\r\n}\r\n\r\n/** 表格选中样式 **/\r\n.bootstrap-table .fixed-table-container .table tbody tr.selected td {\r\n    background-color: #E8F7FD;\r\n    color: #1890ff;\r\n}\r\n\r\n/** 滚动条样式 **/\r\n::-webkit-scrollbar-track {\r\n    background-color: #F5F5F5;\r\n}\r\n\r\n/** 气泡弹出框样式 **/\r\n.popover {\r\n\tfont-size: 13px;\r\n\tmax-width: unset;\r\n}\r\n\r\n.popover-title {\r\n\tpadding: 8px 14px;\r\n\tmargin: 0 !important;\r\n\tfont-size: 14px;\r\n\tbackground-color: #f7f7f7;\r\n\tborder-bottom: 1px solid #ebebeb;\r\n\tborder-radius: 5px 5px 0 0;\r\n}\r\n\r\n.popover-content {\r\n\tpadding: 5px;\r\n}\r\n\r\n/** 向上滚动样式 **/\r\n#scroll-up {\r\n\tborder-width: 0;\r\n\tposition: fixed;\r\n\tright: 2px;\r\n\tz-index: 99;\r\n\t-webkit-transition-duration: .3s;\r\n\ttransition-duration: .3s;\r\n\topacity: 0;\r\n\tfilter: alpha(opacity=0);\r\n\tbottom: -24px;\r\n\tvisibility: hidden;\r\n\tbackground-color: #aaa;\r\n\tcolor: #fff;\r\n\tfont-size: 14px;\r\n\tdisplay: none;\r\n}\r\n\r\n#scroll-up.display {\r\n\topacity: .7;\r\n\tfilter: alpha(opacity=70);\r\n\tbottom: 2px;\r\n\tvisibility: visible;\r\n}\r\n\r\n/* 设置菜单样式 */\r\n.menu-content {\r\n\tpadding: 10px 10px 10px 25px !important;\r\n}\r\n\r\n.tab-content > .tab-pane {\r\n    display: none;\r\n}\r\n\r\n.tab-content > .active {\r\n    display: block;\r\n}\r\n\r\n.height-full {\r\n    height: 100% !important;\r\n}\r\n\r\n/* 设置详细样式 */\r\n.detail-wrap {\r\n    max-width: 860px;\r\n    margin: 20px auto;\r\n    padding: 0 16px 32px;\r\n    font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;\r\n    font-size: 13px;\r\n    color: #333;\r\n}\r\n\r\n/* 详细分组卡片 */\r\n.detail-card {\r\n    background: #fff;\r\n    border: 1px solid #e8ecf0;\r\n    border-radius: 6px;\r\n    margin-bottom: 14px;\r\n    overflow: hidden;\r\n}\r\n.detail-card-title {\r\n    padding: 10px 18px;\r\n    background: #f7f9fb;\r\n    border-bottom: 1px solid #e8ecf0;\r\n    font-size: 13px;\r\n    font-weight: 600;\r\n    color: #555;\r\n}\r\n.detail-card-title i {\r\n    margin-right: 6px;\r\n    color: #888;\r\n}\r\n\r\n/* 详细表格行 */\r\n.detail-table {\r\n    width: 100%;\r\n    border-collapse: collapse;\r\n}\r\n.detail-table tr {\r\n    border-bottom: 1px solid #f0f2f5;\r\n}\r\n.detail-table tr:last-child {\r\n    border-bottom: none;\r\n}\r\n.detail-table th {\r\n    width: 110px;\r\n    padding: 11px 18px;\r\n    text-align: right;\r\n    color: #888;\r\n    font-weight: normal;\r\n    vertical-align: top;\r\n    white-space: nowrap;\r\n}\r\n.detail-table td {\r\n    padding: 11px 18px 11px 0;\r\n    color: #333;\r\n    vertical-align: top;\r\n    word-break: break-all;\r\n}\r\n\r\n.detail-table tr td+th {\r\n    border-left:1px solid #f0f2f5;\r\n    padding-left:18px\r\n}\r\n\r\n/* 详细状态标签 */\r\n.tag-ok {\r\n    display: inline-block;\r\n    padding: 2px 10px;\r\n    background: #f0faf4;\r\n    color: #27ae60;\r\n    border: 1px solid #b7dfca;\r\n    border-radius: 3px;\r\n    font-size: 12px;\r\n}\r\n.tag-err {\r\n    display: inline-block;\r\n    padding: 2px 10px;\r\n    background: #fff5f5;\r\n    color: #e74c3c;\r\n    border: 1px solid #f5c6c6;\r\n    border-radius: 3px;\r\n    font-size: 12px;\r\n}\r\n\r\n/* 设置滚动条样式 */\r\n::-webkit-scrollbar {\r\n   width:10px!important;\r\n   height:10px!important;\r\n   -webkit-appearance:none;\r\n   background:#f1f1f1\r\n}\r\n\r\n::-webkit-scrollbar-thumb {\r\n    height:5px;\r\n    border:1px solid transparent;\r\n    border-top:0;\r\n    border-bottom:0;\r\n    border-radius:6px;\r\n    background-color:#ccc;\r\n    background-clip:padding-box\r\n}\r\n\r\n/* 设置placeholder样式 */\r\n::-webkit-input-placeholder {\r\n\tcolor: #b3b3b3!important;\r\n}\r\n\r\n:-moz-placeholder {\r\n\tcolor: #b3b3b3!important;\r\n}\r\n\r\n::-moz-placeholder {\r\n\tcolor: #b3b3b3!important;\r\n}\r\n\r\n:-ms-input-placeholder {\r\n\tcolor: #b3b3b3!important;\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ruoyi/index.js",
    "content": "/**\n * 首页方法封装处理\n * Copyright (c) 2019 ruoyi\n */\nvar isMobile = false;\nvar sidebarHeight = isMobile ? '100%' : '96%';\n\n$(function() {\n    // MetsiMenu\n    $('#side-menu').metisMenu();\n\n    // 固定菜单栏\n    $('.sidebar-collapse').slimScroll({\n        height: sidebarHeight,\n        railOpacity: 0.9,\n        alwaysVisible: false\n    });\n\n    // 菜单切换\n    $('.navbar-minimalize').click(function() {\n    \tif (isMobile) {\n    \t    $(\"body\").toggleClass(\"canvas-menu\");\n    \t} else {\n    \t    $(\"body\").toggleClass(\"mini-navbar\");\n    \t}\n        SmoothlyMenu();\n    });\n\n    $('#side-menu>li').click(function() {\n    \tif ($('body').hasClass('canvas-menu mini-navbar')) {\n            NavToggle();\n        }\n\n    });\n    $('#side-menu>li li a:not(:has(span))').click(function() {\n        if ($(window).width() < 769) {\n            NavToggle();\n        }\n    });\n\n    $('.nav-close').click(NavToggle);\n\n    //ios浏览器兼容性处理\n    if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {\n        $('#content-main').css('overflow-y', 'auto');\n    }\n\n});\n\n$(window).bind(\"load resize\", function() {\n    isMobile = $.common.isMobile() || $(window).width() < 769;\n    if (isMobile) {\n        $('body').addClass('canvas-menu');\n        $(\"body\").removeClass(\"mini-navbar\");\n        $(\"nav .logo\").addClass(\"hide\");\n        $(\".slimScrollDiv\").css({ \"overflow\": \"hidden\" });\n        $('.navbar-static-side').fadeOut();\n    } else {\n    \tif ($('body').hasClass('canvas-menu')) {\n    \t    $('body').addClass('fixed-sidebar');\n    \t    $('body').removeClass('canvas-menu');\n    \t    $(\"body\").removeClass(\"mini-navbar\");\n    \t    $(\"nav .logo\").removeClass(\"hide\");\n    \t    $(\".slimScrollDiv\").css({ \"overflow\": \"visible\" });\n    \t    $('.navbar-static-side').fadeIn();\n    \t}\n    }\n});\n\nfunction openToCurrentTab(obj) {\n    // 懒加载：若 iframe 还没有 src（如首页初始 iframe），激活时赋值\n    if (!$(obj).attr('src') && $(obj).data('id')) {\n        $(obj).attr('src', $(obj).data('id'));\n    }\n    if (isScrollToTop) {\n        $(obj).show().siblings('.RuoYi_iframe').hide();\n    } else {\n        $(obj).css({\"visibility\": \"visible\", \"position\": \"static\"}).siblings('.RuoYi_iframe').css({\"visibility\": \"hidden\", \"position\": \"absolute\", \"left\": \"0\", \"top\": \"0\"});\n    }\n}\n\nfunction syncMenuTab(dataId) {\n    if (isLinkage) {\n        var $dataObj = $('a[href$=\"' + decodeURI(dataId) + '\"]');\n        if ($dataObj.attr(\"class\") != null && !$dataObj.hasClass(\"noactive\")) {\n            $('.tab-pane li').removeClass(\"active\");\n            $('.nav ul').removeClass(\"in\");\n            $dataObj.parents(\"ul\").addClass(\"in\")\n            $dataObj.parents(\"li\").addClass(\"active\").siblings().removeClass(\"active\").find('li').removeClass(\"active\");\n            $dataObj.parents(\"ul\").css('height', 'auto').height();\n            $(\".nav ul li, .nav li\").removeClass(\"selected\");\n            $dataObj.parent(\"li\").addClass(\"selected\");\n            setIframeUrl(dataId);\n            \n            // 顶部菜单同步处理\n            var tabStr = $dataObj.parents(\".tab-pane\").attr(\"id\");\n            if ($.common.isNotEmpty(tabStr)) {\n                var sepIndex = tabStr.lastIndexOf('_');\n                var menuId = tabStr.substring(sepIndex + 1, tabStr.length);\n                $(\"#tab_\" + menuId + \" a\").click();\n            }\n        }\n    }\n}\n\nfunction NavToggle() {\n    $('.navbar-minimalize').trigger('click');\n}\n\nfunction fixedSidebar() {\n    $('#side-menu').hide();\n    $(\"nav .logo\").addClass(\"hide\");\n    setTimeout(function() {\n        $('#side-menu').fadeIn(500);\n    }, 100);\n}\n\n// 设置锚点\nfunction setIframeUrl(href) {\n\tif ($.common.equals(\"history\", mode)) {\n\t    storage.set('publicPath', href);\n\t} else {\n\t    var nowUrl = window.location.href;\n\t    var newUrl = nowUrl.substring(0, nowUrl.indexOf(\"#\"));\n\t    window.location.href = newUrl + \"#\" + href;\n\t}\n}\n\nfunction SmoothlyMenu() {\n    if (isMobile && !$('body').hasClass('canvas-menu')) {\n    \t$('.navbar-static-side').fadeIn();\n    \tfixedSidebar();\n    } else if (!isMobile &&!$('body').hasClass('mini-navbar')) {\n    \tfixedSidebar();\n    \t$(\"nav .logo\").removeClass(\"hide\");\n    } else if (isMobile && $('body').hasClass('fixed-sidebar')) {\n    \t$('.navbar-static-side').fadeOut();\n    \tfixedSidebar();\n    } else if (!isMobile && $('body').hasClass('fixed-sidebar')) {\n    \tfixedSidebar();\n    } else {\n        $('#side-menu').removeAttr('style');\n    }\n}\n\n/**\n * iframe处理\n */\n$(function() {\n    //计算元素集合的总宽度\n    function calSumWidth(elements) {\n        var width = 0;\n        $(elements).each(function() {\n            width += $(this).outerWidth(true);\n        });\n        return width;\n    }\n\n    // 激活指定选项卡\n    function setActiveTab(element) {\n        if (!$(element).hasClass('active')) {\n            var currentId = $(element).data('id');\n            syncMenuTab(currentId);\n            // 显示tab对应的内容区\n            $('.RuoYi_iframe').each(function() {\n                if ($(this).data('id') == currentId) {\n                    openToCurrentTab(this);\n                }\n            });\n            $(element).addClass('active').siblings('.menuTab').removeClass('active');\n            scrollToTab(element);\n        }\n    }\n\n    //滚动到指定选项卡\n    function scrollToTab(element) {\n        var marginLeftVal = calSumWidth($(element).prevAll()),\n        marginRightVal = calSumWidth($(element).nextAll());\n        // 可视区域非tab宽度\n        var tabOuterWidth = calSumWidth($(\".content-tabs\").children().not(\".menuTabs\"));\n        //可视区域tab宽度\n        var visibleWidth = $(\".content-tabs\").outerWidth(true) - tabOuterWidth;\n        //实际滚动宽度\n        var scrollVal = 0;\n        if ($(\".page-tabs-content\").outerWidth() < visibleWidth) {\n            scrollVal = 0;\n        } else if (marginRightVal <= (visibleWidth - $(element).outerWidth(true) - $(element).next().outerWidth(true))) {\n            if ((visibleWidth - $(element).next().outerWidth(true)) > marginRightVal) {\n                scrollVal = marginLeftVal;\n                var tabElement = element;\n                while ((scrollVal - $(tabElement).outerWidth()) > ($(\".page-tabs-content\").outerWidth() - visibleWidth)) {\n                    scrollVal -= $(tabElement).prev().outerWidth();\n                    tabElement = $(tabElement).prev();\n                }\n            }\n        } else if (marginLeftVal > (visibleWidth - $(element).outerWidth(true) - $(element).prev().outerWidth(true))) {\n            scrollVal = marginLeftVal - $(element).prev().outerWidth(true);\n        }\n        $('.page-tabs-content').animate({ marginLeft: 0 - scrollVal + 'px' }, \"fast\");\n    }\n\n    //查看左侧隐藏的选项卡\n    function scrollTabLeft() {\n        var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left')));\n        // 可视区域非tab宽度\n        var tabOuterWidth = calSumWidth($(\".content-tabs\").children().not(\".menuTabs\"));\n        //可视区域tab宽度\n        var visibleWidth = $(\".content-tabs\").outerWidth(true) - tabOuterWidth;\n        //实际滚动宽度\n        var scrollVal = 0;\n        if (($(\".page-tabs-content\").width()) < visibleWidth) {\n            return false;\n        } else {\n            var tabElement = $(\".menuTab:first\");\n            var offsetVal = 0;\n            while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) { //找到离当前tab最近的元素\n                offsetVal += $(tabElement).outerWidth(true);\n                tabElement = $(tabElement).next();\n            }\n            offsetVal = 0;\n            if (calSumWidth($(tabElement).prevAll()) > visibleWidth) {\n                while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) {\n                    offsetVal += $(tabElement).outerWidth(true);\n                    tabElement = $(tabElement).prev();\n                }\n                scrollVal = calSumWidth($(tabElement).prevAll());\n            }\n        }\n        $('.page-tabs-content').animate({ marginLeft: 0 - scrollVal + 'px' }, \"fast\");\n    }\n\n    //查看右侧隐藏的选项卡\n    function scrollTabRight() {\n        var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left')));\n        // 可视区域非tab宽度\n        var tabOuterWidth = calSumWidth($(\".content-tabs\").children().not(\".menuTabs\"));\n        //可视区域tab宽度\n        var visibleWidth = $(\".content-tabs\").outerWidth(true) - tabOuterWidth;\n        //实际滚动宽度\n        var scrollVal = 0;\n        if ($(\".page-tabs-content\").width() < visibleWidth) {\n            return false;\n        } else {\n            var tabElement = $(\".menuTab:first\");\n            var offsetVal = 0;\n            while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) { //找到离当前tab最近的元素\n                offsetVal += $(tabElement).outerWidth(true);\n                tabElement = $(tabElement).next();\n            }\n            offsetVal = 0;\n            while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) {\n                offsetVal += $(tabElement).outerWidth(true);\n                tabElement = $(tabElement).next();\n            }\n            scrollVal = calSumWidth($(tabElement).prevAll());\n            if (scrollVal > 0) {\n                $('.page-tabs-content').animate({ marginLeft: 0 - scrollVal + 'px' }, \"fast\");\n            }\n        }\n    }\n\n    //通过遍历给菜单项加上data-index属性\n    $(\".menuItem\").each(function(index) {\n        if (!$(this).attr('data-index')) {\n            $(this).attr('data-index', index);\n        }\n    });\n\n    function menuItem() {\n        // 获取标识数据\n        var dataUrl = $(this).attr('href'),\n        dataIndex = $(this).data('index'),\n        menuName = $(this).data('title') || $.trim($(this).text()),\n        isRefresh = $(this).data(\"refresh\"),\n        flag = true;\n\n        var $dataObj = $('a[href$=\"' + decodeURI(dataUrl) + '\"]');\n        if (!$dataObj.hasClass(\"noactive\")) {\n            $('.tab-pane li').removeClass(\"active\");\n            $('.nav ul').removeClass(\"in\");\n            $dataObj.parents(\"ul\").addClass(\"in\")\n            $dataObj.parents(\"li\").addClass(\"active\").siblings().removeClass(\"active\").find('li').removeClass(\"active\");\n            $dataObj.parents(\"ul\").css('height', 'auto').height();\n            $(\".nav ul li, .nav li\").removeClass(\"selected\");\n            $(this).parent(\"li\").addClass(\"selected\");\n        }\n        setIframeUrl(dataUrl);\n        if (dataUrl == undefined || $.trim(dataUrl).length == 0) return false;\n\n        // 选项卡菜单已存在\n        $('.menuTab').each(function() {\n            if ($(this).data('id') == dataUrl) {\n                if (!$(this).hasClass('active')) {\n                    $(this).addClass('active').siblings('.menuTab').removeClass('active');\n                    scrollToTab(this);\n                    // 显示tab对应的内容区\n                    $('.mainContent .RuoYi_iframe').each(function() {\n                        if ($(this).data('id') == dataUrl) {\n                            openToCurrentTab(this);\n                            return false;\n                        }\n                    });\n                }\n                if (isRefresh) {\n                    refreshTab();\n                }\n                flag = false;\n                return false;\n            }\n        });\n        // 选项卡菜单不存在\n        if (flag) {\n            var str = '<a href=\"javascript:;\" class=\"active menuTab\" data-id=\"' + dataUrl + '\">' + menuName + ' <i class=\"fa fa-times-circle\"></i></a>';\n            $('.menuTab').removeClass('active');\n\n            // 添加选项卡对应的iframe\n            var str1 = '<iframe class=\"RuoYi_iframe\" name=\"iframe' + dataIndex + '\" width=\"100%\" height=\"100%\" src=\"' + dataUrl + '\" frameborder=\"0\" data-id=\"' + dataUrl + '\" data-refresh=\"' + isRefresh + '\" seamless></iframe>';\n            if (isScrollToTop) {\n                $('.mainContent').find('iframe.RuoYi_iframe').hide();\n            } else {\n                $('.mainContent').find('iframe.RuoYi_iframe').css({\"visibility\": \"hidden\", \"position\": \"absolute\", \"left\": \"0\", \"top\": \"0\"});\n            }\n            $('.mainContent').append(str1);\n            \n            $.modal.loading(\"数据加载中，请稍候...\");\n\n            $('.mainContent iframe:visible').on('load', function() {\n            \t$.modal.closeLoading();\n            });\n\n            // 添加选项卡\n            $('.menuTabs .page-tabs-content').append(str);\n            scrollToTab($('.menuTab.active'));\n        }\n        return false;\n    }\n\n    function menuBlank() {\n    \t// 新窗口打开外网以http://开头，如http://ruoyi.vip\n    \tvar dataUrl = $(this).attr('href');\n    \twindow.open(dataUrl);\n    \treturn false;\n    }\n\n    $('.menuItem').on('click', menuItem);\n\n    $('.menuBlank').on('click', menuBlank);\n\n    // 关闭选项卡菜单\n    function closeTab() {\n        var closeTabId = $(this).parents('.menuTab').data('id');\n        var currentWidth = $(this).parents('.menuTab').width();\n        var panelUrl = $(this).parents('.menuTab').data('panel');\n        // 当前元素处于活动状态\n        if ($(this).parents('.menuTab').hasClass('active')) {\n\n            // 当前元素后面有同辈元素，使后面的一个元素处于活动状态\n            if ($(this).parents('.menuTab').next('.menuTab').length) {\n\n                var activeId = $(this).parents('.menuTab').next('.menuTab:eq(0)').data('id');\n                $(this).parents('.menuTab').next('.menuTab:eq(0)').addClass('active');\n\n                $('.mainContent .RuoYi_iframe').each(function() {\n                    if ($(this).data('id') == activeId) {\n                        openToCurrentTab(this);\n                        return false;\n                    }\n                });\n\n                var marginLeftVal = parseInt($('.page-tabs-content').css('margin-left'));\n                if (marginLeftVal < 0) {\n                    $('.page-tabs-content').animate({ marginLeft: (marginLeftVal + currentWidth) + 'px' }, \"fast\");\n                }\n\n                //  移除当前选项卡\n                $(this).parents('.menuTab').remove();\n\n                // 移除tab对应的内容区\n                $('.mainContent .RuoYi_iframe').each(function() {\n                    if ($(this).data('id') == closeTabId) {\n                        $(this).remove();\n                        return false;\n                    }\n                });\n            }\n\n            // 当前元素后面没有同辈元素，使当前元素的上一个元素处于活动状态\n            if ($(this).parents('.menuTab').prev('.menuTab').length) {\n                var activeId = $(this).parents('.menuTab').prev('.menuTab:last').data('id');\n                $(this).parents('.menuTab').prev('.menuTab:last').addClass('active');\n                $('.mainContent .RuoYi_iframe').each(function() {\n                    if ($(this).data('id') == activeId) {\n                        openToCurrentTab(this);\n                        return false;\n                    }\n                });\n\n                //  移除当前选项卡\n                $(this).parents('.menuTab').remove();\n\n                // 移除tab对应的内容区\n                $('.mainContent .RuoYi_iframe').each(function() {\n                    if ($(this).data('id') == closeTabId) {\n                        $(this).remove();\n                        return false;\n                    }\n                });\n\n                if ($.common.isNotEmpty(panelUrl)) {\n            \t\t$('.menuTab[data-id=\"' + panelUrl + '\"]').addClass('active').siblings('.menuTab').removeClass('active');\n            \t\t$('.mainContent .RuoYi_iframe').each(function() {\n                        if ($(this).data('id') == panelUrl) {\n                            openToCurrentTab(this);\n                            return false;\n                        }\n                    });\n            \t}\n            }\n        }\n        // 当前元素不处于活动状态\n        else {\n            //  移除当前选项卡\n            $(this).parents('.menuTab').remove();\n\n            // 移除相应tab对应的内容区\n            $('.mainContent .RuoYi_iframe').each(function() {\n                if ($(this).data('id') == closeTabId) {\n                    $(this).remove();\n                    return false;\n                }\n            });\n        }\n        scrollToTab($('.menuTab.active'));\n        syncMenuTab($.common.isNotEmpty(panelUrl) ? panelUrl : $('.page-tabs-content').find('.active').attr('data-id'));\n        return false;\n    }\n\n    $('.menuTabs').on('click', '.menuTab i', closeTab);\n\n    //滚动到已激活的选项卡\n    function showActiveTab() {\n        scrollToTab($('.menuTab.active'));\n    }\n    $('.tabShowActive').on('click', showActiveTab);\n\n    // 点击选项卡菜单\n    function activeTab() {\n        if (!$(this).hasClass('active')) {\n            var currentId = $(this).data('id');\n            var isRefresh = false;\n            syncMenuTab(currentId);\n            // 显示tab对应的内容区\n            $('.mainContent .RuoYi_iframe').each(function() {\n                if ($(this).data('id') == currentId) {\n                    openToCurrentTab(this);\n                    isRefresh = $.common.nullToDefault($(this).data('refresh'), false);\n                    return false;\n                }\n            });\n            $(this).addClass('active').siblings('.menuTab').removeClass('active');\n            if (isRefresh) {\n                refreshTab();\n            }\n            scrollToTab(this);\n        }\n    }\n\n    // 点击选项卡菜单\n    $('.menuTabs').on('click', '.menuTab', activeTab);\n\n    // 刷新iframe\n    function refreshTab() {\n    \tvar currentId = $('.page-tabs-content').find('.active').attr('data-id');\n    \tvar target = $('.RuoYi_iframe[data-id=\"' + currentId + '\"]');\n        var url = target.attr('src');\n    \ttarget.attr('src', url).ready();\n    }\n\n    // 页签全屏\n    function fullScreenTab() {\n    \tvar currentId = $('.page-tabs-content').find('.active').attr('data-id');\n    \tvar target = $('.RuoYi_iframe[data-id=\"' + currentId + '\"]');\n    \ttarget.fullScreen(true);\n    }\n\n    // 关闭当前选项卡\n    function tabCloseCurrent() {\n    \t$('.page-tabs-content').find('.active i').trigger(\"click\");\n    }\n\n    //关闭其他选项卡\n    function tabCloseOther() {\n        $('.page-tabs-content').children(\"[data-id]\").not(\":first\").not(\".active\").each(function() {\n            $('.RuoYi_iframe[data-id=\"' + $(this).data('id') + '\"]').remove();\n            $(this).remove();\n        });\n        $('.page-tabs-content').animate({ marginLeft: '0px' }, \"fast\");\n    }\n\n    // 关闭全部选项卡\n    function tabCloseAll() {\n    \t$('.page-tabs-content').children(\"[data-id]\").not(\":first\").each(function() {\n            $('.RuoYi_iframe[data-id=\"' + $(this).data('id') + '\"]').remove();\n            $(this).remove();\n        });\n        $('.page-tabs-content').children(\"[data-id]:first\").each(function() {\n            if (isScrollToTop) {\n                $('.RuoYi_iframe[data-id=\"' + $(this).data('id') + '\"]').show();\n            } else {\n                $('.RuoYi_iframe[data-id=\"' + $(this).data('id') + '\"]').css({\"visibility\": \"visible\", \"position\": \"static\"});\n            }\n            $(this).addClass(\"active\");\n        });\n        $('.page-tabs-content').css(\"margin-left\", \"0\");\n        syncMenuTab($('.page-tabs-content').find('.active').attr('data-id'));\n    }\n\n\n    // 全屏显示\n    $('#fullScreen').on('click', function () {\n    \t$(document).toggleFullScreen();\n    });\n    \n    // 锁定屏幕\n    $('#lockScreen').on('click', function () {\n    \tstorage.set('lockPath', $('.page-tabs-content').find('.active').attr('data-id'));\n    \tlocation.href  = ctx + \"lockscreen\";\n    });\n\n    // 页签刷新按钮\n    $('.tabReload').on('click', refreshTab);\n\n    // 页签全屏按钮\n    $('.tabFullScreen').on('click', fullScreenTab);\n\n    // 双击选项卡全屏显示\n    $('.menuTabs').on('dblclick', '.menuTab', activeTabMax);\n\n    // 左移按扭\n    $('.tabLeft').on('click', scrollTabLeft);\n\n    // 右移按扭\n    $('.tabRight').on('click', scrollTabRight);\n\n    // 关闭当前\n    $('.tabCloseCurrent').on('click', tabCloseCurrent);\n\n    // 关闭其他\n    $('.tabCloseOther').on('click', tabCloseOther);\n\n    // 关闭全部\n    $('.tabCloseAll').on('click', tabCloseAll);\n\n    // tab全屏显示\n    $('.tabMaxCurrent').on('click', function () {\n        $('.page-tabs-content').find('.active').trigger(\"dblclick\");\n    });\n\n    // 关闭全屏\n    $('#ax_close_max').click(function(){\n    \t$('#content-main').toggleClass('max');\n    \t$('#ax_close_max').hide();\n    })\n\n    // 双击选项卡全屏显示\n    function activeTabMax() {\n        $('#content-main').toggleClass('max');\n        $('#ax_close_max').show();\n    }\n\n    $(window).keydown(function(event) {\n        if (event.keyCode == 27) {\n            $('#content-main').removeClass('max');\n            $('#ax_close_max').hide();\n        }\n    });\n\n    window.onhashchange = function() {\n        var hash = location.hash;\n        var url = hash.substring(1, hash.length);\n        $('a[href$=\"' + url + '\"]').click();\n    };\n\n    // 右键菜单实现\n    $.contextMenu({\n        selector: \".menuTab\",\n        trigger: 'right',\n        autoHide: true,\n        items: {\n            \"close_current\": {\n                name: \"关闭当前\",\n                icon: \"fa-close\",\n                callback: function(key, opt) {\n                    opt.$trigger.find('i').trigger(\"click\");\n                }\n            },\n            \"close_other\": {\n                name: \"关闭其他\",\n                icon: \"fa-window-close-o\",\n                callback: function(key, opt) {\n                    setActiveTab(this);\n                    tabCloseOther();\n                }\n            },\n            \"close_left\": {\n                name: \"关闭左侧\",\n                icon: \"fa-reply\",\n                callback: function(key, opt) {\n                    setActiveTab(this);\n                    this.prevAll('.menuTab').not(\":last\").each(function() {\n                        if ($(this).hasClass('active')) {\n                            setActiveTab(this);\n                        }\n                        $('.RuoYi_iframe[data-id=\"' + $(this).data('id') + '\"]').remove();\n                        $(this).remove();\n                    });\n                    $('.page-tabs-content').animate({ marginLeft: '0px' }, \"fast\");\n                }\n            },\n            \"close_right\": {\n                name: \"关闭右侧\",\n                icon: \"fa-share\",\n                callback: function(key, opt) {\n                    setActiveTab(this);\n                    this.nextAll('.menuTab').each(function() {\n                        $('.RuoYi_iframe[data-id=\"' + $(this).data('id') + '\"]').remove();\n                        $(this).remove();\n                    });\n                }\n            },\n            \"close_all\": {\n                name: \"全部关闭\",\n                icon: \"fa-window-close\",\n                callback: function(key, opt) {\n                    tabCloseAll();\n                }\n            },\n            \"step\": \"---------\",\n            \"full\": {\n                name: \"全屏显示\",\n                icon: \"fa-arrows-alt\",\n                callback: function(key, opt) {\n                    setActiveTab(this);\n                    var target = $('.RuoYi_iframe[data-id=\"' + this.data('id') + '\"]');\n                    target.fullScreen(true);\n                }\n            },\n            \"refresh\": {\n                name: \"刷新页面\",\n                icon: \"fa-refresh\",\n                callback: function(key, opt) {\n                    setActiveTab(this);\n                    var target = $('.RuoYi_iframe[data-id=\"' + this.data('id') + '\"]');\n                    var url = target.attr('src');\n                    $.modal.loading(\"数据加载中，请稍候...\");\n                    target.attr('src', url).on('load', function() {\n                    \t$.modal.closeLoading();\n                    });\n                }\n            },\n            \"open\": {\n                name: \"新窗口打开\",\n                icon: \"fa-link\",\n                callback: function(key, opt) {\n                    var target = $('.RuoYi_iframe[data-id=\"' + this.data('id') + '\"]');\n                    window.open(target.attr('src'));\n                }\n            },\n        }\n    });\n});\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ruoyi/js/common.js",
    "content": "/**\n * 通用方法封装处理\n * Copyright (c) 2019 ruoyi \n */\n\nvar startLayDate;\nvar endLayDate;\nvar isScrollToTop = parent.isScrollToTop;\n\n$(function() {\n\t\n    // 回到顶部绑定\n    if ($.fn.toTop !== undefined) {\n        $('#scroll-up').toTop();\n    }\n\t\n    // select2复选框事件绑定\n    if ($.fn.select2 !== undefined) {\n        $.fn.select2.defaults.set( \"theme\", \"bootstrap\" );\n        $(\"select.form-control:not(.noselect2)\").each(function () {\n            $(this).select2().on(\"change\", function () {\n                $(this).valid();\n            })\n        })\n    }\n\t\n    // iCheck单选框及复选框事件绑定\n    if ($.fn.iCheck !== undefined) {\n        $(\".check-box:not(.noicheck),.radio-box:not(.noicheck)\").each(function() {\n            $(this).iCheck({\n                checkboxClass: 'icheckbox-blue',\n                radioClass: 'iradio-blue',\n            })\n        })\n    }\n\t\n    // 取消回车自动提交表单\n    $(document).on(\"keypress\", \":input:not(textarea):not([type=submit])\", function(event) {\n        if (event.keyCode == 13) {\n            event.preventDefault();\n        }\n    });\n\t \n    // laydate 时间控件绑定\n    if ($(\".select-time\").length > 0 && $('#startTime').length > 0 && $('#endTime').length > 0) {\n       layui.use('laydate', function() {\n            var laydate = layui.laydate;\n            startLayDate = laydate.render({\n                elem: '#startTime',\n                max: $('#endTime').val(),\n                theme: 'molv',\n                type: $('#startTime').attr(\"data-type\") || 'date',\n                trigger: 'click',\n                done: function(value, date) {\n                    // 结束时间大于开始时间\n                    if (value !== '') {\n                        endLayDate.config.min.year = date.year;\n                        endLayDate.config.min.month = date.month - 1;\n                        endLayDate.config.min.date = date.date;\n                    } else {\n                        endLayDate.config.min.year = '';\n                        endLayDate.config.min.month = '';\n                        endLayDate.config.min.date = '';\n                    }\n                    $('#endTime').trigger('click');\n                }\n            });\n            endLayDate = laydate.render({\n                elem: '#endTime',\n                min: $('#startTime').val(),\n                theme: 'molv',\n                type: $('#endTime').attr(\"data-type\") || 'date',\n                trigger: 'click',\n                done: function(value, date) {\n                    // 开始时间小于结束时间\n                    if (value !== '') {\n                        startLayDate.config.max.year = date.year;\n                        startLayDate.config.max.month = date.month - 1;\n                        startLayDate.config.max.date = date.date;\n                    } else {\n                        startLayDate.config.max.year = '2099';\n                        startLayDate.config.max.month = '12';\n                        startLayDate.config.max.date = '31';\n                    }\n                }\n            });\n        });\n    }\n\t\n    // laydate time-input 时间控件绑定\n    if ($(\".time-input\").length > 0) {\n        layui.use('laydate', function () {\n            var com = layui.laydate;\n            $(\".time-input\").each(function (index, item) {\n                var time = $(item);\n                // 控制控件外观\n                var type = time.attr(\"data-type\") || 'date';\n                // 控制回显格式\n                var format = time.attr(\"data-format\") || 'yyyy-MM-dd';\n                // 控制日期控件按钮\n                var buttons = time.attr(\"data-btn\") || 'clear|now|confirm', newBtnArr = [];\n                // 日期控件选择完成后回调处理\n                var callback = time.attr(\"data-callback\") || {};\n                if (buttons) {\n                    if (buttons.indexOf(\"|\") > 0) {\n                        var btnArr = buttons.split(\"|\"), btnLen = btnArr.length;\n                        for (var j = 0; j < btnLen; j++) {\n                            if (\"clear\" === btnArr[j] || \"now\" === btnArr[j] || \"confirm\" === btnArr[j]) {\n                                newBtnArr.push(btnArr[j]);\n                            }\n                        }\n                    } else {\n                        if (\"clear\" === buttons || \"now\" === buttons || \"confirm\" === buttons) {\n                            newBtnArr.push(buttons);\n                        }\n                    }\n                } else {\n                    newBtnArr = ['clear', 'now', 'confirm'];\n                }\n                com.render({\n                    elem: item,\n                    theme: 'molv',\n                    trigger: 'click',\n                    type: type,\n                    format: format,\n                    btns: newBtnArr,\n                    done: function (value, data) {\n                        if (typeof window[callback] != 'undefined'\n                            && window[callback] instanceof Function) {\n                            window[callback](value, data);\n                        }\n                    }\n                });\n            });\n        });\n    }\n\t\n    // tree 关键字搜索绑定\n    if ($(\"#keyword\").length > 0) {\n        $(\"#keyword\").bind(\"focus\", function focusKey(e) {\n            if ($(\"#keyword\").hasClass(\"empty\")) {\n                $(\"#keyword\").removeClass(\"empty\");\n            }\n        }).bind(\"blur\", function blurKey(e) {\n            if ($(\"#keyword\").val() === \"\") {\n                $(\"#keyword\").addClass(\"empty\");\n            }\n            $.tree.searchNode(e);\n        }).bind(\"input propertychange\", $.tree.searchNode);\n    }\n\t\n    // tree表格树 展开/折叠\n    var expandFlag;\n    $(\"#expandAllBtn\").click(function() {\n        var dataExpand = $.common.isEmpty(table.options.expandAll) ? true : table.options.expandAll;\n        expandFlag = $.common.isEmpty(expandFlag) ? dataExpand : expandFlag;\n        if (!expandFlag) {\n            $.bttTable.bootstrapTreeTable('expandAll');\n        } else {\n            $.bttTable.bootstrapTreeTable('collapseAll');\n        }\n        expandFlag = expandFlag ? false: true;\n    })\n\t\n    // 按下ESC按钮关闭弹层\n    $('body', document).on('keyup', function(e) {\n        if (e.which === 27) {\n            $.modal.closeAll();\n        }\n    });\n});\n\n(function ($) {\n    'use strict';\n    $.fn.toTop = function(opt) {\n        var elem = this;\n        var win = (opt && opt.hasOwnProperty('win')) ? opt.win : $(window);\n        var doc = (opt && opt.hasOwnProperty('doc')) ? opt.doc : $('html, body');\n        var options = $.extend({\n            autohide: true,\n            offset: 50,\n            speed: 500,\n            position: true,\n            right: 15,\n            bottom: 5\n        }, opt);\n        elem.css({\n            'cursor': 'pointer'\n        });\n        if (options.autohide) {\n            elem.css('display', 'none');\n        }\n        if (options.position) {\n            elem.css({\n                'position': 'fixed',\n                'right': options.right,\n                'bottom': options.bottom,\n            });\n        }\n        elem.click(function() {\n            doc.animate({\n                scrollTop: 0\n            }, options.speed);\n        });\n        win.scroll(function() {\n            var scrolling = win.scrollTop();\n            if (options.autohide) {\n                if (scrolling > options.offset) {\n                    elem.fadeIn(options.speed);\n                } else elem.fadeOut(options.speed);\n            }\n        });\n    };\n})(jQuery);\n\n/** 刷新选项卡 */\nvar refreshItem = function(){\n    var topWindow = $(window.parent.document);\n    var currentId = $('.page-tabs-content', topWindow).find('.active').attr('data-id');\n    var target = $('.RuoYi_iframe[data-id=\"' + currentId + '\"]', topWindow);\n    var url = target.attr('src');\n    target.attr('src', url).ready();\n}\n\n/** 关闭选项卡 */\nvar closeItem = function(dataId){\n\tvar topWindow = $(window.parent.document);\n\tif ($.common.isNotEmpty(dataId)) {\n\t    window.parent.$.modal.closeLoading();\n\t    // 根据dataId关闭指定选项卡\n\t    $('.menuTab[data-id=\"' + dataId + '\"]', topWindow).remove();\n\t    // 移除相应tab对应的内容区\n\t    $('.mainContent .RuoYi_iframe[data-id=\"' + dataId + '\"]', topWindow).remove();\n\t    return;\n\t}\n\tvar panelUrl = window.frameElement.getAttribute('data-panel');\n\t$('.page-tabs-content .active i', topWindow).click();\n\tif ($.common.isNotEmpty(panelUrl)) {\n\t    $('.menuTab[data-id=\"' + panelUrl + '\"]', topWindow).addClass('active').siblings('.menuTab').removeClass('active');\n\t    $('.mainContent .RuoYi_iframe', topWindow).each(function() {\n\t        if ($(this).data('id') == panelUrl) {\n\t            openToCurrentTab(this);\n\t            return false;\n            }\n        });\n    }\n}\n\n/** 创建选项卡 */\nfunction createMenuItem(dataUrl, menuName, isRefresh) {\n    var panelUrl = window.frameElement.getAttribute('data-id'),\n    dataIndex = $.common.random(1, 100),\n    flag = true;\n    if (dataUrl == undefined || $.trim(dataUrl).length == 0) return false;\n    var topWindow = $(window.parent.document);\n    // 选项卡菜单已存在\n    $('.menuTab', topWindow).each(function() {\n        if ($(this).data('id') == dataUrl) {\n            if (!$(this).hasClass('active')) {\n                $(this).addClass('active').siblings('.menuTab').removeClass('active');\n                scrollToTab(this);\n                $('.page-tabs-content').animate({ marginLeft: \"\"}, \"fast\");\n                // 显示tab对应的内容区\n                $('.mainContent .RuoYi_iframe', topWindow).each(function() {\n                    if ($(this).data('id') == dataUrl) {\n                        openToCurrentTab(this);\n                        return false;\n                    }\n                });\n            }\n            if (isRefresh) {\n                refreshTab();\n            }\n            flag = false;\n            return false;\n        }\n    });\n    // 选项卡菜单不存在\n    if (flag) {\n        var str = '<a href=\"javascript:;\" class=\"active menuTab noactive\" data-id=\"' + dataUrl + '\" data-panel=\"' + panelUrl + '\">' + menuName + ' <i class=\"fa fa-times-circle\"></i></a>';\n        $('.menuTab', topWindow).removeClass('active');\n\n        // 添加选项卡对应的iframe\n        var str1 = '<iframe class=\"RuoYi_iframe\" name=\"iframe' + dataIndex + '\" width=\"100%\" height=\"100%\" src=\"' + dataUrl + '\" frameborder=\"0\" data-id=\"' + dataUrl + '\" data-panel=\"' + panelUrl + '\" seamless></iframe>';\n        if (isScrollToTop) {\n            $('.mainContent', topWindow).find('iframe.RuoYi_iframe').hide();\n        } else {\n            $('.mainContent', topWindow).find('iframe.RuoYi_iframe').css({\"visibility\": \"hidden\", \"position\": \"absolute\", \"left\": \"0\", \"top\": \"0\"});\n        }\n        $('.mainContent', topWindow).append(str1);\n        \n        window.parent.$.modal.loading(\"数据加载中，请稍候...\");\n        $('.mainContent iframe:visible', topWindow).on('load', function() {\n            window.parent.$.modal.closeLoading();\n        });\n\n        // 添加选项卡\n        $('.menuTabs .page-tabs-content', topWindow).append(str);\n        scrollToTab($('.menuTab.active', topWindow));\n    }\n    return false;\n}\n\n// 刷新iframe\nfunction refreshTab() {\n\tvar topWindow = $(window.parent.document);\n\tvar currentId = $('.page-tabs-content', topWindow).find('.active').attr('data-id');\n\tvar target = $('.RuoYi_iframe[data-id=\"' + currentId + '\"]', topWindow);\n    var url = target.attr('src');\n\ttarget.attr('src', url).ready();\n}\n\n// 滚动到指定选项卡\nfunction scrollToTab(element) {\n    var topWindow = $(window.parent.document);\n    var marginLeftVal = calSumWidth($(element).prevAll()),\n    marginRightVal = calSumWidth($(element).nextAll());\n    // 可视区域非tab宽度\n    var tabOuterWidth = calSumWidth($(\".content-tabs\", topWindow).children().not(\".menuTabs\"));\n    //可视区域tab宽度\n    var visibleWidth = $(\".content-tabs\", topWindow).outerWidth(true) - tabOuterWidth;\n    //实际滚动宽度\n    var scrollVal = 0;\n    if ($(\".page-tabs-content\", topWindow).outerWidth() < visibleWidth) {\n        scrollVal = 0;\n    } else if (marginRightVal <= (visibleWidth - $(element).outerWidth(true) - $(element).next().outerWidth(true))) {\n        if ((visibleWidth - $(element).next().outerWidth(true)) > marginRightVal) {\n            scrollVal = marginLeftVal;\n            var tabElement = element;\n            while ((scrollVal - $(tabElement).outerWidth()) > ($(\".page-tabs-content\", topWindow).outerWidth() - visibleWidth)) {\n                scrollVal -= $(tabElement).prev().outerWidth();\n                tabElement = $(tabElement).prev();\n            }\n        }\n    } else if (marginLeftVal > (visibleWidth - $(element).outerWidth(true) - $(element).prev().outerWidth(true))) {\n        scrollVal = marginLeftVal - $(element).prev().outerWidth(true);\n    }\n    $('.page-tabs-content', topWindow).animate({ marginLeft: 0 - scrollVal + 'px' }, \"fast\");\n}\n\n// 计算元素集合的总宽度\nfunction calSumWidth(elements) {\n    var width = 0;\n    $(elements).each(function() {\n        width += $(this).outerWidth(true);\n    });\n    return width;\n}\n\n// 返回当前激活的Tab页面关联的iframe的Windows对象\nfunction activeWindow() {\n\tvar topWindow = $(window.parent.document);\n\tvar currentId = $('.page-tabs-content', topWindow).find('.active').attr('data-id');\n\tif (!currentId) {\n\t\treturn window.parent;\n\t}\n    return $('.RuoYi_iframe[data-id=\"' + currentId + '\"]', topWindow)[0].contentWindow;\n}\n\nfunction openToCurrentTab(obj) {\n    if (isScrollToTop) {\n        $(obj).show().siblings('.RuoYi_iframe').hide();\n    } else {\n        $(obj).css({\"visibility\": \"visible\", \"position\": \"static\"}).siblings('.RuoYi_iframe').css({\"visibility\": \"hidden\", \"position\": \"absolute\", \"left\": \"0\", \"top\": \"0\"});\n    }\n}\n\n/** 密码规则范围验证 */\nfunction checkpwd(chrtype, password) {\n    if (chrtype == 1) {\n        if (!$.common.numValid(password)) {\n            $.modal.alertWarning(\"密码只能为0-9数字\");\n            return false;\n        }\n    } else if (chrtype == 2) {\n        if (!$.common.enValid(password)) {\n            $.modal.alertWarning(\"密码只能为a-z和A-Z字母\");\n            return false;\n        }\n    } else if (chrtype == 3) {\n        if (!$.common.enNumValid(password)) {\n            $.modal.alertWarning(\"密码必须包含字母以及数字\");\n            return false;\n        }\n    } else if (chrtype == 4) {\n        if (!$.common.charValid(password)) {\n            $.modal.alertWarning(\"密码必须包含字母、数字、以及特殊符号<font color='red'>~!@#$%^&*()-=_+</font>\");\n            return false;\n        }\n    }\n    return true;\n}\n\n/** 开始时间/时分秒 */\nfunction beginOfTime(date) {\n    if ($.common.isNotEmpty(date)) {\n        return $.common.sprintf(\"%s 00:00:00\", date);\n    }\n}\n\n/** 结束时间/时分秒 */\nfunction endOfTime(date) {\n    if ($.common.isNotEmpty(date)) {\n        return $.common.sprintf(\"%s 23:59:59\", date);\n    }\n}\n\n/** 重置日期/年月日 */\nfunction resetDate() {\n\tif ($.common.isNotEmpty(startLayDate) && $.common.isNotEmpty(endLayDate)) {\n\t    endLayDate.config.min.year = '';\n\t    endLayDate.config.min.month = '';\n\t    endLayDate.config.min.date = '';\n\t    startLayDate.config.max.year = '2099';\n\t    startLayDate.config.max.month = '12';\n\t    startLayDate.config.max.date = '31';\n\t}\n}\n\n// 日志打印封装处理\nvar log = {\n    log: function(msg) {\n        console.log(msg);\n    },\n    info: function(msg) {\n        console.info(msg);\n    },\n    warn: function(msg) {\n        console.warn(msg);\n    },\n    error: function(msg) {\n        console.error(msg);\n    }\n};\n\n// 本地缓存处理\nvar storage = {\n    set: function(key, value) {\n        window.localStorage.setItem(key, value);\n    },\n    get: function(key) {\n        return window.localStorage.getItem(key);\n    },\n    remove: function(key) {\n        window.localStorage.removeItem(key);\n    },\n    clear: function() {\n        window.localStorage.clear();\n    }\n};\n\n// 主子表操作封装处理\nvar sub = {\n    editRow: function() {\n    \tvar dataColumns = [];\n\t\tfor (var columnIndex = 0; columnIndex < table.options.columns.length; columnIndex++) {\n    \t\tif (table.options.columns[columnIndex].visible != false) {\n    \t\t\tdataColumns.push(table.options.columns[columnIndex]);\n    \t\t}\n    \t}\n\t\tvar params = new Array();\n\t\tvar data = $(\"#\" + table.options.id).bootstrapTable('getData');\n    \tvar count = data.length;\n    \tfor (var dataIndex = 0; dataIndex < count; dataIndex++) {\n    \t    var columns = $('#' + table.options.id + ' tr[data-index=\"' + dataIndex + '\"] td:visible');\n    \t    var obj = new Object();\n    \t    for (var i = 0; i < columns.length; i++) {\n    \t        var inputValue = $(columns[i]).find('input');\n    \t        var selectValue = $(columns[i]).find('select');\n    \t        var textareaValue = $(columns[i]).find('textarea');\n    \t        var key = dataColumns[i].field;\n    \t        if ($.common.isNotEmpty(inputValue.val())) {\n    \t            obj[key] = inputValue.val();\n    \t        } else if ($.common.isNotEmpty(selectValue.val())) {\n    \t            obj[key] = selectValue.val();\n    \t        } else if ($.common.isNotEmpty(textareaValue.val())) {\n    \t            obj[key] = textareaValue.val();\n    \t        } else {\n    \t            if (key == \"index\" && $.common.isNotEmpty(data[dataIndex].index)) {\n    \t                obj[key] = data[dataIndex].index;\n    \t            } else {\n    \t                obj[key] = \"\";\n    \t            }\n    \t        }\n    \t    }\n    \t    var item = data[dataIndex];\n    \t    var extendObj = $.extend({}, item, obj);\n    \t    params.push({ index: dataIndex, row: extendObj });\n    \t}\n    \t$(\"#\" + table.options.id).bootstrapTable(\"updateRow\", params);\n    },\n    delRow: function(column) {\n    \tsub.editRow();\n    \tvar subColumn = $.common.isEmpty(column) ? \"index\" : column;\n    \tvar ids = $.table.selectColumns(subColumn);\n        if (ids.length == 0) {\n            $.modal.alertWarning(\"请至少选择一条记录\");\n            return;\n        }\n        $(\"#\" + table.options.id).bootstrapTable('remove', { field: subColumn, values: ids });\n    },\n    delRowByIndex: function(value, tableId) {\n    \tvar currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n    \tsub.editRow();\n        $(\"#\" + currentId).bootstrapTable('remove', { field: \"index\", values: [value] });\n        sub.editRow();\n    },\n    addRow: function(row, tableId) {\n    \tvar currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n    \ttable.set(currentId);\n    \tvar count = $(\"#\" + currentId).bootstrapTable('getData').length;\n    \tsub.editRow();\n    \t$(\"#\" + currentId).bootstrapTable('insertRow', { index: count + 1, row: row });\n    }\n};\n\n// 动态加载css文件\nfunction loadCss(file, headElem) {\n    var link = document.createElement('link');\n    link.href = file;\n    link.rel = 'stylesheet';\n    link.type = 'text/css';\n    if (headElem) headElem.appendChild(link);\n    else document.getElementsByTagName('head')[0].appendChild(link);\n}\n\n// 动态加载js文件\nfunction loadJs(file, headElem) {\n    var script = document.createElement('script');\n    script.src = file;\n    script.type = 'text/javascript';\n    if (headElem) headElem.appendChild(script);\n    else document.getElementsByTagName('head')[0].appendChild(script);\n}\n\n// 禁止后退键（Backspace）\nwindow.onload = function() {\n\tdocument.getElementsByTagName(\"body\")[0].onkeydown = function() {\n\t\t// 获取事件对象  \n\t\tvar elem = event.relatedTarget || event.srcElement || event.target || event.currentTarget;\n\t\t// 判断按键为backSpace键  \n\t\tif (event.keyCode == 8) {\n\t\t\t// 判断是否需要阻止按下键盘的事件默认传递  \n\t\t\tvar name = elem.nodeName;\n\t\t\tvar className = elem.className;\n\t\t\t// 屏蔽特定的样式名称\n\t\t\tif (className.indexOf('note-editable') != -1)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (name != 'INPUT' && name != 'TEXTAREA') {\n\t\t\t\treturn _stopIt(event);\n\t\t\t}\n\t\t\tvar type_e = elem.type.toUpperCase();\n\t\t\tif (name == 'INPUT' && (type_e != 'TEXT' && type_e != 'TEXTAREA' && type_e != 'PASSWORD' && type_e != 'FILE' && type_e != 'SEARCH' && type_e != 'NUMBER' && type_e != 'EMAIL' && type_e != 'URL')) {\n\t\t\t\treturn _stopIt(event);\n\t\t\t}\n\t\t\tif (name == 'INPUT' && (elem.readOnly == true || elem.disabled == true)) {\n\t\t\t\treturn _stopIt(event);\n\t\t\t}\n\t\t}\n\t};\n};\nfunction _stopIt(e) {\n\tif (e.returnValue) {\n\t\te.returnValue = false;\n\t}\n\tif (e.preventDefault) {\n\t\te.preventDefault();\n\t}\n\treturn false;\n}\n\n/** 设置全局ajax处理 */\n$.ajaxSetup({\n    beforeSend: function (xhr, settings) {\n        var csrftoken = $('meta[name=csrf-token]').attr('content')\n        if (($.common.equalsIgnoreCase(settings.type, \"POST\"))) {\n            xhr.setRequestHeader(\"X-CSRF-Token\", csrftoken)\n        }\n    },\n    complete: function(XMLHttpRequest, textStatus) {\n        if (textStatus == 'timeout') {\n            $.modal.alertWarning(\"服务器超时，请稍后再试！\");\n            $.modal.enable();\n            $.modal.closeLoading();\n        } else if (textStatus == \"parsererror\" || textStatus == \"error\") {\n            $.modal.alertWarning(\"服务器错误，请联系管理员！\");\n            $.modal.enable();\n            $.modal.closeLoading();\n        }\n    }\n});\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ruoyi/js/ry-ui.js",
    "content": "/**\n * 通用js方法封装处理\n * Copyright (c) 2019 ruoyi\n */\n\n// 当前table相关信息\nvar table = {\n    config: {},\n    // 当前实例配置\n    options: {},\n    // 设置实例配置\n    set: function(id) {\n        if ($.common.getLength(table.config) > 1 && $.common.isNotEmpty(event)) {\n            var tableId = $.common.isEmpty(id) ? $(event.currentTarget).parents(\".bootstrap-table\").find(\"table.table\").attr(\"id\") || $(event.currentTarget).parents(\".bootstrap-tree-table\").find(\"table.table\").attr(\"id\") : id;\n            if ($.common.isNotEmpty(tableId)) {\n                table.options = table.get(tableId);\n            }\n        }\n    },\n    // 获取实例配置\n    get: function(id) {\n        return table.config[id];\n    },\n    // 记住选择实例组\n    rememberSelecteds: {},\n    // 记住选择ID组\n    rememberSelectedIds: {}\n};\n\n(function ($) {\n    $.extend({\n        _tree: {},\n        bttTable: {},\n        // 表格封装处理\n        table: {\n            // 初始化表格参数\n            init: function(options) {\n                var defaults = {\n                    id: \"bootstrap-table\",\n                    type: 0, // 0 代表bootstrapTable 1代表bootstrapTreeTable\n                    method: 'post',\n                    height: undefined,\n                    sidePagination: \"server\",\n                    undefinedText: '-',\n                    sortName: undefined,\n                    sortOrder: \"asc\",\n                    pagination: true,\n                    paginationLoop: false,\n                    pageSize: 10,\n                    pageNumber: 1,\n                    pageList: [10, 25, 50, 100],\n                    toolbar: \"toolbar\",\n                    loadingFontSize: 13,\n                    striped: false,\n                    escape: true,\n                    firstLoad: true,\n                    showFooter: false,\n                    search: false,\n                    showSearch: true,\n                    showPageGo: false,\n                    showRefresh: true,\n                    showColumns: true,\n                    showToggle: true,\n                    showExport: false,\n                    showPrint: false,\n                    exportDataType: 'all',\n                    exportTypes: ['csv', 'txt', 'doc', 'excel'],\n                    clickToSelect: false,\n                    singleSelect: false,\n                    mobileResponsive: true,\n                    maintainSelected: false,\n                    rememberSelected: false,\n                    fixedColumns: false,\n                    fixedNumber: 0,\n                    fixedRightNumber: 0,\n                    queryParams: $.table.queryParams,\n                    rowStyle: undefined\n                };\n                var options = $.extend(defaults, options);\n                table.options = options;\n                table.config[options.id] = options;\n                $.table.initEvent();\n                $('#' + options.id).bootstrapTable({\n                    id: options.id,\n                    url: options.url,                                   // 请求后台的URL（*）\n                    contentType: \"application/x-www-form-urlencoded\",   // 编码类型\n                    method: options.method,                             // 请求方式（*）\n                    cache: false,                                       // 是否使用缓存\n                    height: options.height,                             // 表格的高度\n                    striped: options.striped,                           // 是否显示行间隔色\n                    undefinedText: options.undefinedText,               // 数据值为空时显示的内容\n                    sortable: true,                                     // 是否启用排序\n                    sortStable: true,                                   // 设置为 true 将获得稳定的排序\n                    sortName: options.sortName,                         // 排序列名称\n                    sortOrder: options.sortOrder,                       // 排序方式  asc 或者 desc\n                    pagination: options.pagination,                     // 是否显示分页（*）\n                    paginationLoop: options.paginationLoop,             // 是否启用分页条无限循环的功能\n                    pageNumber: 1,                                      // 初始化加载第一页，默认第一页\n                    pageSize: options.pageSize,                         // 每页的记录行数（*） \n                    pageList: options.pageList,                         // 可供选择的每页的行数（*）\n                    firstLoad: options.firstLoad,                       // 是否首次请求加载数据，对于数据较大可以配置false\n                    escape: options.escape,                             // 转义HTML字符串\n                    showFooter: options.showFooter,                     // 是否显示表尾\n                    iconSize: 'outline',                                // 图标大小：undefined默认的按钮尺寸 xs超小按钮sm小按钮lg大按钮\n                    toolbar: '#' + options.toolbar,                     // 指定工作栏\n                    virtualScroll: options.virtualScroll,               // 是否启动虚拟滚动（大量数据纯展示时使用)\n                    loadingFontSize: options.loadingFontSize,           // 自定义加载文本的字体大小\n                    sidePagination: options.sidePagination,             // server启用服务端分页client客户端分页\n                    search: options.search,                             // 是否显示搜索框功能\n                    searchText: options.searchText,                     // 搜索框初始显示的内容，默认为空\n                    showSearch: options.showSearch,                     // 是否显示检索信息\n                    showPageGo: options.showPageGo,                     // 是否显示跳转页\n                    showRefresh: options.showRefresh,                   // 是否显示刷新按钮\n                    showColumns: options.showColumns,                   // 是否显示隐藏某列下拉框\n                    showToggle: options.showToggle,                     // 是否显示详细视图和列表视图的切换按钮\n                    showExport: options.showExport,                     // 是否支持导出文件\n                    showPrint: options.showPrint,                       // 是否支持打印页面\n                    showHeader: options.showHeader,                     // 是否显示表头\n                    showFullscreen: options.showFullscreen,             // 是否显示全屏按钮\n                    uniqueId: options.uniqueId,                         // 唯一的标识符\n                    clickToSelect: options.clickToSelect,               // 是否启用点击选中行\n                    singleSelect: options.singleSelect,                 // 是否单选checkbox\n                    mobileResponsive: options.mobileResponsive,         // 是否支持移动端适配\n                    cardView: options.cardView,                         // 是否启用显示卡片视图\n                    detailView: options.detailView,                     // 是否启用显示细节视图\n                    onCheck: options.onCheck,                           // 当选择此行时触发\n                    onUncheck: options.onUncheck,                       // 当取消此行时触发\n                    onCheckAll: options.onCheckAll,                     // 当全选行时触发\n                    onUncheckAll: options.onUncheckAll,                 // 当取消全选行时触发\n                    onClickRow: options.onClickRow,                     // 点击某行触发的事件\n                    onDblClickRow: options.onDblClickRow,               // 双击某行触发的事件\n                    onClickCell: options.onClickCell,                   // 单击某格触发的事件\n                    onDblClickCell: options.onDblClickCell,             // 双击某格触发的事件\n                    onEditableSave: options.onEditableSave,             // 行内编辑保存的事件\n                    onExpandRow: options.onExpandRow,                   // 点击详细视图的事件\n                    onPostBody: options.onPostBody,                     // 渲染完成后执行的事件\n                    maintainSelected: options.maintainSelected,         // 前端翻页时保留所选行\n                    rememberSelected: options.rememberSelected,         // 启用翻页记住前面的选择\n                    fixedColumns: options.fixedColumns,                 // 是否启用冻结列（左侧）\n                    fixedNumber: options.fixedNumber,                   // 列冻结的个数（左侧）\n                    fixedRightNumber: options.fixedRightNumber,         // 列冻结的个数（右侧）\n                    onReorderRow: options.onReorderRow,                 // 当拖拽结束后处理函数\n                    queryParams: options.queryParams,                   // 传递参数（*）\n                    rowStyle: options.rowStyle,                         // 通过自定义函数设置行样式\n                    footerStyle: options.footerStyle,                   // 通过自定义函数设置页脚样式\n                    headerStyle: options.headerStyle,                   // 通过自定义函数设置标题样式\n                    selectItemName: options.selectItemName,             // 自定义radio/checkbox的name值\n                    columns: options.columns,                           // 显示列信息（*）\n                    data: options.data,                                 // 被加载的数据\n                    responseHandler: $.table.responseHandler,           // 在加载服务器发送来的数据之前处理函数\n                    onLoadSuccess: $.table.onLoadSuccess,               // 当所有数据被加载时触发处理函数\n                    exportOptions: options.exportOptions,               // 前端导出忽略列索引\n                    exportDataType: options.exportDataType,             // 导出方式（默认all：导出所有数据；basic：导出当前页的数据；selected：导出选中的数据）\n                    exportTypes: options.exportTypes,                   // 导出文件类型 （json、xml、png、csv、txt、sql、doc、excel、xlsx、powerpoint、pdf）\n                    printPageBuilder: options.printPageBuilder,         // 自定义打印页面模板\n                    detailFormatter: options.detailFormatter,           // 在行下面展示其他数据列表\n                });\n            },\n            // 获取实例ID，如存在多个返回#id1,#id2 delimeter分隔符\n            getOptionsIds: function(separator) {\n                var _separator = $.common.isEmpty(separator) ? \",\" : separator;\n                var optionsIds = \"\";  \n                $.each(table.config, function(key, value){\n                    optionsIds += \"#\" + key + _separator;\n                });\n                return optionsIds.substring(0, optionsIds.length - 1);\n            },\n            // 查询条件\n            queryParams: function(params) {\n                table.set();\n                var curParams = {\n                    // 传递参数查询参数\n                    pageSize:       params.limit,\n                    pageNum:        params.offset / params.limit + 1,\n                    searchValue:    params.search,\n                    orderByColumn:  params.sort,\n                    isAsc:          params.order\n                };\n                var currentId = $.common.isEmpty(table.options.formId) ? $('form').attr('id') : table.options.formId;\n                return $.extend(curParams, $.common.formToJSON(currentId)); \n            },\n            // 请求获取数据后处理回调函数\n            responseHandler: function(res) {\n                if (typeof table.get(this.id).responseHandler == \"function\") {\n                    table.get(this.id).responseHandler(res);\n                }\n                var thisOptions = table.config[this.id];\n                if (res.code == web_status.SUCCESS) {\n                    if ($.common.isNotEmpty(thisOptions.sidePagination) && thisOptions.sidePagination == 'client') {\n                        return res.rows;\n                    } else {\n                        if ($.common.isNotEmpty(thisOptions.rememberSelected) && thisOptions.rememberSelected) {\n                            var column = $.common.isEmpty(thisOptions.uniqueId) ? thisOptions.columns[1].field : thisOptions.uniqueId;\n                            $.each(res.rows, function(i, row) {\n                                row.state = $.inArray(row[column], table.rememberSelectedIds[thisOptions.id]) !== -1;\n                            })\n                        }\n                        return { rows: res.rows, total: res.total };\n                    }\n                } else {\n                    $.modal.alertWarning(res.msg);\n                    return { rows: [], total: 0 };\n                }\n            },\n            // 初始化事件\n            initEvent: function() {\n                // 实例ID信息\n                var optionsIds = $.table.getOptionsIds();\n                // 监听事件处理\n                $(optionsIds).on(TABLE_EVENTS, function () {\n                    table.set($(this).attr(\"id\"));\n                });\n                // 在表格体渲染完成，并在 DOM 中可见后触发（事件）\n                $(optionsIds).on(\"post-body.bs.table\", function (e, args) {\n                    // 浮动提示框特效\n                    $(\".table [data-toggle='tooltip']\").tooltip();\n                    // 气泡弹出框特效\n                    $('.table [data-toggle=\"popover\"]').popover();\n                });\n                // 选中、取消、全部选中、全部取消（事件）\n                $(optionsIds).on(\"check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table\", function (e, rowsAfter, rowsBefore) {\n                    // 复选框分页保留保存选中数组\n                    var rows = $.common.equals(\"uncheck-all\", e.type) ? rowsBefore : rowsAfter;\n                    var rowIds = $.table.affectedRowIds(rows);\n                    if ($.common.isNotEmpty(table.options.rememberSelected) && table.options.rememberSelected) {\n                        func = $.inArray(e.type, ['check', 'check-all']) > -1 ? 'union' : 'difference';\n                        var selectedIds = table.rememberSelectedIds[table.options.id];\n                        if ($.common.isNotEmpty(selectedIds)) {\n                            table.rememberSelectedIds[table.options.id] = _[func](selectedIds, rowIds);\n                        } else {\n                            table.rememberSelectedIds[table.options.id] = _[func]([], rowIds);\n                        }\n                        var selectedRows = table.rememberSelecteds[table.options.id];\n                        if ($.common.isNotEmpty(selectedRows)) {\n                            table.rememberSelecteds[table.options.id] = _[func](selectedRows, rows);\n                        } else {\n                            table.rememberSelecteds[table.options.id] = _[func]([], rows);\n                        }\n                    }\n                });\n                // 加载成功、选中、取消、全部选中、全部取消（事件）\n                $(optionsIds).on(\"check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table load-success.bs.table\", function () {\n                    var toolbar = table.options.toolbar;\n                    var uniqueId = table.options.uniqueId;\n                    // 工具栏按钮控制\n                    var rows = $.common.isEmpty(uniqueId) ? $.table.selectFirstColumns() : $.table.selectColumns(uniqueId);\n                    // 非多个禁用\n                    $('#' + toolbar + ' .multiple').toggleClass('disabled', !rows.length);\n                    // 非单个禁用\n                    $('#' + toolbar + ' .single').toggleClass('disabled', rows.length!=1);\n                });\n                // 图片预览事件\n                $(optionsIds).off(\"click\").on(\"click\", '.img-circle', function() {\n                    var src = $(this).attr('src');\n                    var target = $(this).data('target');\n                    if ($.common.equals(\"self\", target)) {\n                        var height = $(this).data('height');\n                        var width = $(this).data('width');\n                        top.layer.open({\n                            title: false,\n                            type: 1,\n                            closeBtn: true,\n                            shadeClose: true,\n                            content: \"<img src='\" + src + \"' height='\" + height + \"' width='\" + width + \"'/>\"\n                        });\n                    } else if ($.common.equals(\"blank\", target)) {\n                        window.open(src);\n                    }\n                });\n                // 单击tooltip事件\n                $(optionsIds).on(\"click\", '.tooltip-show', function() {\n                    var target = $(this).data('target');\n                    var input = $(this).prev();\n                    if ($.common.equals(\"copy\", target)) {\n                        input.select();\n                        document.execCommand(\"copy\");\n                    } else if ($.common.equals(\"open\", target)) {\n                        top.layer.alert(input.val(), {\n                            title: \"信息内容\",\n                            area: ['400px', ''],\n                            shadeClose: true,\n                            btn: ['关闭'],\n                            btnclass: ['btn btn-primary'],\n                        });\n                    }\n                });\n            },\n            // 当所有数据被加载时触发\n            onLoadSuccess: function(data) {\n                if (typeof table.options.onLoadSuccess == \"function\") {\n                    table.options.onLoadSuccess(data);\n                }\n            },\n            // 表格销毁\n            destroy: function (tableId) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                $(\"#\" + currentId).bootstrapTable('destroy');\n                delete table.rememberSelectedIds[currentId];\n                delete table.rememberSelecteds[currentId];\n            },\n            // 序列号生成\n            serialNumber: function (index, tableId) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                var tableParams = $(\"#\" + currentId).bootstrapTable('getOptions');\n                var pageSize = $.common.isNotEmpty(tableParams.pageSize) ? tableParams.pageSize: table.options.pageSize;\n                var pageNumber = $.common.isNotEmpty(tableParams.pageNumber) ? tableParams.pageNumber: table.options.pageNumber;\n                if (table.options.sidePagination == 'client') {\n                    return index + 1;\n                }\n                return pageSize * (pageNumber - 1) + index + 1;\n            },\n            // 列超出指定长度浮动提示 target（copy单击复制文本 open弹窗打开文本）\n            tooltip: function (value, length, target) {\n                var _length = $.common.isEmpty(length) ? 20 : length;\n                var _text = \"\";\n                var _value = $.common.nullToStr(value);\n                var _target = $.common.isEmpty(target) ? 'copy' : target;\n                if (_value.length > _length) {\n                    _text = _value.substr(0, _length) + \"...\";\n                    _value = _value.replace(/\\'/g,\"&apos;\");\n                    _value = _value.replace(/\\\"/g,\"&quot;\");\n                    var actions = [];\n                    actions.push($.common.sprintf('<input style=\"opacity: 0;position: absolute;z-index:-1\" type=\"text\" value=\"%s\"/>', _value));\n                    actions.push($.common.sprintf('<a href=\"###\" class=\"tooltip-show\" data-toggle=\"tooltip\" data-target=\"%s\" title=\"%s\">%s</a>', _target, _value, _text));\n                    return actions.join('');\n                } else {\n                    _text = _value;\n                    return _text;\n                }\n            },\n            // 下拉按钮切换\n            dropdownToggle: function (value) {\n                var actions = [];\n                actions.push('<div class=\"btn-group\">');\n                actions.push('<button type=\"button\" class=\"btn btn-xs dropdown-toggle\" data-toggle=\"dropdown\" aria-expanded=\"false\">');\n                actions.push('<i class=\"fa fa-cog\"></i>&nbsp;<span class=\"fa fa-chevron-down\"></span></button>');\n                actions.push('<ul class=\"dropdown-menu\">');\n                actions.push(value.replace(/<a/g,\"<li><a\").replace(/<\\/a>/g,\"</a></li>\"));\n                actions.push('</ul>');\n                actions.push('</div>');\n                return actions.join('');\n            },\n            // 图片预览\n            imageView: function (value, height, width, target) {\n                if ($.common.isEmpty(width)) {\n                    width = 'auto';\n                }\n                if ($.common.isEmpty(height)) {\n                    height = 'auto';\n                }\n                // blank or self\n                var _target = $.common.isEmpty(target) ? 'self' : target;\n                if ($.common.isNotEmpty(value)) {\n                    return $.common.sprintf(\"<img class='img-circle img-xs' data-height='%s' data-width='%s' data-target='%s' src='%s'/>\", height, width, _target, value);\n                } else {\n                    return $.common.nullToStr(value);\n                }\n            },\n            // 搜索-默认第一个form\n            search: function(formId, tableId, pageNumber, pageSize) {\n                table.set(tableId);\n                table.options.formId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;\n                var params = $.common.isEmpty(tableId) ? $(\"#\" + table.options.id).bootstrapTable('getOptions') : $(\"#\" + tableId).bootstrapTable('getOptions');\n                if ($.common.isNotEmpty(pageNumber)) {\n                    params.pageNumber = pageNumber;\n                }\n                if ($.common.isNotEmpty(pageSize)) {\n                    params.pageSize = pageSize;\n                }\n                if ($.common.isNotEmpty(tableId)) {\n                    $(\"#\" + tableId).bootstrapTable('refresh', params);\n                } else{\n                    $(\"#\" + table.options.id).bootstrapTable('refresh', params);\n                }\n            },\n            // 导出数据\n            exportExcel: function(formId) {\n                table.set();\n                $.modal.confirm(\"确定导出所有\" + table.options.modalName + \"吗？\", function() {\n                    var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;\n                    var params = $(\"#\" + table.options.id).bootstrapTable('getOptions');\n                    var dataParam = $(\"#\" + currentId).serializeArray();\n                    dataParam.push({ \"name\": \"orderByColumn\", \"value\": params.sortName });\n                    dataParam.push({ \"name\": \"isAsc\", \"value\": params.sortOrder });\n                    $.modal.loading(\"正在导出数据，请稍候...\");\n                    $.post(table.options.exportUrl, dataParam, function(result) {\n                        if (result.code == web_status.SUCCESS) {\n                            window.location.href = ctx + \"common/download?fileName=\" + encodeURI(result.msg) + \"&delete=\" + true;\n                        } else if (result.code == web_status.WARNING) {\n                            $.modal.alertWarning(result.msg)\n                        } else {\n                            $.modal.alertError(result.msg);\n                        }\n                        $.modal.closeLoading();\n                    });\n                });\n            },\n            // 下载模板\n            importTemplate: function() {\n                $.get(activeWindow().table.options.importTemplateUrl, function(result) {\n                    if (result.code == web_status.SUCCESS) {\n                        window.location.href = ctx + \"common/download?fileName=\" + encodeURI(result.msg) + \"&delete=\" + true;\n                    } else if (result.code == web_status.WARNING) {\n                        $.modal.alertWarning(result.msg)\n                    } else {\n                        $.modal.alertError(result.msg);\n                    }\n                });\n            },\n            // 导入数据\n            importExcel: function(formId, width, height) {\n                table.set();\n                var currentId = $.common.isEmpty(formId) ? 'importTpl' : formId;\n                var _width = $.common.isEmpty(width) ? \"400\" : width;\n                var _height = $.common.isEmpty(height) ? \"230\" : height;\n                top.layer.open({\n                    type: 1,\n                    area: [_width + 'px', _height + 'px'],\n                    fix: false,\n                    //不固定\n                    maxmin: true,\n                    shade: 0.3,\n                    title: '导入' + table.options.modalName + '数据',\n                    content: $('#' + currentId).html(),\n                    btn: ['<i class=\"fa fa-check\"></i> 导入', '<i class=\"fa fa-remove\"></i> 取消'],\n                    // 弹层外区域关闭\n                    shadeClose: true,\n                    btn1: function(index, layero){\n                        var file = layero.find('#file').val();\n                        if (file == '' || (!$.common.endWith(file, '.xls') && !$.common.endWith(file, '.xlsx'))) {\n                            $.modal.msgWarning(\"请选择后缀为 “xls”或“xlsx”的文件。\");\n                            return false;\n                        }\n                        var index = top.layer.load(2, {shade: false});\n                        $.modal.disable();\n                        var formData = new FormData(layero.find('form')[0]);\n                        $.ajax({\n                            url: table.options.importUrl,\n                            data: formData,\n                            cache: false,\n                            contentType: false,\n                            processData: false,\n                            type: 'POST',\n                            success: function (result) {\n                                if (result.code == web_status.SUCCESS) {\n                                \t$.modal.close(index);\n                                    $.modal.closeAll();\n                                    $.modal.alertSuccess(result.msg);\n                                    $.table.refresh();\n                                } else if (result.code == web_status.WARNING) {\n                                \t$.modal.close(index);\n                                    $.modal.enable();\n                                    $.modal.alertWarning(result.msg)\n                                } else {\n                                    $.modal.close(index);\n                                    $.modal.enable();\n                                    $.modal.alertError(result.msg);\n                                }\n                            },\n                            complete: function () {\n                            \tlayero.find('#file').val('');\n                            }\n                        });\n                    }\n                });\n            },\n            // 刷新表格\n            refresh: function(tableId, pageNumber, pageSize, url) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                var params = $(\"#\" + currentId).bootstrapTable('getOptions');\n                if ($.common.isEmpty(pageNumber)) {\n                    pageNumber = params.pageNumber;\n                }\n                if ($.common.isEmpty(pageSize)) {\n                    pageSize = params.pageSize;\n                }\n                if ($.common.isEmpty(url)) {\n                    url = $.common.isEmpty(url) ? params.url : url;\n                }\n                $(\"#\" + currentId).bootstrapTable('refresh', {\n                    silent: true,\n                    url: url,\n                    pageNumber: pageNumber,\n                    pageSize: pageSize\n                });\n            },\n            // 刷新options配置\n            refreshOptions: function(options, tableId) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                $(\"#\" + currentId).bootstrapTable('refreshOptions', options);\n            },\n            // 查询表格指定列值 deDuplication（ true去重、false不去重）\n            selectColumns: function(column, deDuplication) {\n                var distinct = $.common.isEmpty(deDuplication) ? true : deDuplication;\n                var rows = $.map($(\"#\" + table.options.id).bootstrapTable('getSelections'), function (row) {\n                    return $.common.getItemField(row, column);\n                });\n                if ($.common.isNotEmpty(table.options.rememberSelected) && table.options.rememberSelected) {\n                    var selectedRows = table.rememberSelecteds[table.options.id];\n                    if ($.common.isNotEmpty(selectedRows)) {\n                        rows = $.map(table.rememberSelecteds[table.options.id], function (row) {\n                            return $.common.getItemField(row, column);\n                        });\n                    }\n                }\n                return distinct ? $.common.uniqueFn(rows) : rows;\n            },\n            // 获取当前页选中或者取消的行ID\n            affectedRowIds: function(rows) {\n                var column = $.common.isEmpty(table.options.uniqueId) ? table.options.columns[1].field : table.options.uniqueId;\n                var rowIds;\n                if ($.isArray(rows)) {\n                    rowIds = $.map(rows, function(row) {\n                        return $.common.getItemField(row, column);\n                    });\n                } else {\n                    rowIds = [rows[column]];\n                }\n                return rowIds;\n            },\n            // 查询表格首列值deDuplication（ true去重、false不去重）\n            selectFirstColumns: function(deDuplication) {\n                var distinct = $.common.isEmpty(deDuplication) ? true : deDuplication;\n                var rows = $.map($(\"#\" + table.options.id).bootstrapTable('getSelections'), function (row) {\n                    return $.common.getItemField(row, table.options.columns[1].field);\n                });\n                if ($.common.isNotEmpty(table.options.rememberSelected) && table.options.rememberSelected) {\n                    var selectedRows = table.rememberSelecteds[table.options.id];\n                    if ($.common.isNotEmpty(selectedRows)) {\n                        rows = $.map(selectedRows, function (row) {\n                            return $.common.getItemField(row, table.options.columns[1].field);\n                        });\n                    }\n                }\n                return distinct ? $.common.uniqueFn(rows) : rows;\n            },\n            // 回显数据字典\n            selectDictLabel: function(datas, value) {\n                if ($.common.isEmpty(datas) || $.common.isEmpty(value)) {\n                    return '';\n                }\n                var actions = [];\n                $.each(datas, function(index, dict) {\n                    if (dict.dictValue == ('' + value)) {\n                        var listClass = $.common.equals(\"default\", dict.listClass) || $.common.isEmpty(dict.listClass) ? \"\" : \"badge badge-\" + dict.listClass;\n                        var cssClass = $.common.isNotEmpty(dict.cssClass) ? dict.cssClass : listClass;\n                        actions.push($.common.sprintf(\"<span class='%s'>%s</span>\", cssClass, dict.dictLabel));\n                        return false;\n                    }\n                });\n                if (actions.length === 0) {\n                    actions.push($.common.sprintf(\"<span>%s</span>\", value))\n                }\n                return actions.join('');\n            },\n            // 回显数据字典（字符串数组）\n            selectDictLabels: function(datas, value, separator) {\n                if ($.common.isEmpty(datas) || $.common.isEmpty(value)) {\n                    return '';\n                }\n                var currentSeparator = $.common.isEmpty(separator) ? \",\" : separator;\n                var actions = [];\n                $.each(value.split(currentSeparator), function(i, val) {\n                    var match = false\n                    $.each(datas, function(index, dict) {\n                        if (dict.dictValue == ('' + val)) {\n                            var listClass = $.common.equals(\"default\", dict.listClass) || $.common.isEmpty(dict.listClass) ? \"\" : \"badge badge-\" + dict.listClass;\n                            actions.push($.common.sprintf(\"<span class='%s'>%s</span>\", listClass, dict.dictLabel));\n                            match = true\n                            return false;\n                        }\n                    });\n                    if (!match) {\n                        actions.push($.common.sprintf(\"<span> %s </span>\", val));\n                    }\n                });\n                return actions.join('');\n            },\n            // 显示表格指定列\n            showColumn: function(column, tableId) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                $(\"#\" + currentId).bootstrapTable('showColumn', column);\n            },\n            // 隐藏表格指定列\n            hideColumn: function(column, tableId) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                $(\"#\" + currentId).bootstrapTable('hideColumn', column);\n            },\n            // 显示所有表格列\n            showAllColumns: function(tableId) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                $(\"#\" + currentId).bootstrapTable('showAllColumns');\n            },\n            // 隐藏所有表格列\n            hideAllColumns: function(tableId) {\n                var currentId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                $(\"#\" + currentId).bootstrapTable('hideAllColumns');\n            }\n        },\n        // 表格树封装处理\n        treeTable: {\n            // 初始化表格\n            init: function(options) {\n                var defaults = {\n                    id: \"bootstrap-tree-table\",\n                    type: 1, // 0 代表bootstrapTable 1代表bootstrapTreeTable\n                    height: 0,\n                    rootIdValue: 0,\n                    ajaxParams: {},\n                    toolbar: \"toolbar\",\n                    striped: false,\n                    pagination: false,\n                    pageSize: 10,\n                    pageList: [10, 25, 50],\n                    expandColumn: 1,\n                    showSearch: true,\n                    showRefresh: true,\n                    showColumns: true,\n                    expandAll: true,\n                    expandFirst: true\n                };\n                var options = $.extend(defaults, options);\n                table.options = options;\n                table.config[options.id] = options;\n                $.table.initEvent();\n                $.bttTable = $('#' + options.id).bootstrapTreeTable({\n                    code: options.code,                                 // 用于设置父子关系\n                    parentCode: options.parentCode,                     // 用于设置父子关系\n                    type: 'post',                                       // 请求方式（*）\n                    url: options.url,                                   // 请求后台的URL（*）\n                    data: options.data,                                 // 无url时用于渲染的数据\n                    ajaxParams: options.ajaxParams,                     // 请求数据的ajax的data属性\n                    rootIdValue: options.rootIdValue,                   // 设置指定根节点id值\n                    height: options.height,                             // 表格树的高度\n                    pagination: options.pagination,                     // 是否显示分页\n                    dataUrl: options.dataUrl,                           // 加载子节点异步请求数据url\n                    pageSize: options.pageSize,                         // 每页的记录行数\n                    pageList: options.pageList,                         // 可供选择的每页的行数\n                    expandColumn: options.expandColumn,                 // 在哪一列上面显示展开按钮\n                    striped: options.striped,                           // 是否显示行间隔色\n                    bordered: options.bordered,                         // 是否显示边框\n                    toolbar: '#' + options.toolbar,                     // 指定工作栏\n                    showSearch: options.showSearch,                     // 是否显示检索信息\n                    showRefresh: options.showRefresh,                   // 是否显示刷新按钮\n                    showColumns: options.showColumns,                   // 是否显示隐藏某列下拉框\n                    expandAll: options.expandAll,                       // 是否全部展开\n                    expandFirst: options.expandFirst,                   // 是否默认第一级展开--expandAll为false时生效\n                    columns: options.columns,                           // 显示列信息（*）\n                    onClickRow: options.onClickRow,                     // 单击某行事件\n                    responseHandler: $.treeTable.responseHandler,       // 在加载服务器发送来的数据之前处理函数\n                    onLoadSuccess: $.treeTable.onLoadSuccess            // 当所有数据被加载时触发处理函数\n                });\n            },\n            // 条件查询\n            search: function(formId) {\n                var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;\n                var params = $.common.formToJSON(currentId);\n                $.bttTable.bootstrapTreeTable('refresh', $.extend(params, table.options.ajaxParams));\n            },\n            // 刷新\n            refresh: function() {\n                $.bttTable.bootstrapTreeTable('refresh');\n            },\n            // 查询表格树指定列值deDuplication（ true去重、false不去重）\n            selectColumns: function(column, deDuplication) {\n                var distinct = $.common.isEmpty(deDuplication) ? true : deDuplication;\n                var rows = $.map($.bttTable.bootstrapTreeTable('getSelections'), function (row) {\n                    return $.common.getItemField(row, column);\n                });\n                return distinct ? $.common.uniqueFn(rows) : rows;\n            },\n            // 请求获取数据后处理回调函数，校验异常状态提醒\n            responseHandler: function(res) {\n                if (typeof table.options.responseHandler == \"function\") {\n                    table.options.responseHandler(res);\n                }\n                if (res.code != undefined && res.code != web_status.SUCCESS) {\n                    $.modal.alertWarning(res.msg);\n                    return [];\n                } else {\n                    return res;\n                }\n            },\n            // 当所有数据被加载时触发\n            onLoadSuccess: function(data) {\n                if (typeof table.options.onLoadSuccess == \"function\") {\n                    table.options.onLoadSuccess(data);\n                }\n                $(\".table [data-toggle='tooltip']\").tooltip();\n            },\n        },\n        // 表单封装处理\n        form: {\n            // 表单重置\n            reset: function(formId, tableId, pageNumber, pageSize) {\n                table.set(tableId);\n                formId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;\n                $(\"#\" + formId)[0].reset();\n                var tableId = $.common.isEmpty(tableId) ? table.options.id : tableId;\n                if (table.options.type == table_type.bootstrapTable) {\n                    var params = $(\"#\" + tableId).bootstrapTable('getOptions');\n                    params.pageNumber = 1;\n                    if ($.common.isNotEmpty(pageSize)) {\n                        params.pageSize = pageSize;\n                    }\n                    $(\"#\" + tableId).bootstrapTable('refresh', params);\n                } else if (table.options.type == table_type.bootstrapTreeTable) {\n                    $(\"#\" + tableId).bootstrapTreeTable('refresh', table.options.ajaxParams);\n                }\n                resetDate();\n            },\n            // 获取选中复选框项\n            selectCheckeds: function(name) {\n                var checkeds = \"\";\n                $('input:checkbox[name=\"' + name + '\"]:checked').each(function(i) {\n                    if (0 == i) {\n                        checkeds = $(this).val();\n                    } else {\n                        checkeds += (\",\" + $(this).val());\n                    }\n                });\n                return checkeds;\n            },\n            // 获取选中下拉框项\n            selectSelects: function(name) {\n                var selects = \"\";\n                $('#' + name + ' option:selected').each(function (i) {\n                    if (0 == i) {\n                        selects = $(this).val();\n                    } else {\n                        selects += (\",\" + $(this).val());\n                    }\n                });\n                return selects;\n            }\n        },\n        // 弹出层封装处理\n        modal: {\n            // 显示图标\n            icon: function(type) {\n                var icon = \"\";\n                if (type == modal_status.WARNING) {\n                    icon = 0;\n                } else if (type == modal_status.SUCCESS) {\n                    icon = 1;\n                } else if (type == modal_status.FAIL) {\n                    icon = 2;\n                } else {\n                    icon = 3;\n                }\n                return icon;\n            },\n            // 消息提示\n            msg: function(content, type) {\n                if (type != undefined) {\n                \ttop.layer.msg(content, { icon: $.modal.icon(type), time: 1000, shift: 5 });\n                } else {\n                \ttop.layer.msg(content);\n                }\n            },\n            // 错误消息\n            msgError: function(content) {\n                $.modal.msg(content, modal_status.FAIL);\n            },\n            // 成功消息\n            msgSuccess: function(content) {\n                $.modal.msg(content, modal_status.SUCCESS);\n            },\n            // 警告消息\n            msgWarning: function(content) {\n                $.modal.msg(content, modal_status.WARNING);\n            },\n            // 弹出提示\n            alert: function(content, type) {\n                top.layer.alert(content, {\n                    icon: $.modal.icon(type),\n                    title: \"系统提示\",\n                    btn: ['关闭'],\n                    btnclass: ['btn btn-primary'],\n                });\n            },\n            // 错误提示\n            alertError: function(content) {\n                $.modal.alert(content, modal_status.FAIL);\n            },\n            // 成功提示\n            alertSuccess: function(content) {\n                $.modal.alert(content, modal_status.SUCCESS);\n            },\n            // 警告提示\n            alertWarning: function(content) {\n                $.modal.alert(content, modal_status.WARNING);\n            },\n            // 消息提示，重新加载页面\n            msgReload: function(msg, type) {\n                top.layer.msg(msg, {\n                    icon: $.modal.icon(type),\n                    time: 500,\n                    shade: [0.1, '#8F8F8F']\n                },\n                function() {\n                    $.modal.reload();\n                });\n            },\n            // 消息提示成功并刷新父窗体\n            msgSuccessReload: function(msg) {\n            \t$.modal.msgReload(msg, modal_status.SUCCESS);\n            },\n            // 获取iframe页的DOM\n            getChildFrame: function (index) {\n                if ($.common.isEmpty(index)) {\n                    var index = parent.layer.getFrameIndex(window.name);\n                    return parent.layer.getChildFrame('body', index);\n                } else {\n                    return top.layer.getChildFrame('body', index);\n                }\n            },\n            // 关闭窗体\n            close: function (index) {\n                if ($.common.isEmpty(index)) {\n                    var index = parent.layer.getFrameIndex(window.name);\n                    parent.layer.close(index);\n                } else {\n                    top.layer.close(index);\n                }\n            },\n            // 关闭全部窗体\n            closeAll: function () {\n                top.layer.closeAll();\n            },\n            // 确认窗体\n            confirm: function (content, callBack) {\n                top.layer.confirm(content, {\n                    icon: 3,\n                    title: \"系统提示\",\n                    btn: ['确认', '取消']\n                }, function (index) {\n                    $.modal.close(index);\n                    callBack(true);\n                });\n            },\n            // 弹出层指定宽度\n            open: function (title, url, width, height, callback) {\n                // 如果是移动端，就使用自适应大小弹窗\n                if ($.common.isMobile()) {\n                    width = 'auto';\n                    height = 'auto';\n                }\n                if ($.common.isEmpty(title)) {\n                    title = false;\n                }\n                if ($.common.isEmpty(url)) {\n                    url = \"/404.html\";\n                }\n                if ($.common.isEmpty(width)) {\n                    width = 800;\n                }\n                if ($.common.isEmpty(height)) {\n                    height = ($(window).height() - 50);\n                }\n                if ($.common.isEmpty(callback)) {\n                    callback = function(index, layero) {\n                        var iframeWin = layero.find('iframe')[0];\n                        iframeWin.contentWindow.submitHandler(index, layero);\n                    }\n                }\n                top.layer.open({\n                    type: 2,\n                    area: [width + 'px', height + 'px'],\n                    fix: false,\n                    //不固定\n                    maxmin: true,\n                    shade: 0.3,\n                    title: title,\n                    content: url,\n                    btn: ['确定', '关闭'],\n                    // 弹层外区域关闭\n                    shadeClose: true,\n                    yes: callback,\n                    cancel: function(index) {\n                        return true;\n                    },\n                    success: function () {\n                        $(':focus').blur();\n                    }\n                });\n            },\n            // 弹出层指定参数选项\n            openOptions: function (options) {\n                var _url = $.common.isEmpty(options.url) ? \"/404.html\" : options.url; \n                var _title = $.common.isEmpty(options.title) ? \"系统窗口\" : options.title; \n                var _width = $.common.isEmpty(options.width) ? \"800\" : options.width; \n                var _height = $.common.isEmpty(options.height) ? ($(window).height() - 50) : options.height;\n                var _btn = ['<i class=\"fa fa-check\"></i> 确认', '<i class=\"fa fa-close\"></i> 关闭'];\n                // 如果是移动端，就使用自适应大小弹窗\n                if ($.common.isMobile()) {\n                    _width = 'auto';\n                    _height = 'auto';\n                }\n                if ($.common.isEmpty(options.yes)) {\n                    options.yes = function(index, layero) {\n                        options.callBack(index, layero);\n                    }\n                }\n                var btnCallback = {};\n                if (options.btn instanceof Array){\n                    for (var i = 1, len = options.btn.length; i < len; i++) {\n                        var btn = options[\"btn\" + (i + 1)];\n                        if (btn) {\n                            btnCallback[\"btn\" + (i + 1)] = btn;\n                        }\n                    }\n                }\n                var index = top.layer.open($.extend({\n                    id: options.id,       // 唯一id\n                    anim: options.anim,   // 弹出动画 0-6\n                    type: 2,\n                    maxmin: $.common.isEmpty(options.maxmin) ? true : options.maxmin,\n                    shade: 0.3,\n                    title: _title,\n                    fix: false,\n                    area: [_width + 'px', _height + 'px'],\n                    content: _url,\n                    closeBtn: $.common.isEmpty(options.closeBtn) ? 1 : options.closeBtn,\n                    shadeClose: $.common.isEmpty(options.shadeClose) ? true : options.shadeClose,\n                    skin: options.skin,\n                    // options.btn设置为0表示不显示按钮\n                    btn: $.common.isEmpty(options.btn) ? _btn : options.btn,\n                    yes: options.yes,\n                    cancel: function () {\n                        return true;\n                    },\n                    success: function () {\n                        $(':focus').blur();\n                    }\n                }, btnCallback));\n                if ($.common.isNotEmpty(options.full) && options.full === true) {\n                    top.layer.full(index);\n                }\n            },\n            // 弹出层全屏\n            openFull: function (title, url, width, height) {\n                // 如果是移动端，就使用自适应大小弹窗\n                if ($.common.isMobile()) {\n                    width = 'auto';\n                    height = 'auto';\n                }\n                if ($.common.isEmpty(title)) {\n                    title = false;\n                }\n                if ($.common.isEmpty(url)) {\n                    url = \"/404.html\";\n                }\n                if ($.common.isEmpty(width)) {\n                    width = 800;\n                }\n                if ($.common.isEmpty(height)) {\n                    height = ($(window).height() - 50);\n                }\n                var index = top.layer.open({\n                    type: 2,\n                    area: [width + 'px', height + 'px'],\n                    fix: false,\n                    //不固定\n                    maxmin: true,\n                    shade: 0.3,\n                    title: title,\n                    content: url,\n                    btn: ['确定', '关闭'],\n                    // 弹层外区域关闭\n                    shadeClose: true,\n                    yes: function(index, layero) {\n                        var iframeWin = layero.find('iframe')[0];\n                        iframeWin.contentWindow.submitHandler(index, layero);\n                    },\n                    cancel: function(index) {\n                        return true;\n                    },\n                    success: function () {\n                        $(':focus').blur();\n                    }\n                });\n                top.layer.full(index);\n            },\n            // 选卡页方式打开\n            openTab: function (title, url, isRefresh) {\n                createMenuItem(url, title, isRefresh);\n            },\n            // 选卡页同一页签打开\n            parentTab: function (title, url) {\n                var dataId = window.frameElement.getAttribute('data-id');\n                createMenuItem(url, title);\n                closeItem(dataId);\n            },\n            // 右侧弹出窗口打开\n            popupRight: function(title, url){\n                var width = 150;\n                if (top.location !== self.location) {\n                    if ($(top.window).outerWidth() < 400) {\n                        width = 50;\n                    }\n                }\n                top.layer.open({\n                    type: 2,\n                    offset: 'r',\n                    anim: 'slideLeft',\n                    move: false,\n                    title: title,\n                    shade: 0.3,\n                    shadeClose: true,\n                    area: [($(window).outerWidth() - width) + 'px', '100%'],\n                    content: url\n                });\n            },\n            // 关闭选项卡\n            closeTab: function (dataId) {\n                closeItem(dataId);\n            },\n            // 禁用按钮\n            disable: function() {\n                var doc = window.top == window.parent ? top.window.document : window.parent.document;\n                $(\"a[class*=layui-layer-btn]\", doc).addClass(\"layer-disabled\");\n            },\n            // 启用按钮\n            enable: function() {\n                var doc = window.top == window.parent ? top.window.document : window.parent.document;\n                $(\"a[class*=layui-layer-btn]\", doc).removeClass(\"layer-disabled\");\n            },\n            // 打开遮罩层\n            loading: function (message) {\n                $.blockUI({ message: '<div class=\"loaderbox\"><div class=\"loading-activity\"></div> ' + message + '</div>' });\n            },\n            // 关闭遮罩层\n            closeLoading: function () {\n                setTimeout(function(){\n                    $.unblockUI();\n                }, 50);\n            },\n            // 重新加载\n            reload: function () {\n                parent.location.reload();\n            }\n        },\n        // 操作封装处理\n        operate: {\n            // 提交数据\n            submit: function(url, type, dataType, data, callback) {\n                var config = {\n                    url: url,\n                    type: type,\n                    dataType: dataType,\n                    data: data,\n                    beforeSend: function (xhr, settings) {\n                        var csrftoken = $('meta[name=csrf-token]').attr('content');\n                        if ($.common.equalsIgnoreCase(settings.type, \"POST\")) {\n                            xhr.setRequestHeader(\"X-CSRF-Token\", csrftoken);\n                        }\n                        $.modal.loading(\"正在处理中，请稍候...\");\n                    },\n                    success: function(result) {\n                        if (typeof callback == \"function\") {\n                            callback(result);\n                        }\n                        $.operate.ajaxSuccess(result);\n                    }\n                };\n                $.ajax(config)\n            },\n            // post请求传输\n            post: function(url, data, callback) {\n                $.operate.submit(url, \"post\", \"json\", data, callback);\n            },\n            // get请求传输\n            get: function(url, callback) {\n                $.operate.submit(url, \"get\", \"json\", \"\", callback);\n            },\n            // 详细信息\n            detail: function(id, width, height) {\n                table.set();\n                var _url = $.operate.detailUrl(id);\n                var options = {\n                    title: table.options.modalName + \"详细\",\n                    width: width,\n                    height: height,\n                    url: _url,\n                    btn: 0,\n                    yes: function (index, layero) {\n                        $.modal.close(index);\n                    }\n                };\n                $.modal.openOptions(options);\n            },\n            // 详细信息，以tab页展现\n            detailTab: function(id) {\n                table.set();\n                $.modal.openTab(\"详细\" + table.options.modalName, $.operate.detailUrl(id));\n            },\n            // 详细访问地址\n            detailUrl: function(id) {\n                var url = \"/404.html\";\n                if ($.common.isNotEmpty(id)) {\n                    url = table.options.detailUrl.replace(\"{id}\", id);\n                } else {\n                    var id = $.common.isEmpty(table.options.uniqueId) ? $.table.selectFirstColumns() : $.table.selectColumns(table.options.uniqueId);\n                    if (id.length == 0) {\n                        $.modal.alertWarning(\"请至少选择一条记录\");\n                        return;\n                    }\n                    url = table.options.detailUrl.replace(\"{id}\", id);\n                }\n                return url;\n            },\n            // 删除信息\n            remove: function(id) {\n                table.set();\n                $.modal.confirm(\"确定删除该条\" + table.options.modalName + \"信息吗？\", function() {\n                    var url = $.common.isEmpty(id) ? table.options.removeUrl : table.options.removeUrl.replace(\"{id}\", id);\n                    if (table.options.type == table_type.bootstrapTreeTable) {\n                        $.operate.get(url);\n                    } else {\n                        var data = { \"ids\": id };\n                        $.operate.submit(url, \"post\", \"json\", data);\n                    }\n                });\n            },\n            // 批量删除信息\n            removeAll: function() {\n                table.set();\n                var rows = $.common.isEmpty(table.options.uniqueId) ? $.table.selectFirstColumns() : $.table.selectColumns(table.options.uniqueId);\n                if (rows.length == 0) {\n                    $.modal.alertWarning(\"请至少选择一条记录\");\n                    return;\n                }\n                $.modal.confirm(\"确认要删除选中的\" + rows.length + \"条数据吗?\", function() {\n                    var url = table.options.removeUrl;\n                    var data = { \"ids\": rows.join() };\n                    $.operate.submit(url, \"post\", \"json\", data);\n                });\n            },\n            // 清空信息\n            clean: function() {\n                table.set();\n                $.modal.confirm(\"确定清空所有\" + table.options.modalName + \"吗？\", function() {\n                    var url = table.options.cleanUrl;\n                    $.operate.submit(url, \"post\", \"json\", \"\");\n                });\n            },\n            // 添加信息\n            add: function(id) {\n                table.set();\n                $.modal.open(\"添加\" + table.options.modalName, $.operate.addUrl(id));\n            },\n            // 添加信息，以tab页展现\n            addTab: function (id) {\n                table.set();\n                $.modal.openTab(\"添加\" + table.options.modalName, $.operate.addUrl(id));\n            },\n            // 添加信息 全屏\n            addFull: function(id) {\n                table.set();\n                $.modal.openFull(\"添加\" + table.options.modalName, $.operate.addUrl(id));\n            },\n            // 添加访问地址\n            addUrl: function(id) {\n                var url = $.common.isEmpty(id) ? table.options.createUrl.replace(\"{id}\", \"\") : table.options.createUrl.replace(\"{id}\", id);\n                return url;\n            },\n            // 修改信息\n            edit: function(id) {\n                table.set();\n                if ($.common.isEmpty(id) && table.options.type == table_type.bootstrapTreeTable) {\n                    var row = $(\"#\" + table.options.id).bootstrapTreeTable('getSelections')[0];\n                    if ($.common.isEmpty(row)) {\n                        $.modal.alertWarning(\"请至少选择一条记录\");\n                        return;\n                    }\n                    var url = table.options.updateUrl.replace(\"{id}\", row[table.options.uniqueId]);\n                    $.modal.open(\"修改\" + table.options.modalName, url);\n                } else {\n                    $.modal.open(\"修改\" + table.options.modalName, $.operate.editUrl(id));\n                }\n            },\n            // 修改信息，以tab页展现\n            editTab: function(id) {\n                table.set();\n                $.modal.openTab(\"修改\" + table.options.modalName, $.operate.editUrl(id));\n            },\n            // 修改信息 全屏\n            editFull: function(id) {\n                table.set();\n                var url = \"/404.html\";\n                if ($.common.isNotEmpty(id)) {\n                    url = table.options.updateUrl.replace(\"{id}\", id);\n                } else {\n                    if (table.options.type == table_type.bootstrapTreeTable) {\n                        var row = $(\"#\" + table.options.id).bootstrapTreeTable('getSelections')[0];\n                        if ($.common.isEmpty(row)) {\n                            $.modal.alertWarning(\"请至少选择一条记录\");\n                            return;\n                        }\n                        url = table.options.updateUrl.replace(\"{id}\", row[table.options.uniqueId]);\n                    } else {\n                        var row = $.common.isEmpty(table.options.uniqueId) ? $.table.selectFirstColumns() : $.table.selectColumns(table.options.uniqueId);\n                        url = table.options.updateUrl.replace(\"{id}\", row);\n                    }\n                }\n                $.modal.openFull(\"修改\" + table.options.modalName, url);\n            },\n            // 修改访问地址\n            editUrl: function(id) {\n                var url = \"/404.html\";\n                if ($.common.isNotEmpty(id)) {\n                    url = table.options.updateUrl.replace(\"{id}\", id);\n                } else {\n                    var id = $.common.isEmpty(table.options.uniqueId) ? $.table.selectFirstColumns() : $.table.selectColumns(table.options.uniqueId);\n                    if (id.length == 0) {\n                        $.modal.alertWarning(\"请至少选择一条记录\");\n                        return;\n                    }\n                    url = table.options.updateUrl.replace(\"{id}\", id);\n                }\n                return url;\n            },\n            // 右侧弹出详情\n            view: function(id){\n                table.set();\n                var url = table.options.viewUrl.replace(\"{id}\", id);\n                $.modal.popupRight(table.options.modalName + \"信息详情\", url);\n            },\n            // 保存信息 刷新表格\n            save: function(url, data, callback) {\n                var config = {\n                    url: url,\n                    type: \"post\",\n                    dataType: \"json\",\n                    data: data,\n                    beforeSend: function (xhr, settings) {\n                        var csrftoken = $('meta[name=csrf-token]').attr('content');\n                        if (($.common.equalsIgnoreCase(settings.type, \"POST\"))) {\n                            xhr.setRequestHeader(\"X-CSRF-Token\", csrftoken);\n                        }\n                        $.modal.loading(\"正在处理中，请稍候...\");\n                        $.modal.disable();\n                    },\n                    success: function(result) {\n                        if (typeof callback == \"function\") {\n                            callback(result);\n                        }\n                        $.operate.successCallback(result);\n                    }\n                };\n                $.ajax(config)\n            },\n            // 保存信息 弹出结果提示框\n            saveModal: function(url, data, callback) {\n                var config = {\n                    url: url,\n                    type: \"post\",\n                    dataType: \"json\",\n                    data: data,\n                    beforeSend: function (xhr, settings) {\n                        var csrftoken = $('meta[name=csrf-token]').attr('content');\n                        if (($.common.equalsIgnoreCase(settings.type, \"POST\"))) {\n                            xhr.setRequestHeader(\"X-CSRF-Token\", csrftoken);\n                        }\n                        $.modal.loading(\"正在处理中，请稍候...\");\n                    },\n                    success: function(result) {\n                        if (typeof callback == \"function\") {\n                            callback(result);\n                        }\n                        if (result.code == web_status.SUCCESS) {\n                            $.modal.alertSuccess(result.msg)\n                        } else if (result.code == web_status.WARNING) {\n                            $.modal.alertWarning(result.msg)\n                        } else {\n                            $.modal.alertError(result.msg);\n                        }\n                        $.modal.closeLoading();\n                    }\n                };\n                $.ajax(config)\n            },\n            // 保存选项卡信息\n            saveTab: function(url, data, callback) {\n                var config = {\n                    url: url,\n                    type: \"post\",\n                    dataType: \"json\",\n                    data: data,\n                    beforeSend: function (xhr, settings) {\n                        var csrftoken = $('meta[name=csrf-token]').attr('content');\n                        if (($.common.equalsIgnoreCase(settings.type, \"POST\"))) {\n                            xhr.setRequestHeader(\"X-CSRF-Token\", csrftoken);\n                        }\n                        $.modal.loading(\"正在处理中，请稍候...\");\n                    },\n                    success: function(result) {\n                        if (typeof callback == \"function\") {\n                            callback(result);\n                        }\n                        $.operate.successTabCallback(result);\n                    }\n                };\n                $.ajax(config)\n            },\n            // 保存结果弹出msg刷新table表格\n            ajaxSuccess: function (result) {\n                if (result.code == web_status.SUCCESS && table.options.type == table_type.bootstrapTable) {\n                    $.modal.msgSuccess(result.msg);\n                    $.table.refresh();\n                } else if (result.code == web_status.SUCCESS && table.options.type == table_type.bootstrapTreeTable) {\n                    $.modal.msgSuccess(result.msg);\n                    $.treeTable.refresh();\n                } else if (result.code == web_status.SUCCESS && $.common.isEmpty(table.options.type)) {\n                    $.modal.msgSuccess(result.msg)\n                }  else if (result.code == web_status.WARNING) {\n                    $.modal.alertWarning(result.msg)\n                }  else {\n                    $.modal.alertError(result.msg);\n                }\n                $.modal.closeLoading();\n            },\n            // 保存结果重新加载页面\n            saveReload: function (result) {\n                if (result.code == web_status.SUCCESS) {\n                    $.modal.msgSuccessReload(result.msg);\n                } else if (result.code == web_status.WARNING) {\n                    $.modal.alertWarning(result.msg)\n                }  else {\n                    $.modal.alertError(result.msg);\n                }\n                $.modal.closeLoading();\n            },\n            // 成功回调执行事件（父窗体静默更新）\n            successCallback: function(result) {\n                if (result.code == web_status.SUCCESS) {\n                    var parent = activeWindow();\n                    if ($.common.isEmpty(parent.table)) {\n                        $.modal.msgSuccessReload(result.msg);\n                    } else if (parent.table.options.type == table_type.bootstrapTable) {\n                        parent.$.modal.msgSuccess(result.msg);\n                        parent.$.table.refresh();\n                    } else if (parent.table.options.type == table_type.bootstrapTreeTable) {\n                        parent.$.modal.msgSuccess(result.msg);\n                        parent.$.treeTable.refresh();\n                    } else {\n                        parent.$.modal.msgSuccess(result.msg);\n                    }\n                    $.modal.close();\n                } else if (result.code == web_status.WARNING) {\n                    $.modal.alertWarning(result.msg)\n                }  else {\n                    $.modal.alertError(result.msg);\n                }\n                $.modal.closeLoading();\n                $.modal.enable();\n            },\n            // 选项卡成功回调执行事件（父窗体静默更新）\n            successTabCallback: function(result) {\n                if (result.code == web_status.SUCCESS) {\n                    var topWindow = $(window.parent.document);\n                    var currentId = $('.page-tabs-content', topWindow).find('.active').attr('data-panel');\n                    var topWindow = $('.RuoYi_iframe[data-id=\"' + currentId + '\"]', topWindow)[0];\n                    if ($.common.isNotEmpty(topWindow) && $.common.isNotEmpty(currentId)) {\n                    \tvar $contentWindow = topWindow.contentWindow;\n                    \t$contentWindow.$.modal.msgSuccess(result.msg);\n                        $contentWindow.$(\".layui-layer-padding\").removeAttr(\"style\");\n                        if ($contentWindow.table.options.type == table_type.bootstrapTable) {\n                            $contentWindow.$.table.refresh();\n                        } else if ($contentWindow.table.options.type == table_type.bootstrapTreeTable) {\n                            $contentWindow.$.treeTable.refresh();\n                        }\n                    } else {\n                        $.modal.msgSuccess(result.msg);\n                    }\n                    $.modal.close();\n                    $.modal.closeTab();\n                } else if (result.code == web_status.WARNING) {\n                    $.modal.alertWarning(result.msg)\n                } else {\n                    $.modal.alertError(result.msg);\n                }\n                $.modal.closeLoading();\n            }\n        },\n        // 校验封装处理\n        validate: {\n            // 表单验证\n            form: function (formId) {\n                var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;\n                return $(\"#\" + currentId).validate().form();\n            },\n            // 重置表单验证（清除提示信息）\n            reset: function (formId) {\n                var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;\n                return $(\"#\" + currentId).validate().resetForm();\n            }\n        },\n        // 树插件封装处理\n        tree: {\n            _option: {},\n            _lastValue: {},\n            // 初始化树结构\n            init: function(options) {\n                var defaults = {\n                    id: \"tree\",                    // 属性ID\n                    expandLevel: 0,                // 展开等级节点\n                    view: {\n                        selectedMulti: false,      // 设置是否允许同时选中多个节点\n                        nameIsHTML: true           // 设置 name 属性是否支持 HTML 脚本\n                    },\n                    check: {\n                        enable: false,             // 置 zTree 的节点上是否显示 checkbox / radio\n                        nocheckInherit: true,      // 设置子节点是否自动继承\n                        chkboxType: { \"Y\": \"ps\", \"N\": \"ps\" } // 父子节点的关联关系\n                    },\n                    data: {\n                        key: {\n                            title: \"title\"         // 节点数据保存节点提示信息的属性名称\n                        },\n                        simpleData: {\n                            enable: true           // true / false 分别表示 使用 / 不使用 简单数据模式\n                        }\n                    },\n                };\n                var options = $.extend(defaults, options);\n                $.tree._option = options;\n                // 树结构初始化加载\n                var setting = {\n                    callback: {\n                        onClick: options.onClick,                      // 用于捕获节点被点击的事件回调函数\n                        onCheck: options.onCheck,                      // 用于捕获 checkbox / radio 被勾选 或 取消勾选的事件回调函数\n                        onDblClick: options.onDblClick                 // 用于捕获鼠标双击之后的事件回调函数\n                    },\n                    check: options.check,\n                    view: options.view,\n                    data: options.data\n                };\n                $.get(options.url, function(data) {\n                    var treeId = $(\"#treeId\").val();\n                    tree = $.fn.zTree.init($(\"#\" + options.id), setting, data);\n                    $._tree = tree;\n                    for (var i = 0; i < options.expandLevel; i++) {\n                        var nodes = tree.getNodesByParam(\"level\", i);\n                        for (var j = 0; j < nodes.length; j++) {\n                            tree.expandNode(nodes[j], true, false, false);\n                        }\n                    }\n                    var node = tree.getNodesByParam(\"id\", treeId, null)[0];\n                    $.tree.selectByIdName(treeId, node);\n                    // 回调tree方法\n                    if (typeof(options.callBack) === \"function\"){\n                        options.callBack(tree);\n                    }\n                });\n            },\n            // 搜索节点\n            searchNode: function() {\n                // 取得输入的关键字的值\n                var value = $.common.trim($(\"#keyword\").val());\n                if ($.tree._lastValue == value) {\n                    return;\n                }\n                // 保存最后一次搜索名称\n                $.tree._lastValue = value;\n                var nodes = $._tree.getNodes();\n                // 如果要查空字串，就退出不查了。\n                if (value == \"\") {\n                    $.tree.showAllNode(nodes);\n                    return;\n                }\n                $.tree.hideAllNode(nodes);\n                // 根据搜索值模糊匹配\n                $.tree.updateNodes($._tree.getNodesByParamFuzzy(\"name\", value));\n            },\n            // 根据Id和Name选中指定节点\n            selectByIdName: function(treeId, node) {\n                if ($.common.isNotEmpty(treeId) && node && treeId == node.id) {\n                    $._tree.selectNode(node, true);\n                }\n            },\n            // 显示所有节点\n            showAllNode: function(nodes) {\n                nodes = $._tree.transformToArray(nodes);\n                for (var i = nodes.length - 1; i >= 0; i--) {\n                    if (nodes[i].getParentNode() != null) {\n                        $._tree.expandNode(nodes[i], true, false, false, false);\n                    } else {\n                        $._tree.expandNode(nodes[i], true, true, false, false);\n                    }\n                    $._tree.showNode(nodes[i]);\n                    $.tree.showAllNode(nodes[i].children);\n                }\n            },\n            // 隐藏所有节点\n            hideAllNode: function(nodes) {\n                var nodes = $._tree.transformToArray(nodes);\n                for (var i = nodes.length - 1; i >= 0; i--) {\n                    $._tree.hideNode(nodes[i]);\n                }\n            },\n            // 显示所有父节点\n            showParent: function(treeNode) {\n                var parentNode;\n                while ((parentNode = treeNode.getParentNode()) != null) {\n                    $._tree.showNode(parentNode);\n                    $._tree.expandNode(parentNode, true, false, false);\n                    treeNode = parentNode;\n                }\n            },\n            // 显示所有孩子节点\n            showChildren: function(treeNode) {\n                if (treeNode.isParent) {\n                    for (var idx in treeNode.children) {\n                        var node = treeNode.children[idx];\n                        $._tree.showNode(node);\n                        $.tree.showChildren(node);\n                    }\n                }\n            },\n            // 更新节点状态\n            updateNodes: function(nodeList) {\n                $._tree.showNodes(nodeList);\n                for (var i = 0, l = nodeList.length; i < l; i++) {\n                    var treeNode = nodeList[i];\n                    $.tree.showChildren(treeNode);\n                    $.tree.showParent(treeNode)\n                }\n            },\n            // 获取当前被勾选集合\n            getCheckedNodes: function(column) {\n                var _column = $.common.isEmpty(column) ? \"id\" : column;\n                var nodes = $._tree.getCheckedNodes(true);\n                return $.map(nodes, function (row) {\n                    return row[_column];\n                }).join();\n            },\n            // 不允许根父节点选择\n            notAllowParents: function(_tree) {\n                var nodes = _tree.getSelectedNodes();\n                if (nodes.length == 0){\n                    $.modal.msgError(\"请选择节点后提交\");\n                    return false;\n                }\n                for (var i = 0; i < nodes.length; i++) {\n                    if (nodes[i].level == 0) {\n                        $.modal.msgError(\"不能选择根节点（\" + nodes[i].name + \"）\");\n                        return false;\n                    }\n                    if (nodes[i].isParent) {\n                        $.modal.msgError(\"不能选择父节点（\" + nodes[i].name + \"）\");\n                        return false;\n                    }\n                }\n                return true;\n            },\n            // 不允许最后层级节点选择\n            notAllowLastLevel: function(_tree) {\n                var nodes = _tree.getSelectedNodes();\n                for (var i = 0; i < nodes.length; i++) {\n                    if (!nodes[i].isParent) {\n                        $.modal.msgError(\"不能选择最后层级节点（\" + nodes[i].name + \"）\");\n                        return false;\n                    }\n                }\n                return true;\n            },\n            // 隐藏/显示搜索栏\n            toggleSearch: function() {\n                $('#search').slideToggle(200);\n                $('#btnShow').toggle();\n                $('#btnHide').toggle();\n                $('#keyword').focus();\n            },\n            // 折叠\n            collapse: function() {\n                $._tree.expandAll(false);\n            },\n            // 展开\n            expand: function() {\n                $._tree.expandAll(true);\n            }\n        },\n        // 通用方法封装处理\n        common: {\n            // 判断字符串是否为空\n            isEmpty: function (value) {\n                if (value == null || this.trim(value) == \"\" || value == undefined || value == \"undefined\") {\n                    return true;\n                }\n                return false;\n            },\n            // 判断一个字符串是否为非空串\n            isNotEmpty: function (value) {\n                return !$.common.isEmpty(value);\n            },\n            // 如果值是空，则返回指定默认字符串，否则返回字符串本身\n            nullToDefault: function (value, defaultValue) {\n                return $.common.isEmpty(value) ? defaultValue : value;\n            },\n            // 空对象转字符串\n            nullToStr: function(value) {\n                if ($.common.isEmpty(value)) {\n                    return \"-\";\n                }\n                return value;\n            },\n            // 是否显示数据 为空默认为显示\n            visible: function (value) {\n                if ($.common.isEmpty(value) || value == true) {\n                    return true;\n                }\n                return false;\n            },\n            // 空格截取\n            trim: function (value) {\n                if (value == null) {\n                    return \"\";\n                }\n                return value.toString().replace(/(^\\s*)|(\\s*$)|\\r|\\n/g, \"\");\n            },\n            // 比较两个字符串（大小写敏感）\n            equals: function (str, that) {\n                return str == that;\n            },\n            // 比较两个字符串（大小写不敏感）\n            equalsIgnoreCase: function (str, that) {\n                return String(str).toUpperCase() === String(that).toUpperCase();\n            },\n            // 将字符串按指定字符分割\n            split: function (str, sep, maxLen) {\n                if ($.common.isEmpty(str)) {\n                    return null;\n                }\n                var value = String(str).split(sep);\n                return maxLen ? value.slice(0, maxLen - 1) : value;\n            },\n            // 字符串格式化(%s )\n            sprintf: function (str) {\n                var args = arguments, flag = true, i = 1;\n                str = str.replace(/%s/g, function () {\n                    var arg = args[i++];\n                    if (typeof arg === 'undefined') {\n                        flag = false;\n                        return '';\n                    }\n                    return arg == null ? '' : arg;\n                });\n                return flag ? str : '';\n            },\n            // 日期格式化 时间戳  -> yyyy-MM-dd HH-mm-ss\n            dateFormat: function(date, format) {\n                var that = this;\n                if (that.isEmpty(date)) return \"\";\n                if (!date) return;\n                if (!format) format = \"yyyy-MM-dd\";\n                switch (typeof date) {\n                case \"string\":\n                    date = new Date(date.replace(/-/g, \"/\"));\n                    break;\n                case \"number\":\n                    date = new Date(date);\n                    break;\n                }\n                if (!date instanceof Date) return;\n                var dict = {\n                    \"yyyy\": date.getFullYear(),\n                    \"M\": date.getMonth() + 1,\n                    \"d\": date.getDate(),\n                    \"H\": date.getHours(),\n                    \"m\": date.getMinutes(),\n                    \"s\": date.getSeconds(),\n                    \"MM\": (\"\" + (date.getMonth() + 101)).substr(1),\n                    \"dd\": (\"\" + (date.getDate() + 100)).substr(1),\n                    \"HH\": (\"\" + (date.getHours() + 100)).substr(1),\n                    \"mm\": (\"\" + (date.getMinutes() + 100)).substr(1),\n                    \"ss\": (\"\" + (date.getSeconds() + 100)).substr(1)\n                };\n                return format.replace(/(yyyy|MM?|dd?|HH?|ss?|mm?)/g,\n                function() {\n                    return dict[arguments[0]];\n                });\n            },\n            // 获取节点数据，支持多层级访问\n            getItemField: function (item, field) {\n                var value = item;\n                if (typeof field !== 'string' || item.hasOwnProperty(field)) {\n                    return item[field];\n                }\n                var props = field.split('.');\n                for (var p in props) {\n                    value = value && value[props[p]];\n                }\n                return value;\n            },\n            // 指定随机数返回\n            random: function (min, max) {\n                return Math.floor((Math.random() * max) + min);\n            },\n            // 判断字符串是否是以start开头\n            startWith: function(value, start) {\n                var reg = new RegExp(\"^\" + start);\n                return reg.test(value)\n            },\n            // 判断字符串是否是以end结尾\n            endWith: function(value, end) {\n                var reg = new RegExp(end + \"$\");\n                return reg.test(value)\n            },\n            // 数组去重\n            uniqueFn: function(array) {\n                var result = [];\n                var hashObj = {};\n                for (var i = 0; i < array.length; i++) {\n                    if (!hashObj[array[i]]) {\n                        hashObj[array[i]] = true;\n                        result.push(array[i]);\n                    }\n                }\n                return result;\n            },\n            // 数组中的所有元素放入一个字符串\n            join: function(array, separator) {\n                if ($.common.isEmpty(array)) {\n                    return null;\n                }\n                return array.join(separator);\n            },\n            // 获取form下所有的字段并转换为json对象\n            formToJSON: function(formId) {\n                var json = {};\n                $.each($(\"#\" + formId).serializeArray(), function(i, field) {\n                    if (json[field.name]) {\n                        json[field.name] += (\",\" + field.value);\n                    } else {\n                        json[field.name] = field.value;\n                    }\n                });\n                return json;\n            },\n            // 数据字典转下拉框\n            dictToSelect: function(datas, value, name) {\n                var actions = [];\n                actions.push($.common.sprintf(\"<select class='form-control' name='%s'>\", name));\n                $.each(datas, function(index, dict) {\n                    actions.push($.common.sprintf(\"<option value='%s'\", dict.dictValue));\n                    if (dict.dictValue == ('' + value)) {\n                        actions.push(' selected');\n                    }\n                    actions.push($.common.sprintf(\">%s</option>\", dict.dictLabel));\n                });\n                actions.push('</select>');\n                return actions.join('');\n            },\n            // 获取obj对象长度\n            getLength: function(obj) {\n                var count = 0;　　\n                for (var i in obj) {\n                    if (obj.hasOwnProperty(i)) {\n                        count++;\n                    }　　\n                }\n                return count;\n            },\n            // 判断移动端\n            isMobile: function () {\n                return navigator.userAgent.match(/(Android|iPhone|SymbianOS|Windows Phone|iPad|iPod)/i);\n            },\n            // 数字正则表达式，只能为0-9数字\n            numValid : function(text){\n                var patten = new RegExp(/^[0-9]+$/);\n                return patten.test(text);\n            },\n            // 英文正则表达式，只能为a-z和A-Z字母\n            enValid : function(text){\n                var patten = new RegExp(/^[a-zA-Z]+$/);\n                return patten.test(text);\n            },\n            // 英文、数字正则表达式，必须包含（字母，数字）\n            enNumValid : function(text){\n                var patten = new RegExp(/^(?=.*[a-zA-Z]+)(?=.*[0-9]+)[a-zA-Z0-9]+$/);\n                return patten.test(text);\n            },\n            // 英文、数字、特殊字符正则表达式，必须包含（字母，数字，特殊字符!@#$%^&*()-=_+）\n            charValid : function(text){\n                var patten = new RegExp(/^(?=.*[A-Za-z])(?=.*\\d)(?=.*[~!@#\\$%\\^&\\*\\(\\)\\-=_\\+])[A-Za-z\\d~!@#\\$%\\^&\\*\\(\\)\\-=_\\+]{6,}$/);\n                return patten.test(text);\n            },\n        }\n    });\n})(jQuery);\n\n/** 表格类型 */\ntable_type = {\n    bootstrapTable: 0,\n    bootstrapTreeTable: 1\n};\n\n/** 消息状态码 */\nweb_status = {\n    SUCCESS: 0,\n    FAIL: 500,\n    WARNING: 301\n};\n\n/** 弹窗状态码 */\nmodal_status = {\n    SUCCESS: \"success\",\n    FAIL: \"error\",\n    WARNING: \"warning\"\n};"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ruoyi/login.js",
    "content": "\r\n$(function() {\r\n    validateKickout();\r\n    validateRule();\r\n    $('.imgcode').click(function() {\r\n        var url = ctx + \"captcha/captchaImage?type=\" + captchaType + \"&s=\" + Math.random();\r\n        $(\".imgcode\").attr(\"src\", url);\r\n    });\r\n});\r\n\r\nfunction login() {\r\n    var username = $.common.trim($(\"input[name='username']\").val());\r\n    var password = $.common.trim($(\"input[name='password']\").val());\r\n    var validateCode = $(\"input[name='validateCode']\").val();\r\n    var rememberMe = $(\"input[name='rememberme']\").is(':checked');\r\n    if($.common.isEmpty(validateCode) && captchaEnabled) {\r\n        $.modal.msg(\"请输入验证码\");\r\n        return false;\r\n    }\r\n    $.ajax({\r\n        type: \"post\",\r\n        url: ctx + \"login\",\r\n        data: {\r\n            \"username\": username,\r\n            \"password\": password,\r\n            \"validateCode\": validateCode,\r\n            \"rememberMe\": rememberMe\r\n        },\r\n        beforeSend: function () {\r\n            $.modal.loading($(\"#btnSubmit\").data(\"loading\"));\r\n        },\r\n        success: function(r) {\r\n            if (r.code == web_status.SUCCESS) {\r\n                location.href = ctx + 'index';\r\n            } else {\r\n                $('.imgcode').click();\r\n                $(\".code\").val(\"\");\r\n                $.modal.msg(r.msg);\r\n            }\r\n            $.modal.closeLoading();\r\n        }\r\n    });\r\n}\r\n\r\nfunction validateRule() {\r\n    var icon = \"<i class='fa fa-times-circle'></i> \";\r\n    $(\"#signupForm\").validate({\r\n        rules: {\r\n            username: {\r\n                required: true\r\n            },\r\n            password: {\r\n                required: true\r\n            }\r\n        },\r\n        messages: {\r\n            username: {\r\n                required: icon + \"请输入您的用户名\",\r\n            },\r\n            password: {\r\n                required: icon + \"请输入您的密码\",\r\n            }\r\n        },\r\n        submitHandler: function(form) {\r\n            login();\r\n        }\r\n    })\r\n}\r\n\r\nfunction validateKickout() {\r\n    if (getParam(\"kickout\") == 1) {\r\n        layer.alert(\"<font color='red'>您已在别处登录，请您修改密码或重新登录</font>\", {\r\n            icon: 0,\r\n            title: \"系统提示\"\r\n        },\r\n        function(index) {\r\n            //关闭弹窗\r\n            layer.close(index);\r\n            if (top != self) {\r\n                top.location = self.location;\r\n            } else {\r\n                var url = location.search;\r\n                if (url) {\r\n                    var oldUrl = window.location.href;\r\n                    var newUrl = oldUrl.substring(0, oldUrl.indexOf('?'));\r\n                    self.location = newUrl;\r\n                }\r\n            }\r\n        });\r\n    }\r\n}\r\n\r\nfunction getParam(paramName) {\r\n    var reg = new RegExp(\"(^|&)\" + paramName + \"=([^&]*)(&|$)\");\r\n    var r = window.location.search.substr(1).match(reg);\r\n    if (r != null) return decodeURI(r[2]);\r\n    return null;\r\n}"
  },
  {
    "path": "ruoyi-admin/src/main/resources/static/ruoyi/register.js",
    "content": "\r\n$(function() {\r\n    validateRule();\r\n    $('.imgcode').click(function() {\r\n        var url = ctx + \"captcha/captchaImage?type=\" + captchaType + \"&s=\" + Math.random();\r\n        $(\".imgcode\").attr(\"src\", url);\r\n    });\r\n});\r\n\r\nfunction register() {\r\n    var username = $.common.trim($(\"input[name='username']\").val());\r\n    var password = $.common.trim($(\"input[name='password']\").val());\r\n    var validateCode = $(\"input[name='validateCode']\").val();\r\n    if($.common.isEmpty(validateCode) && captchaEnabled) {\r\n        $.modal.msg(\"请输入验证码\");\r\n        return false;\r\n    }\r\n    $.ajax({\r\n        type: \"post\",\r\n        url: ctx + \"register\",\r\n        data: {\r\n            \"loginName\": username,\r\n            \"password\": password,\r\n            \"validateCode\": validateCode\r\n        },\r\n        beforeSend: function () {\r\n            $.modal.loading($(\"#btnSubmit\").data(\"loading\"));\r\n        },\r\n        success: function(r) {\r\n            if (r.code == web_status.SUCCESS) {\r\n            \tlayer.alert(\"<font color='red'>恭喜你，您的账号 \" + username + \" 注册成功！</font>\", {\r\n            \t    icon: 1,\r\n            \t    title: \"系统提示\"\r\n            \t},\r\n            \tfunction(index) {\r\n            \t    //关闭弹窗\r\n            \t    layer.close(index);\r\n            \t    location.href = ctx + 'login';\r\n            \t});\r\n            } else {\r\n            \t$.modal.closeLoading();\r\n            \t$('.imgcode').click();\r\n            \t$(\".code\").val(\"\");\r\n            \t$.modal.msg(r.msg);\r\n            }\r\n        }\r\n    });\r\n}\r\n\r\nfunction validateRule() {\r\n    var icon = \"<i class='fa fa-times-circle'></i> \";\r\n    $(\"#registerForm\").validate({\r\n        rules: {\r\n            username: {\r\n                required: true,\r\n                minlength: 2\r\n            },\r\n            password: {\r\n                required: true,\r\n                minlength: 5,\r\n                specialSign: true\r\n            },\r\n            confirmPassword: {\r\n                required: true,\r\n                equalTo: \"[name='password']\"\r\n            }\r\n        },\r\n        messages: {\r\n            username: {\r\n                required: icon + \"请输入您的用户名\",\r\n                minlength: icon + \"用户名不能小于2个字符\"\r\n            },\r\n            password: {\r\n            \trequired: icon + \"请输入您的密码\",\r\n                minlength: icon + \"密码不能小于5个字符\",\r\n            },\r\n            confirmPassword: {\r\n                required: icon + \"请再次输入您的密码\",\r\n                equalTo: icon + \"两次密码输入不一致\"\r\n            }\r\n        },\r\n        submitHandler: function(form) {\r\n            register();\r\n        }\r\n    })\r\n}\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/autocomplete.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('搜索自动补全')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n      <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>搜索自动补全<small>https://github.com/lzwme/bootstrap-suggest-plugin</small></h5>\r\n                    </div>  \r\n                    <div class=\"ibox-content\">\r\n                        <p>展示下拉菜单按钮。</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <div class=\"input-group\">\r\n                                    <input type=\"text\" class=\"form-control\" id=\"suggest-demo-1\">\r\n                                    <div class=\"input-group-btn\">\r\n                                        <button type=\"button\" class=\"btn btn-white dropdown-toggle\" style=\"height: 31px\" data-toggle=\"dropdown\">\r\n                                            <span class=\"caret\"></span>\r\n                                        </button>\r\n                                        <ul class=\"dropdown-menu dropdown-menu-right\" role=\"menu\">\r\n                                        </ul>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <p>不展示下拉菜单按钮。</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <div class=\"input-group\">\r\n                                    <input type=\"text\" class=\"form-control\" id=\"suggest-demo-2\">\r\n                                    <div class=\"input-group-btn\">\r\n                                        <button type=\"button\" class=\"btn btn-white dropdown-toggle\" data-toggle=\"dropdown\">\r\n                                            <span class=\"caret\"></span>\r\n                                        </button>\r\n                                        <ul class=\"dropdown-menu dropdown-menu-right\" role=\"menu\">\r\n                                        </ul>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <p>前端json中获取数据</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <div class=\"input-group\">\r\n                                    <input type=\"text\" class=\"form-control\" id=\"suggest-demo-3\">\r\n                                    <div class=\"input-group-btn\">\r\n                                        <button type=\"button\" class=\"btn btn-white dropdown-toggle\" style=\"height: 31px\" data-toggle=\"dropdown\">\r\n                                            <span class=\"caret\"></span>\r\n                                        </button>\r\n                                        <ul class=\"dropdown-menu dropdown-menu-right\" role=\"menu\">\r\n                                        </ul>\r\n                                    </div>\r\n                                    <!-- /btn-group -->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <h3>百度搜索</h3>\r\n                        <p>支持逗号分隔多关键字</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <div class=\"input-group\" style=\"width: 300px;\">\r\n                                    <input type=\"text\" class=\"form-control\" id=\"baidu\">\r\n                                    <div class=\"input-group-btn\">\r\n                                        <button type=\"button\" class=\"btn btn-white dropdown-toggle\" style=\"height: 31px\" data-toggle=\"dropdown\">\r\n                                            <span class=\"caret\"></span>\r\n                                        </button>\r\n                                        <ul class=\"dropdown-menu dropdown-menu-right\" role=\"menu\">\r\n                                        </ul>\r\n                                    </div>\r\n                                    <!-- /btn-group -->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <h3>淘宝搜索</h3>\r\n                        <p>支持逗号分隔多关键字</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <div class=\"input-group\" style=\"width: 400px;\">\r\n                                    <input type=\"text\" class=\"form-control\" id=\"taobao\">\r\n                                    <div class=\"input-group-btn\">\r\n                                        <button type=\"button\" class=\"btn btn-white dropdown-toggle\" style=\"height: 31px\" data-toggle=\"dropdown\">\r\n                                            <span class=\"caret\"></span>\r\n                                        </button>\r\n                                        <ul class=\"dropdown-menu dropdown-menu-right\" role=\"menu\">\r\n                                        </ul>\r\n                                    </div>\r\n                                    <!-- /btn-group -->\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-suggest\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-suggest</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            \r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>搜索自动补全<small>https://github.com/bassjobsen/Bootstrap-3-Typeahead</small></h5>\r\n                    </div>  \r\n                    <div class=\"ibox-content\">\r\n                        <p>通过数据属性的基本示例。</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                           \t    <input type=\"text\" placeholder=\"ruoyi...\" data-provide=\"typeahead\" data-source='[\"ruoyi 1\",\"ruoyi 2\",\"ruoyi 3\"]' class=\"form-control\" />\r\n                            </div>\r\n                        </div>\r\n                        <hr>\r\n                        \r\n                        <p>通过javascript的基本示例。</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <input type=\"text\" placeholder=\"ruoyi...\" class=\"form-control\" id=\"typeahead-demo-1\"/>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <hr>\r\n                        <p>通过javascript的复杂示例。</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <input type=\"text\" placeholder=\"ruoyi...\" class=\"form-control\" id=\"typeahead-demo-2\"/>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <hr>\r\n                        <p>后台url中获取简单数据</p>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-lg-6\">\r\n                                <input type=\"text\" placeholder=\"ruoyi...\" class=\"form-control\" id=\"typeahead-demo-3\"/>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-typeahead\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-typeahead</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: bootstrap-suggest-js\" />\r\n    <th:block th:include=\"include :: bootstrap-typeahead-js\" />\r\n    <script type=\"text/javascript\">\r\n        \r\n\t    var testBsSuggest = $(\"#suggest-demo-1\").bsSuggest({\r\n\t        url: ctx + \"demo/form/userModel\",\r\n\t        idField: \"userId\",\r\n\t        keyField: \"userName\"\r\n\t    }).on('onDataRequestSuccess', function (e, result) {\r\n\t        console.log('onDataRequestSuccess: ', result);\r\n\t    }).on('onSetSelectValue', function (e, keyword) {\r\n\t        console.log('onSetSelectValue: ', keyword);\r\n\t    }).on('onUnsetSelectValue', function (e) {\r\n\t        console.log(\"onUnsetSelectValue\");\r\n\t    });\r\n\t    \r\n\t    var testBsSuggest = $(\"#suggest-demo-2\").bsSuggest({\r\n\t        url: ctx + \"demo/form/userModel\",\r\n\t        showBtn: false,\r\n\t        idField: \"userId\",\r\n\t        keyField: \"userName\"\r\n\t    }).on('onDataRequestSuccess', function (e, result) {\r\n\t        console.log('onDataRequestSuccess: ', result);\r\n\t    }).on('onSetSelectValue', function (e, keyword) {\r\n\t        console.log('onSetSelectValue: ', keyword);\r\n\t    }).on('onUnsetSelectValue', function (e) {\r\n\t        console.log(\"onUnsetSelectValue\");\r\n\t    });\r\n\t\r\n\t    //data 数据中获取\r\n\t    var testdataBsSuggest = $(\"#suggest-demo-3\").bsSuggest({\r\n\t        indexId: 1,\r\n\t        indexKey: 2,\r\n\t        data: {\r\n\t            'value': [\r\n\t                {\r\n\t                    'userId': '1',\r\n\t                    'userCode': '1000001',\r\n\t                    'userName': '测试1',\r\n\t                    'userPhone': '15888888888'\r\n\t                },\r\n\t                {\r\n\t                    'userId': '2',\r\n\t                    'userCode': '1000002',\r\n\t                    'userName': '测试2',\r\n\t                    'userPhone': '15888888888'\r\n\t                },\r\n\t                {\r\n\t                    'userId': '3',\r\n\t                    'userCode': '1000003',\r\n\t                    'userName': '测试3',\r\n\t                    'userPhone': '15888888888'\r\n\t                },\r\n\t                {\r\n\t                    'userId': '4',\r\n\t                    'userCode': '1000004',\r\n\t                    'userName': '测试4',\r\n\t                    'userPhone': '15888888888'\r\n\t                },\r\n\t                {\r\n\t                    'userId': '5',\r\n\t                    'userCode': '1000005',\r\n\t                    'userName': '测试5',\r\n\t                    'userPhone': '15888888888'\r\n\t                }\r\n\t\t\t\t],\r\n\t            'defaults': 'http://ruoyi.vip'\r\n\t        }\r\n\t    });\r\n\t    \r\n\t    //百度搜索测试\r\n\t    var baiduBsSuggest = $(\"#baidu\").bsSuggest({\r\n\t        allowNoKeyword: false, //是否允许无关键字时请求数据\r\n\t        multiWord: true, //以分隔符号分割的多关键字支持\r\n\t        separator: \",\", //多关键字支持时的分隔符，默认为空格\r\n\t        getDataMethod: \"url\", //获取数据的方式，总是从 URL 获取\r\n\t        url: 'http://unionsug.baidu.com/su?p=3&t=' + (new Date()).getTime() + '&wd=',\r\n\t        /*优先从url ajax 请求 json 帮助数据，注意最后一个参数为关键字请求参数*/\r\n\t        jsonp: 'cb',\r\n\t        /*如果从 url 获取数据，并且需要跨域，则该参数必须设置*/\r\n\t        processData: function (json) { // url 获取数据时，对数据的处理，作为 getData 的回调函数\r\n\t            var i, len, data = {\r\n\t                value: []\r\n\t            };\r\n\t            if (!json || !json.s || json.s.length === 0) {\r\n\t                return false;\r\n\t            }\r\n\t\r\n\t            console.log(json);\r\n\t            len = json.s.length;\r\n\t\r\n\t            jsonStr = \"{'value':[\";\r\n\t            for (i = 0; i < len; i++) {\r\n\t                data.value.push({\r\n\t                    word: json.s[i]\r\n\t                });\r\n\t            }\r\n\t            data.defaults = 'baidu';\r\n\t\r\n\t            //字符串转化为 js 对象\r\n\t            return data;\r\n\t        }\r\n\t    });\r\n\t    \r\n\t    //淘宝搜索建议测试\r\n\t    var taobaoBsSuggest = $(\"#taobao\").bsSuggest({\r\n\t        indexId: 2,                 // data.value 的第几个数据，作为input输入框的内容\r\n\t        indexKey: 1,                // data.value 的第几个数据，作为input输入框的内容\r\n\t        allowNoKeyword: false,      // 是否允许无关键字时请求数据\r\n\t        hideOnSelect: true,         // 鼠标从列表单击选择了值时，是否隐藏选择列表\r\n\t        multiWord: true,            // 以分隔符号分割的多关键字支持\r\n\t        separator: \",\",             // 多关键字支持时的分隔符，默认为空格\r\n\t        getDataMethod: \"url\",       // 获取数据的方式，总是从 URL 获取\r\n\t        effectiveFieldsAlias: {\r\n\t            Id: \"序号\",\r\n\t            Keyword: \"关键字\",\r\n\t            Count: \"数量\"\r\n\t        },\r\n\t        showHeader: true,\r\n\t        url: 'http://suggest.taobao.com/sug?code=utf-8&extras=1&q=',\r\n\t        /*优先从url ajax 请求 json 帮助数据，注意最后一个参数为关键字请求参数*/\r\n\t        jsonp: 'callback',\r\n\t        /*如果从 url 获取数据，并且需要跨域，则该参数必须设置*/\r\n\t        processData: function (json) { // url 获取数据时，对数据的处理，作为 getData 的回调函数\r\n\t            var i, len, data = {\r\n\t                value: []\r\n\t            };\r\n\t\r\n\t            if (!json || !json.result || json.result.length == 0) {\r\n\t                return false;\r\n\t            }\r\n\t\r\n\t            console.log(json);\r\n\t            len = json.result.length;\r\n\t\r\n\t            for (i = 0; i < len; i++) {\r\n\t                data.value.push({\r\n\t                    \"Id\": (i + 1),\r\n\t                    \"Keyword\": json.result[i][0],\r\n\t                    \"Count\": json.result[i][1]\r\n\t                });\r\n\t            }\r\n\t            console.log(data);\r\n\t            return data;\r\n\t        }\r\n\t    });\r\n\t    \r\n\t    $('#typeahead-demo-1').typeahead({\r\n            source: [\"ruoyi 1\",\"ruoyi 2\",\"ruoyi 3\"]\r\n        });\r\n\t    \r\n\t    $('#typeahead-demo-2').typeahead({\r\n            source: [\r\n                {\"name\": \"Afghanistan\", \"code\": \"AF\", \"ccn0\": \"040\"},\r\n                {\"name\": \"Land Islands\", \"code\": \"AX\", \"ccn0\": \"050\"},\r\n                {\"name\": \"Albania\", \"code\": \"AL\",\"ccn0\": \"060\"},\r\n                {\"name\": \"Algeria\", \"code\": \"DZ\",\"ccn0\": \"070\"}\r\n            ]\r\n        });\r\n\t    \r\n\t    $.get(ctx + \"demo/form/collection\", function(data){\r\n\t    \t$(\"#typeahead-demo-3\").typeahead({\r\n\t\t        source: data.value\r\n\t\t    });\r\n        },'json');\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/basic.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('基本表单')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-7\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>基本表单 <small>简单登录表单示例</small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"row\">\r\n                            <div class=\"col-sm-6 b-r\">\r\n                                <h3 class=\"m-t-none m-b\">登录</h3>\r\n                                <p>欢迎登录本站(⊙o⊙)</p>\r\n                                <form role=\"form\">\r\n                                    <div class=\"form-group\">\r\n                                        <label>用户名</label>\r\n                                        <input type=\"email\" placeholder=\"请输入您注册的E-mail\" class=\"form-control\">\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <label>密码</label>\r\n                                        <input type=\"password\" placeholder=\"请输入密码\" class=\"form-control\">\r\n                                    </div>\r\n                                    <div>\r\n                                        <button class=\"btn btn-sm btn-primary pull-right m-t-n-xs\" type=\"submit\"><strong>登 录</strong>\r\n                                        </button>\r\n                                        <label>\r\n                                            <input type=\"checkbox\">自动登录</label>\r\n                                    </div>\r\n                                </form>\r\n                            </div>\r\n                            <div class=\"col-sm-6\">\r\n                                <h4>还不是会员？</h4>\r\n                                <p>您可以注册一个新账户</p>\r\n                                <p class=\"text-center\">\r\n                                    <a href=\"javascript:;\"><i class=\"fa fa-sign-in big-icon\"></i></a>\r\n                                </p>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-5\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>横向表单</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <form class=\"form-horizontal\">\r\n                            <p>欢迎登录本站(⊙o⊙)</p>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">用户名：</label>\r\n\r\n                                <div class=\"col-sm-8\">\r\n                                    <input type=\"email\" placeholder=\"用户名\" class=\"form-control\"> <span class=\"help-block m-b-none\">请输入您注册时所填的E-mail</span>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">密码：</label>\r\n\r\n                                <div class=\"col-sm-8\">\r\n                                    <input type=\"password\" placeholder=\"密码\" class=\"form-control\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <div class=\"col-sm-offset-3 col-sm-8\">\r\n                                    <button class=\"btn btn-sm btn-white\" type=\"submit\">登 录</button>\r\n                                </div>\r\n                            </div>\r\n                        </form>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-8\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>内联表单</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <form role=\"form\" class=\"form-inline\">\r\n                            <div class=\"form-group\">\r\n                                <label for=\"exampleInputEmail2\" class=\"sr-only\">用户名</label>\r\n                                <input type=\"email\" placeholder=\"请输入用户名\" id=\"exampleInputEmail2\" class=\"form-control\">\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label for=\"exampleInputPassword2\" class=\"sr-only\">密码</label>\r\n                                <input type=\"password\" placeholder=\"请输入密码\" id=\"exampleInputPassword2\" class=\"form-control\">\r\n                            </div>\r\n                            <div class=\"checkbox m-l m-r-xs\">\r\n                                <label>\r\n                                    <input type=\"checkbox\"><i></i> 自动登录</label>\r\n                            </div>\r\n                            <button class=\"btn btn-white\" type=\"submit\">登录</button>\r\n                        </form>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>弹出表单 <small>弹出框登录示例</small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"text-center\">\r\n                            <a data-toggle=\"modal\" class=\"btn btn-primary\" href=\"#modal-form\">打开登录窗口</a>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>所有表单元素 <small>包括自定义样式的复选和单选按钮</small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <form method=\"get\" class=\"form-horizontal\">\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">普通</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" class=\"form-control\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">带说明信息</label>\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" class=\"form-control\"> <span class=\"help-block m-b-none\">帮助文本，可能会超过一行，以块级元素显示</span>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">密码</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"password\" class=\"form-control\" name=\"password\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">提示</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" placeholder=\"提示信息\" class=\"form-control\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">禁用</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" disabled=\"\" placeholder=\"已被禁用\" class=\"form-control\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">静态控制</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <p class=\"form-control-static\">ruoyi.vip</p>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">复选框&amp;单选框\r\n                                    <br/>\r\n                                    <small class=\"text-navy\">普通Bootstrap元素</small>\r\n                                </label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <div class=\"checkbox\">\r\n                                        <label>\r\n                                            <input type=\"checkbox\" value=\"\">选项1</label>\r\n                                    </div>\r\n                                    <div class=\"radio\">\r\n                                        <label>\r\n                                            <input type=\"radio\" checked=\"\" value=\"option1\" id=\"optionsRadios1\" name=\"optionsRadios\">选项1</label>\r\n                                    </div>\r\n                                    <div class=\"radio\">\r\n                                        <label>\r\n                                            <input type=\"radio\" value=\"option2\" id=\"optionsRadios2\" name=\"optionsRadios\">选项2</label>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">内联复选框</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <label class=\"checkbox-inline\">\r\n                                        <input type=\"checkbox\" value=\"option1\" id=\"inlineCheckbox1\">a</label>\r\n                                    <label class=\"checkbox-inline\">\r\n                                        <input type=\"checkbox\" value=\"option2\" id=\"inlineCheckbox2\">b</label>\r\n                                    <label class=\"checkbox-inline\">\r\n                                        <input type=\"checkbox\" value=\"option3\" id=\"inlineCheckbox3\">c</label>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">复选框&amp;单选框\r\n                                    <br/><small class=\"text-navy\">自定义样式</small>\r\n                                </label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <div class=\"checkbox check-box\">\r\n                                        <label>\r\n                                            <input type=\"checkbox\" value=\"\"> <i></i> 选项1</label>\r\n                                    </div>\r\n                                    <div class=\"checkbox check-box\">\r\n                                        <label>\r\n                                            <input type=\"checkbox\" value=\"\" checked=\"\"> <i></i> 选项2（选中）</label>\r\n                                    </div>\r\n                                    <div class=\"checkbox check-box\">\r\n                                        <label>\r\n                                            <input type=\"checkbox\" value=\"\" disabled=\"\" checked=\"\"> <i></i> 选项3（选中并禁用）</label>\r\n                                    </div>\r\n                                    <div class=\"checkbox check-box\">\r\n                                        <label>\r\n                                            <input type=\"checkbox\" value=\"\" disabled=\"\"> <i></i> 选项4（禁用）</label>\r\n                                    </div>\r\n                                    <div class=\"radio check-box\">\r\n                                        <label>\r\n                                            <input type=\"radio\" value=\"option1\" name=\"a\"> <i></i> 选项1</label>\r\n                                    </div>\r\n                                    <div class=\"radio check-box\">\r\n                                        <label>\r\n                                            <input type=\"radio\" checked=\"\" value=\"option2\" name=\"a\"> <i></i> 选项2（选中）</label>\r\n                                    </div>\r\n                                    <div class=\"radio check-box\">\r\n                                        <label>\r\n                                            <input type=\"radio\" disabled=\"\" checked=\"\" value=\"option2\"> <i></i> 选项3（选中并禁用）</label>\r\n                                    </div>\r\n                                    <div class=\"radio check-box\">\r\n                                        <label>\r\n                                            <input type=\"radio\" disabled=\"\" name=\"a\"> <i></i> 选项4（禁用）</label>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">内联复选框</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <label class=\"checkbox-inline check-box\">\r\n                                        <input type=\"checkbox\" value=\"option1\">a</label>\r\n                                    <label class=\"checkbox-inline check-box\">\r\n                                        <input type=\"checkbox\" value=\"option2\">b</label>\r\n                                    <label class=\"checkbox-inline check-box\">\r\n                                        <input type=\"checkbox\" value=\"option3\">c</label>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">Select</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <select class=\"form-control m-b\" name=\"account\">\r\n                                        <option>选项 1</option>\r\n                                        <option>选项 2</option>\r\n                                        <option>选项 3</option>\r\n                                        <option>选项 4</option>\r\n                                    </select>\r\n\r\n                                    <div class=\"col-sm-4 m-l-n\">\r\n                                        <select class=\"form-control\" multiple=\"\">\r\n                                            <option>选项 1</option>\r\n                                            <option>选项 2</option>\r\n                                            <option>选项 3</option>\r\n                                            <option>选项 4</option>\r\n                                        </select>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group has-success\">\r\n                                <label class=\"col-sm-2 control-label\">验证通过</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" class=\"form-control\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group has-warning\">\r\n                                <label class=\"col-sm-2 control-label\">未填写</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" class=\"form-control\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group has-error\">\r\n                                <label class=\"col-sm-2 control-label\">验证未通过</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" class=\"form-control\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">自定义尺寸</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <input type=\"text\" placeholder=\".input-lg\" class=\"form-control input-lg m-b\">\r\n                                    <input type=\"text\" placeholder=\"Default input\" class=\"form-control m-b\">\r\n                                    <input type=\"text\" placeholder=\".input-sm\" class=\"form-control input-sm\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">列尺寸</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <div class=\"row\">\r\n                                        <div class=\"col-md-2\">\r\n                                            <input type=\"text\" placeholder=\".col-md-2\" class=\"form-control\">\r\n                                        </div>\r\n                                        <div class=\"col-md-3\">\r\n                                            <input type=\"text\" placeholder=\".col-md-3\" class=\"form-control\">\r\n                                        </div>\r\n                                        <div class=\"col-md-4\">\r\n                                            <input type=\"text\" placeholder=\".col-md-4\" class=\"form-control\">\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">文本框组</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <div class=\"input-group m-b\"><span class=\"input-group-addon\">@</span>\r\n                                        <input type=\"text\" placeholder=\"用户名\" class=\"form-control\">\r\n                                    </div>\r\n                                    <div class=\"input-group m-b\">\r\n                                        <input type=\"text\" class=\"form-control\"> <span class=\"input-group-addon\">.00</span>\r\n                                    </div>\r\n                                    <div class=\"input-group m-b\"><span class=\"input-group-addon\">&yen;</span>\r\n                                        <input type=\"text\" class=\"form-control\"> <span class=\"input-group-addon\">.00</span>\r\n                                    </div>\r\n                                    <div class=\"input-group m-b\"><span class=\"input-group-addon\"> <input type=\"checkbox\"> </span>\r\n                                        <input type=\"text\" class=\"form-control\">\r\n                                    </div>\r\n                                    <div class=\"input-group\"><span class=\"input-group-addon\"> <input type=\"radio\"> </span>\r\n                                        <input type=\"text\" class=\"form-control\">\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">按钮插件</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <div class=\"input-group m-b\"><span class=\"input-group-btn\">\r\n                                            <button type=\"button\" class=\"btn btn-primary\">搜</button> </span>\r\n                                        <input type=\"text\" class=\"form-control\">\r\n                                    </div>\r\n                                    <div class=\"input-group\">\r\n                                        <input type=\"text\" class=\"form-control\"> <span class=\"input-group-btn\"> <button type=\"button\" class=\"btn btn-primary\">搜索\r\n                                        </button> </span>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">带下拉框</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <div class=\"input-group m-b\">\r\n                                        <div class=\"input-group-btn\">\r\n                                            <button data-toggle=\"dropdown\" class=\"btn btn-white dropdown-toggle\" type=\"button\">操作 <span class=\"caret\"></span>\r\n                                            </button>\r\n                                            <ul class=\"dropdown-menu\">\r\n                                                <li><a href=\"javascript:;\">选项1</a>\r\n                                                </li>\r\n                                                <li><a href=\"javascript:;\">选项2</a>\r\n                                                </li>\r\n                                                <li><a href=\"javascript:;\">选项3</a>\r\n                                                </li>\r\n                                                <li class=\"divider\"></li>\r\n                                                <li><a href=\"javascript:;\">选项4</a>\r\n                                                </li>\r\n                                            </ul>\r\n                                        </div>\r\n                                        <input type=\"text\" class=\"form-control\">\r\n                                    </div>\r\n                                    <div class=\"input-group\">\r\n                                        <input type=\"text\" class=\"form-control\">\r\n\r\n                                        <div class=\"input-group-btn\">\r\n                                            <button data-toggle=\"dropdown\" class=\"btn btn-white dropdown-toggle\" type=\"button\">操作 <span class=\"caret\"></span>\r\n                                            </button>\r\n                                            <ul class=\"dropdown-menu pull-right\">\r\n                                                <li><a href=\"javascript:;\">选项1</a>\r\n                                                </li>\r\n                                                <li><a href=\"javascript:;\">选项2</a>\r\n                                                </li>\r\n                                                <li><a href=\"javascript:;\">选项3</a>\r\n                                                </li>\r\n                                                <li class=\"divider\"></li>\r\n                                                <li><a href=\"javascript:;\">选项4</a>\r\n                                                </li>\r\n                                            </ul>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-2 control-label\">分段</label>\r\n\r\n                                <div class=\"col-sm-10\">\r\n                                    <div class=\"input-group m-b\">\r\n                                        <div class=\"input-group-btn\">\r\n                                            <button tabindex=\"-1\" class=\"btn btn-white\" type=\"button\">操作</button>\r\n                                            <button data-toggle=\"dropdown\" class=\"btn btn-white dropdown-toggle\" type=\"button\"><span class=\"caret\"></span>\r\n                                            </button>\r\n                                            <ul class=\"dropdown-menu\">\r\n                                                <li><a href=\"javascript:;\">选项1</a>\r\n                                                </li>\r\n                                                <li><a href=\"javascript:;\">选项2</a>\r\n                                                </li>\r\n                                                <li><a href=\"javascript:;\">选项3</a>\r\n                                                </li>\r\n                                                <li class=\"divider\"></li>\r\n                                                <li><a href=\"javascript:;\">选项4</a>\r\n                                                </li>\r\n                                            </ul>\r\n                                        </div>\r\n                                        <input type=\"text\" class=\"form-control\">\r\n                                    </div>\r\n                                    <div class=\"input-group\">\r\n                                        <input type=\"text\" class=\"form-control\">\r\n\r\n                                        <div class=\"input-group-btn\">\r\n                                            <button tabindex=\"-1\" class=\"btn btn-white\" type=\"button\">操作</button>\r\n                                            <button data-toggle=\"dropdown\" class=\"btn btn-white dropdown-toggle\" type=\"button\"><span class=\"caret\"></span>\r\n                                            </button>\r\n                                            <ul class=\"dropdown-menu pull-right\">\r\n                                                \t分段\r\n                                            </ul>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group\">\r\n                                <div class=\"col-sm-4 col-sm-offset-2\">\r\n                                    <button class=\"btn btn-primary\" type=\"submit\">保存内容</button>\r\n                                    <button class=\"btn btn-white\" type=\"submit\">取消</button>\r\n                                </div>\r\n                            </div>\r\n                        </form>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n\r\n    <div id=\"modal-form\" class=\"modal fade\" aria-hidden=\"true\">\r\n        <div class=\"modal-dialog\">\r\n            <div class=\"modal-content\">\r\n                <div class=\"modal-body\">\r\n                    <div class=\"row\">\r\n                        <div class=\"col-sm-6 b-r\">\r\n                            <h3 class=\"m-t-none m-b\">登录</h3>\r\n\r\n                            <p>欢迎登录本站(⊙o⊙)</p>\r\n\r\n                            <form role=\"form\">\r\n                                <div class=\"form-group\">\r\n                                    <label>用户名：</label>\r\n                                    <input type=\"email\" placeholder=\"请输入用户名\" class=\"form-control\">\r\n                                </div>\r\n                                <div class=\"form-group\">\r\n                                    <label>密码：</label>\r\n                                    <input type=\"password\" placeholder=\"请输入密码\" class=\"form-control\">\r\n                                </div>\r\n                                <div>\r\n                                    <button class=\"btn btn-sm btn-primary pull-right m-t-n-xs\" type=\"submit\"><strong>登录</strong>\r\n                                    </button>\r\n                                    <label>\r\n                                        <input type=\"checkbox\" class=\"i-checks\">自动登录</label>\r\n                                </div>\r\n                            </form>\r\n                        </div>\r\n                        <div class=\"col-sm-6\">\r\n                            <h4>还不是会员？</h4>\r\n                            <p>您可以注册一个账户</p>\r\n                            <p class=\"text-center\">\r\n                                <a href=\"javascript:;\"><i class=\"fa fa-sign-in big-icon\"></i></a>\r\n                            </p>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/button.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('按钮')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"row wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"col-sm-4\">\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title\">\r\n                    <h5>按钮颜色</h5>\r\n                    <div class=\"ibox-tools\">\r\n                        <a class=\"collapse-link\">\r\n                            <i class=\"fa fa-chevron-up\"></i>\r\n                        </a>\r\n                        <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                            <i class=\"fa fa-wrench\"></i>\r\n                        </a>\r\n                        <ul class=\"dropdown-menu dropdown-user\">\r\n                            <li><a href=\"javascript:;\">选项1</a>\r\n                            </li>\r\n                            <li><a href=\"javascript:;\">选项2</a>\r\n                            </li>\r\n                        </ul>\r\n                        <a class=\"close-link\">\r\n                            <i class=\"fa fa-times\"></i>\r\n                        </a>\r\n                    </div>\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>\r\n                        可使用class来快速改变按钮的颜色，如<code>.btn-primary</code>\r\n                    </p>\r\n\r\n                    <h3 class=\"font-bold\">\r\n                            普通按钮\r\n                        </h3>\r\n                    <p>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-default\">btn-default</button>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-primary\">btn-primary</button>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-success\">btn-success</button>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-info\">btn-info</button>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-warning\">btn-warning</button>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-danger\">btn-danger</button>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-white\">btn-white</button>\r\n                        <button type=\"button\" class=\"btn btn-w-m btn-link\">btn-link</button>\r\n                    </p>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"col-sm-4\">\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title\">\r\n                    <h5>按钮大小</h5>\r\n                    <div class=\"ibox-tools\">\r\n                        <a class=\"collapse-link\">\r\n                            <i class=\"fa fa-chevron-up\"></i>\r\n                        </a>\r\n                        <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                            <i class=\"fa fa-wrench\"></i>\r\n                        </a>\r\n                        <ul class=\"dropdown-menu dropdown-user\">\r\n                            <li><a href=\"javascript:;\">选项1</a>\r\n                            </li>\r\n                            <li><a href=\"javascript:;\">选项2</a>\r\n                            </li>\r\n                        </ul>\r\n                        <a class=\"close-link\">\r\n                            <i class=\"fa fa-times\"></i>\r\n                        </a>\r\n                    </div>\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>\r\n                        可以通过添加class的值为<code>.btn-lg</code>, <code>.btn-sm</code>, or <code>.btn-xs</code>来修改按钮的大小\r\n                    </p>\r\n                    <h3 class=\"font-bold\">按钮尺寸</h3>\r\n                    <p>\r\n                        <button type=\"button\" class=\"btn btn-primary btn-lg\">大按钮</button>\r\n                        <button type=\"button\" class=\"btn btn-default btn-lg\">大按钮</button>\r\n                        <br/>\r\n                        <button type=\"button\" class=\"btn btn-primary\">默认按钮</button>\r\n                        <button type=\"button\" class=\"btn btn-default\">默认按钮</button>\r\n                        <br/>\r\n                        <button type=\"button\" class=\"btn btn-primary btn-sm\">小按钮</button>\r\n                        <button type=\"button\" class=\"btn btn-default btn-sm\">小按钮</button>\r\n                        <br/>\r\n                        <button type=\"button\" class=\"btn btn-primary btn-xs\">Mini按钮</button>\r\n                        <button type=\"button\" class=\"btn btn-default btn-xs\">Mini按钮</button>\r\n                    </p>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"col-sm-4\">\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title\">\r\n                    <h5>线性按钮</h5>\r\n                    <div class=\"ibox-tools\">\r\n                        <a class=\"collapse-link\">\r\n                            <i class=\"fa fa-chevron-up\"></i>\r\n                        </a>\r\n                        <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                            <i class=\"fa fa-wrench\"></i>\r\n                        </a>\r\n                        <ul class=\"dropdown-menu dropdown-user\">\r\n                            <li><a href=\"javascript:;\">选项1</a>\r\n                            </li>\r\n                            <li><a href=\"javascript:;\">选项2</a>\r\n                            </li>\r\n                        </ul>\r\n                        <a class=\"close-link\">\r\n                            <i class=\"fa fa-times\"></i>\r\n                        </a>\r\n                    </div>\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>\r\n                        要使用线性按钮，可添加class<code>.btn-block</code>或<code>.btn-outline</code>\r\n                    </p>\r\n\r\n                    <h3 class=\"font-bold\">线性按钮</h3>\r\n                    <p>\r\n                        <button type=\"button\" class=\"btn btn-outline btn-default\">默认</button>\r\n                        <button type=\"button\" class=\"btn btn-outline btn-primary\">主要</button>\r\n                        <button type=\"button\" class=\"btn btn-outline btn-success\">成功</button>\r\n                        <button type=\"button\" class=\"btn btn-outline btn-info\">信息</button>\r\n                        <button type=\"button\" class=\"btn btn-outline btn-warning\">警告</button>\r\n                        <button type=\"button\" class=\"btn btn-outline btn-danger\">危险</button>\r\n                        <button type=\"button\" class=\"btn btn-outline btn-link\">链接</button>\r\n                    </p>\r\n                    <h3 class=\"font-bold\">块级按钮</h3>\r\n                    <p>\r\n                        <button type=\"button\" class=\"btn btn-block btn-outline btn-primary\">这是一个块级按钮</button>\r\n                    </p>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"col-sm-12\">\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title\">\r\n                    <h5>3D按钮</h5>\r\n                    <div class=\"ibox-tools\">\r\n                        <a class=\"collapse-link\">\r\n                            <i class=\"fa fa-chevron-up\"></i>\r\n                        </a>\r\n                        <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                            <i class=\"fa fa-wrench\"></i>\r\n                        </a>\r\n                        <ul class=\"dropdown-menu dropdown-user\">\r\n                            <li><a href=\"javascript:;\">选项1</a>\r\n                            </li>\r\n                            <li><a href=\"javascript:;\">选项2</a>\r\n                            </li>\r\n                        </ul>\r\n                        <a class=\"close-link\">\r\n                            <i class=\"fa fa-times\"></i>\r\n                        </a>\r\n                    </div>\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>\r\n                        可以通过添加<code>.dim</code>class来使用3D按钮.\r\n                    </p>\r\n                    <h3 class=\"font-bold\">3D按钮</h3>\r\n\r\n                    <button class=\"btn btn-primary dim btn-large-dim\" type=\"button\"><i class=\"fa fa-money\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-warning dim btn-large-dim\" type=\"button\"><i class=\"fa fa-warning\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-danger  dim btn-large-dim\" type=\"button\"><i class=\"fa fa-heart\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-primary  dim btn-large-dim\" type=\"button\"><i class=\"fa fa-dollar\"></i>6</button>\r\n                    <button class=\"btn btn-info  dim btn-large-dim btn-outline\" type=\"button\"><i class=\"fa fa-ruble\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-primary dim\" type=\"button\"><i class=\"fa fa-money\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-warning dim\" type=\"button\"><i class=\"fa fa-warning\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-primary dim\" type=\"button\"><i class=\"fa fa-check\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-success  dim\" type=\"button\"><i class=\"fa fa-upload\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-info  dim\" type=\"button\"><i class=\"fa fa-paste\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-warning  dim\" type=\"button\"><i class=\"fa fa-warning\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-default  dim \" type=\"button\"><i class=\"fa fa-star\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-danger  dim \" type=\"button\"><i class=\"fa fa-heart\"></i>\r\n                    </button>\r\n\r\n                    <button class=\"btn btn-outline btn-primary dim\" type=\"button\"><i class=\"fa fa-money\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-outline btn-warning dim\" type=\"button\"><i class=\"fa fa-warning\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-outline btn-primary dim\" type=\"button\"><i class=\"fa fa-check\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-outline btn-success  dim\" type=\"button\"><i class=\"fa fa-upload\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-outline btn-info  dim\" type=\"button\"><i class=\"fa fa-paste\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-outline btn-warning  dim\" type=\"button\"><i class=\"fa fa-warning\"></i>\r\n                    </button>\r\n                    <button class=\"btn btn-outline btn-danger  dim \" type=\"button\"><i class=\"fa fa-heart\"></i>\r\n                    </button>\r\n\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"col-sm-12\">\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5>下拉按钮</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\">\r\n                                    <i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                    <i class=\"fa fa-wrench\"></i>\r\n                                </a>\r\n                                <ul class=\"dropdown-menu dropdown-user\">\r\n                                    <li><a href=\"javascript:;\">选项1</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">选项2</a>\r\n                                    </li>\r\n                                </ul>\r\n                                <a class=\"close-link\">\r\n                                    <i class=\"fa fa-times\"></i>\r\n                                </a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <p>\r\n                                下拉按钮可使用任何颜色任何大小\r\n                            </p>\r\n\r\n                            <h3 class=\"font-bold\">下拉按钮</h3>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-primary dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-warning dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-default dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n\r\n                            <br/>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-primary btn-sm dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-warning btn-sm dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-default btn-sm dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                            <br/>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-primary btn-xs dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-warning btn-xs dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                            <div class=\"btn-group\">\r\n                                <button data-toggle=\"dropdown\" class=\"btn btn-default btn-xs dropdown-toggle\">操作 <span class=\"caret\"></span>\r\n                                </button>\r\n                                <ul class=\"dropdown-menu\">\r\n                                    <li><a href=\"javascript:;\">置顶</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\" class=\"font-bold\">修改</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">禁用</a>\r\n                                    </li>\r\n                                    <li class=\"divider\"></li>\r\n                                    <li><a href=\"javascript:;\">删除</a>\r\n                                    </li>\r\n                                </ul>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5>按钮组</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\">\r\n                                    <i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                    <i class=\"fa fa-wrench\"></i>\r\n                                </a>\r\n                                <ul class=\"dropdown-menu dropdown-user\">\r\n                                    <li><a href=\"javascript:;\">选项1</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">选项2</a>\r\n                                    </li>\r\n                                </ul>\r\n                                <a class=\"close-link\">\r\n                                    <i class=\"fa fa-times\"></i>\r\n                                </a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n\r\n                            <h3 class=\"font-bold\">按钮组</h3>\r\n                            <div class=\"btn-group\">\r\n                                <button class=\"btn btn-white\" type=\"button\">左</button>\r\n                                <button class=\"btn btn-primary\" type=\"button\">中</button>\r\n                                <button class=\"btn btn-white\" type=\"button\">右</button>\r\n                            </div>\r\n                            <br/>\r\n                            <br/>\r\n                            <div class=\"btn-group\">\r\n                                <button type=\"button\" class=\"btn btn-white\"><i class=\"fa fa-chevron-left\"></i>\r\n                                </button>\r\n                                <button class=\"btn btn-white\">1</button>\r\n                                <button class=\"btn btn-white  active\">2</button>\r\n                                <button class=\"btn btn-white\">3</button>\r\n                                <button class=\"btn btn-white\">4</button>\r\n                                <button type=\"button\" class=\"btn btn-white\"><i class=\"fa fa-chevron-right\"></i>\r\n                                </button>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title\">\r\n                    <h5>图标按钮 </h5>\r\n                    <div class=\"ibox-tools\">\r\n                        <a class=\"collapse-link\">\r\n                            <i class=\"fa fa-chevron-up\"></i>\r\n                        </a>\r\n                        <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                            <i class=\"fa fa-wrench\"></i>\r\n                        </a>\r\n                        <ul class=\"dropdown-menu dropdown-user\">\r\n                            <li><a href=\"javascript:;\">选项1</a>\r\n                            </li>\r\n                            <li><a href=\"javascript:;\">选项2</a>\r\n                            </li>\r\n                        </ul>\r\n                        <a class=\"close-link\">\r\n                            <i class=\"fa fa-times\"></i>\r\n                        </a>\r\n                    </div>\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>\r\n                        任何按钮都可以在左侧或右侧添加图标\r\n                    </p>\r\n\r\n                    <h3 class=\"font-bold\">图标按钮</h3>\r\n                    <p>\r\n                        <button class=\"btn btn-primary \" type=\"button\"><i class=\"fa fa-check\"></i>&nbsp;提交</button>\r\n                        <button class=\"btn btn-success \" type=\"button\"><i class=\"fa fa-upload\"></i>&nbsp;&nbsp;<span class=\"bold\">上传</span>\r\n                        </button>\r\n                        <button class=\"btn btn-info \" type=\"button\"><i class=\"fa fa-paste\"></i> 编辑</button>\r\n                        <button class=\"btn btn-warning \" type=\"button\"><i class=\"fa fa-warning\"></i> <span class=\"bold\">警告</span>\r\n                        </button>\r\n                        <button class=\"btn btn-default \" type=\"button\"><i class=\"fa fa-map-marker\"></i>&nbsp;&nbsp;百度地图</button>\r\n\r\n                        <a class=\"btn btn-success\">\r\n                            <i class=\"fa fa-weixin\"> </i> 分享到微信\r\n                        </a>\r\n                        <a class=\"btn btn-success btn-outline\">\r\n                            <i class=\"fa fa-qq\"> </i> 使用QQ账号登录\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-user-md\"></i>\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-group\"></i>\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-wrench\"></i>\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-exchange\"></i>\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-check-circle-o\"></i>\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-road\"></i>\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-ambulance\"></i>\r\n                        </a>\r\n                        <a class=\"btn btn-white btn-bitbucket\">\r\n                            <i class=\"fa fa-star\"></i> 收藏\r\n                        </a>\r\n                    </p>\r\n\r\n                    <h3 class=\"font-bold\">按钮切换</h3>\r\n                    <button data-toggle=\"button\" class=\"btn btn-primary btn-outline\" type=\"button\">按钮1</button>\r\n                    <button data-toggle=\"button\" class=\"btn btn-primary\" type=\"button\">按钮2</button>\r\n                    <div data-toggle=\"buttons-checkbox\" class=\"btn-group\">\r\n                        <button class=\"btn btn-primary active\" type=\"button\"><i class=\"fa fa-bold\"></i> 粗体</button>\r\n                        <button class=\"btn btn-primary\" type=\"button\"><i class=\"fa fa-underline\"></i> 下划线</button>\r\n                        <button class=\"btn btn-primary active\" type=\"button\"><i class=\"fa fa-italic\"></i> 斜体</button>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"col-sm-12\">\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5>圆形图标按钮</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\">\r\n                                    <i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                    <i class=\"fa fa-wrench\"></i>\r\n                                </a>\r\n                                <ul class=\"dropdown-menu dropdown-user\">\r\n                                    <li><a href=\"javascript:;\">选项1</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">选项2</a>\r\n                                    </li>\r\n                                </ul>\r\n                                <a class=\"close-link\">\r\n                                    <i class=\"fa fa-times\"></i>\r\n                                </a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <p>\r\n                                要使用圆形图标按钮，可以通过添加class为<code>.btn-circle</code>实现\r\n                            </p>\r\n\r\n                            <h3 class=\"font-bold\">圆形按钮</h3>\r\n                            <br/>\r\n                            <button class=\"btn btn-default btn-circle\" type=\"button\"><i class=\"fa fa-check\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-primary btn-circle\" type=\"button\"><i class=\"fa fa-list\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-success btn-circle\" type=\"button\"><i class=\"fa fa-link\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-info btn-circle\" type=\"button\"><i class=\"fa fa-check\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-warning btn-circle\" type=\"button\"><i class=\"fa fa-times\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-danger btn-circle\" type=\"button\"><i class=\"fa fa-heart\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-danger btn-circle btn-outline\" type=\"button\"><i class=\"fa fa-heart\"></i>\r\n                            </button>\r\n                            <br/>\r\n                            <br/>\r\n                            <button class=\"btn btn-default btn-circle btn-lg\" type=\"button\"><i class=\"fa fa-check\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-primary btn-circle btn-lg\" type=\"button\"><i class=\"fa fa-list\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-success btn-circle btn-lg\" type=\"button\"><i class=\"fa fa-link\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-info btn-circle btn-lg\" type=\"button\"><i class=\"fa fa-check\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-warning btn-circle btn-lg\" type=\"button\"><i class=\"fa fa-times\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-danger btn-circle btn-lg\" type=\"button\"><i class=\"fa fa-heart\"></i>\r\n                            </button>\r\n                            <button class=\"btn btn-danger btn-circle btn-lg btn-outline\" type=\"button\"><i class=\"fa fa-heart\"></i>\r\n                            </button>\r\n\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5>圆角按钮</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\">\r\n                                    <i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                    <i class=\"fa fa-wrench\"></i>\r\n                                </a>\r\n                                <ul class=\"dropdown-menu dropdown-user\">\r\n                                    <li><a href=\"javascript:;\">选项1</a>\r\n                                    </li>\r\n                                    <li><a href=\"javascript:;\">选项2</a>\r\n                                    </li>\r\n                                </ul>\r\n                                <a class=\"close-link\">\r\n                                    <i class=\"fa fa-times\"></i>\r\n                                </a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <p>\r\n                                可以通过添加class的值微<code>.btn-rounded</code>来实现圆角按钮\r\n                            </p>\r\n\r\n                            <h3 class=\"font-bold\">按钮组</h3>\r\n                            <p>\r\n                                <a class=\"btn btn-default btn-rounded\" href=\"javascript:;\">默认</a>\r\n                                <a class=\"btn btn-primary btn-rounded\" href=\"javascript:;\">主要</a>\r\n                                <a class=\"btn btn-success btn-rounded\" href=\"javascript:;\">成果</a>\r\n                                <a class=\"btn btn-info btn-rounded\" href=\"javascript:;\">信息</a>\r\n                                <a class=\"btn btn-warning btn-rounded\" href=\"javascript:;\">警告</a>\r\n                                <a class=\"btn btn-danger btn-rounded\" href=\"javascript:;\">危险</a>\r\n                                <a class=\"btn btn-danger btn-rounded btn-outline\" href=\"javascript:;\">危险</a>\r\n                                <br/>\r\n                                <br/>\r\n                                <a class=\"btn btn-primary btn-rounded btn-block\" href=\"javascript:;\"><i class=\"fa fa-info-circle\"></i> 圆角块级带图标按钮</a>\r\n                            </p>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/cards.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n\t<th:block th:include=\"include :: header('卡片列表')\" />\n</head>\n<body class=\"gray-bg\">\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\n        <div class=\"row\">\n            <div class=\"col-sm-4\">\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <span class=\"label label-primary pull-right\">NEW</span>\n                        <h5>IT-01 - 设计部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">48%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 48%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                12\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                4个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;200,913 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <h5>IT-04 - 市场部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">32%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 32%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                24\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                3个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;190,325 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <h5>IT-07 - 财务部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">73%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 73%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                11\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                6个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;560,105 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n            </div>\n            <div class=\"col-sm-4\">\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <h5>IT-02 - 开发部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">61%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 61%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                43\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                1个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;705,913 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <span class=\"label label-warning pull-right\">截止</span>\n                        <h5>IT-05 - 管理层</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">14%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 14%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                8\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                7个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;40,200 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <h5>IT-08 - 销售部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">25%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 25%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                25\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                4个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;140,105 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n            </div>\n            <div class=\"col-sm-4\">\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n\n                        <h5>IT-02 - 销售部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">82%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 82%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                68\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                2个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;701,400 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <h5>IT-06 - 销售部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">26%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 26%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                16\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                8个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;160,100 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n                <div class=\"ibox\">\n                    <div class=\"ibox-title\">\n                        <h5>IT-09 - 销售部</h5>\n                    </div>\n                    <div class=\"ibox-content\">\n                        <h4>部门简介</h4>\n                        <p>\n                                                                           平面设计（graphic design），也称为视觉传达设计，是以“视觉”作为沟通和表现的方式，透过多种方式来创造和结合符号、图片和文字，借此作出用来传达想法或讯息的视觉表现。\n                        </p>\n                        <div>\n                            <span>当前项目进度：</span>\n                            <div class=\"stat-percent\">18%</div>\n                            <div class=\"progress progress-mini\">\n                                <div style=\"width: 18%;\" class=\"progress-bar\"></div>\n                            </div>\n                        </div>\n                        <div class=\"row  m-t-sm\">\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">项目</div>\n                                53\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <div class=\"font-bold\">周期</div>\n                                9个月\n                            </div>\n                            <div class=\"col-sm-4 text-right\">\n                                <div class=\"font-bold\">预算</div>\n                                &yen;60,140 <i class=\"fa fa-level-up text-navy\"></i>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n    <th:block th:include=\"include :: footer\" />\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/cxselect.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('多级联动下拉')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n      <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>多级联动下拉<small>https://github.com/ciaoca/cxSelect</small></h5>\r\n                    </div>  \r\n                    <div class=\"ibox-content\">\r\n                        <p>简单联动示例。</p>\r\n                        <div id=\"element\" class=\"row\">\r\n                            <div class=\"col-sm-2\">\r\n\t                            <select class=\"type form-control m-b\" data-first-title=\"请选择\">\r\n\t\t\t\t                  <option value=\"\">请选择</option>\r\n\t\t\t\t                </select>\r\n\t\t\t                </div>\r\n\t\t\t                <div class=\"col-sm-2\">\r\n\t\t\t\t                <select class=\"router form-control m-b\" data-first-title=\"请选择\">\r\n\t\t\t\t                  <option value=\"\">请选择</option>\r\n\t\t\t\t                </select>\r\n\t\t\t                </div>\r\n                        </div>\r\n                        <hr>\r\n                        \r\n                        <p>国内省市区联动。</p>\r\n                        <div id=\"element1\" class=\"row\">\r\n                            <div class=\"col-sm-2\">\r\n\t                            <select class=\"province form-control m-b\" data-first-title=\"选择省\">\r\n\t\t\t\t                  <option value=\"\">请选择</option>\r\n\t\t\t\t                  <option value=\"广东省\" selected>广东省</option>\r\n\t\t\t\t                </select>\r\n\t\t\t                </div>\r\n\t\t\t                <div class=\"col-sm-2\">\r\n\t\t\t\t                <select class=\"city form-control m-b\" data-first-title=\"选择市\">\r\n\t\t\t\t                  <option value=\"\">请选择</option>\r\n\t\t\t\t                  <option value=\"深圳市\" selected>深圳市</option>\r\n\t\t\t\t                </select>\r\n\t\t\t                </div>\r\n\t\t\t                <div class=\"col-sm-2\">\r\n\t\t\t\t                <select class=\"area form-control m-b\" data-first-title=\"选择地区\">\r\n\t\t\t\t                  <option value=\"\">请选择</option>\r\n\t\t\t\t                  <option value=\"南山区\" selected>南山区</option>\r\n\t\t\t\t                </select>\r\n\t\t\t                </div>\r\n                        </div>\r\n                        <hr>\r\n                        \r\n                        <p>自定义选项。</p>\r\n                        <div id=\"element2\" class=\"row\">\r\n                            <div class=\"col-sm-2\">\r\n\t                            <select class=\"first form-control m-b\"></select>\r\n\t\t\t                </div>\r\n\t\t\t                <div class=\"col-sm-2\">\r\n\t\t\t\t                <select class=\"second form-control m-b\"></select>\r\n\t\t\t                </div>\r\n\t\t\t                <div class=\"col-sm-2\">\r\n\t\t\t\t                <select class=\"third form-control m-b\"></select>\r\n\t\t\t                </div>\r\n\t\t\t                <div class=\"col-sm-2\">\r\n\t\t\t\t                <select class=\"fourth form-control m-b\"></select>\r\n\t\t\t                </div>\r\n\t\t\t                <div class=\"col-sm-2\">\r\n\t\t\t                    <select class=\"fifth form-control m-b\"></select>\r\n\t\t\t                </div>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jquery-cxselect\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jquery-cxselect</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: jquery-cxselect-js\" />\r\n    <script th:inline=\"javascript\">\r\n        // 直接返回获取\r\n   \t\tvar data = [[${data}]];\r\n    \t$('#element').cxSelect({\r\n    \t  selects: ['type', 'router'],\r\n    \t  jsonValue: 'v',\r\n    \t  data: data\r\n    \t});\r\n    \t\r\n    \t// 通过默认url获取\r\n    \tvar urlChina = 'cityData';\r\n    \t$.cxSelect.defaults.url = urlChina;\r\n    \t$('#element1').cxSelect({\r\n   \t\t  selects: ['province', 'city', 'area'],\r\n   \t\t  nodata: 'none'\r\n   \t\t});\r\n    \t\r\n    \t// 固定值获取\r\n    \t$('#element2').cxSelect({\r\n   \t\t  selects: ['first', 'second', 'third', 'fourth', 'fifth'],\r\n   \t\t  required: true,\r\n   \t\t  jsonValue: 'v',\r\n   \t\t  data: [\r\n   \t\t\t{'v': '1', 'n': '第一级 >', 's': [\r\n   \t\t\t  {'v': '2', 'n': '第二级 >', 's': [\r\n   \t\t\t\t{'v': '3', 'n': '第三级 >', 's': [\r\n   \t\t\t\t  {'v': '4', 'n': '第四级 >', 's': [\r\n   \t\t\t\t\t{'v': '5', 'n': '第五级 >', 's': [\r\n   \t\t\t\t\t  {'v': '6', 'n': '第六级 >'}\r\n   \t\t\t\t\t]}\r\n   \t\t\t\t  ]}\r\n   \t\t\t\t]}\r\n   \t\t\t  ]}\r\n   \t\t\t]},\r\n   \t\t\t{'v': 'test number', 'n': '测试数字', 's': [\r\n   \t\t\t  {'v': 'text', 'n': '文本类型', 's': [\r\n   \t\t\t\t{'v': '4', 'n': '4'},\r\n   \t\t\t\t{'v': '5', 'n': '5'},\r\n   \t\t\t\t{'v': '6', 'n': '6'},\r\n   \t\t\t\t{'v': '7', 'n': '7'},\r\n   \t\t\t\t{'v': '8', 'n': '8'},\r\n   \t\t\t\t{'v': '9', 'n': '9'},\r\n   \t\t\t\t{'v': '10', 'n': '10'}\r\n   \t\t\t  ]},\r\n   \t\t\t  {'v': 'number', 'n': '数值类型', 's': [\r\n   \t\t\t\t{'v': 11, 'n': 11},\r\n   \t\t\t\t{'v': 12, 'n': 12},\r\n   \t\t\t\t{'v': 13, 'n': 13},\r\n   \t\t\t\t{'v': 14, 'n': 14},\r\n   \t\t\t\t{'v': 15, 'n': 15},\r\n   \t\t\t\t{'v': 16, 'n': 16},\r\n   \t\t\t\t{'v': 17, 'n': 17}\r\n   \t\t\t  ]}\r\n   \t\t\t]},\r\n   \t\t\t{'v': 'test boolean','n': '测试 Boolean 类型', 's': [\r\n   \t\t\t  {'v': true ,'n': true},\r\n   \t\t\t  {'v': false ,'n': false}\r\n   \t\t\t]},\r\n   \t\t\t{v: 'test quotes', n: '测试属性不加引号', s: [\r\n   \t\t\t  {v: 'quotes', n: '引号'}\r\n   \t\t\t]},\r\n   \t\t\t{v: 'test other', n: '测试奇怪的值', s: [\r\n   \t\t\t  {v: '[]', n: '数组（空）'},\r\n   \t\t\t  {v: [1,2,3], n: '数组（数值）'},\r\n   \t\t\t  {v: ['a','b','c'], n: '数组（文字）'},\r\n   \t\t\t  {v: new Date(), n: '日期'},\r\n   \t\t\t  {v: new RegExp('\\\\d+'), n: '正则对象'},\r\n   \t\t\t  {v: /\\d+/, n: '正则直接量'},\r\n   \t\t\t  {v: {}, n: '对象'},\r\n   \t\t\t  {v: document.getElementById('custom_data'), n: 'DOM'},\r\n   \t\t\t  {v: null, n: 'Null'},\r\n   \t\t\t  {n: '未设置 value'}\r\n   \t\t\t]},\r\n   \t\t\t{'v': '' , 'n': '无子级'}\r\n   \t\t  ]\r\n   \t\t});\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/datetime.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('日期和时间')\" />\r\n\t<th:block th:include=\"include :: datetimepicker-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n      <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>日期选择器 <small>https://github.com/smalot/bootstrap-datetimepicker</small></h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">简单示例</label>\r\n                            <div class=\"input-group date\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                                <input type=\"text\" class=\"form-control\" id=\"datetimepicker-demo-1\" placeholder=\"yyyy-MM-dd HH:mm\">\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">显示年月日</label>\r\n                            <div class=\"input-group date\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                                <input type=\"text\" class=\"form-control\" id=\"datetimepicker-demo-2\" placeholder=\"yyyy-MM-dd\">\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">显示年月日时分秒</label>\r\n                            <div class=\"input-group date\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                                <input type=\"text\" class=\"form-control\" id=\"datetimepicker-demo-3\" placeholder=\"yyyy-MM-dd HH:mm:ss\">\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n\t\t\t                <label class=\"font-noraml\">带清空的按钮</label>\r\n\t\t\t                <div class=\"input-group date form_date\">\r\n\t\t\t                    <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n\t\t\t                    <input class=\"form-control\" size=\"16\" type=\"text\" readonly>\r\n\t\t\t                    <span class=\"input-group-addon\"><span class=\"glyphicon glyphicon-remove\"></span></span>\r\n\t\t\t                </div>\r\n\t\t\t            </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">日期范围选择</label>\r\n                            <div class=\"input-daterange input-group\">\r\n                                <input type=\"text\" class=\"input-sm form-control\" id=\"datetimepicker-startTime\" placeholder=\"yyyy-MM-dd\"/>\r\n                                <span class=\"input-group-addon\">到</span>\r\n                                <input type=\"text\" class=\"input-sm form-control\" id=\"datetimepicker-endTime\" placeholder=\"yyyy-MM-dd\"/>\r\n                            </div>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-datetimepicker\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-datetimepicker</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>日期选择器 <small>https://github.com/sentsin/laydate</small></h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">简单示例</label>\r\n                            <div class=\"input-group date\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                                <input type=\"text\" class=\"form-control\" id=\"laydate-demo-1\" placeholder=\"yyyy-MM-dd\">\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">显示年月日</label>\r\n                            <div class=\"input-group date\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                                <input type=\"text\" class=\"form-control\" id=\"laydate-demo-2\" placeholder=\"yyyy-MM-dd\">\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">显示年月日时分秒</label>\r\n                            <div class=\"input-group date\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                                <input type=\"text\" class=\"form-control\" id=\"laydate-demo-3\" placeholder=\"yyyy-MM-dd HH:mm:ss\">\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">单框范围选择</label>\r\n                            <div class=\"input-group date\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                                <input type=\"text\" class=\"form-control\" id=\"laydate-demo-4\" placeholder=\"yyyy-MM-dd - yyyy-MM-dd\">\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">日期范围选择</label>\r\n                            <div class=\"input-daterange input-group\">\r\n                                <input type=\"text\" class=\"input-sm form-control\" id=\"laydate-startTime\" placeholder=\"yyyy-MM-dd\"/>\r\n                                <span class=\"input-group-addon\">到</span>\r\n                                <input type=\"text\" class=\"input-sm form-control\" id=\"laydate-endTime\" placeholder=\"yyyy-MM-dd\"/>\r\n                            </div>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#laydate\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#laydate</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: datetimepicker-js\" />\r\n    <script type=\"text/javascript\">\r\n        $(function(){\r\n        \t<!-- datetimepicker示例 -->\r\n        \t$(\"#datetimepicker-demo-1\").datetimepicker();\r\n        \t\r\n        \t$(\"#datetimepicker-demo-2\").datetimepicker({\r\n       \t\t    format: \"yyyy-mm-dd\",\r\n       \t\t    minView: \"month\",\r\n       \t\t    autoclose: true,\r\n       \t\t    clearBtn:true\r\n       \t\t});\r\n        \t\r\n        \t$(\"#datetimepicker-demo-3\").datetimepicker({\r\n       \t\t    format: \"yyyy-mm-dd hh:ii:ss\",\r\n       \t\t    autoclose: true\r\n       \t\t});\r\n        \t\r\n        \t$('.form_date').datetimepicker({\r\n        \t\tformat: \"yyyy-mm-dd\",\r\n       \t\t    minView: \"month\",\r\n       \t\t    autoclose: true\r\n            });\r\n        \t\r\n        \t$(\"#datetimepicker-startTime\").datetimepicker({\r\n        \t\tformat: 'yyyy-mm-dd',\r\n        \t\tminView: \"month\",\r\n        \t    todayBtn:  true,\r\n        \t    autoclose: true,\r\n        \t\tendDate : new Date(),\r\n        \t}).on('changeDate', function(event) {\r\n        \t\tevent.preventDefault();\r\n        \t\tevent.stopPropagation();\r\n        \t\tvar startTime = event.date;\r\n        \t\t$('#datetimepicker-endTime').datetimepicker('setStartDate', startTime);\r\n        \t});\r\n        \t\r\n        \t$(\"#datetimepicker-endTime\").datetimepicker({\r\n        \t\tformat: 'yyyy-mm-dd',\r\n        \t\tminView: \"month\",\r\n        \t\ttodayBtn:  true,\r\n        \t\tautoclose: true,\r\n        \t\tendDate : new Date(),\r\n        \t}).on('changeDate', function(event) {\r\n        \t\tevent.preventDefault();\r\n        \t\tevent.stopPropagation();\r\n        \t\tvar endTime = event.date;\r\n        \t\t$(\"#datetimepicker-startTime\").datetimepicker('setEndDate', endTime);\r\n        \t});\r\n        \t\r\n        \t<!-- laydate示例 -->\r\n        \tlayui.use('laydate', function(){\r\n       \t\t  var laydate = layui.laydate;\r\n       \t\t  \r\n       \t\t  laydate.render({\r\n       \t\t    elem: '#laydate-demo-1'\r\n       \t\t  });\r\n       \t\t  \r\n       \t\t  laydate.render({ \r\n       \t\t    elem: '#laydate-demo-2',\r\n       \t\t    type: 'date'\r\n       \t\t  });\r\n       \t\t  \r\n       \t\t  laydate.render({ \r\n       \t\t    elem: '#laydate-demo-3',\r\n       \t\t    type: 'datetime',\r\n       \t\t    trigger: 'click'\r\n       \t\t  });\r\n       \t\t  \r\n       \t\t  laydate.render({\r\n       \t\t    elem: '#laydate-demo-4',\r\n       \t\t    range: true\r\n       \t\t  });\r\n       \t\t  \r\n       \t\t  var startDate = laydate.render({\r\n\t\t        elem: '#laydate-startTime',\r\n\t\t        max: $('#laydate-endTime').val(),\r\n\t\t        theme: 'molv',\r\n\t\t        trigger: 'click',\r\n\t\t        done: function(value, date) {\r\n\t\t            // 结束时间大于开始时间\r\n\t\t            if (value !== '') {\r\n\t\t                endDate.config.min.year = date.year;\r\n\t\t                endDate.config.min.month = date.month - 1;\r\n\t\t                endDate.config.min.date = date.date;\r\n\t\t            } else {\r\n\t\t                endDate.config.min.year = '';\r\n\t\t                endDate.config.min.month = '';\r\n\t\t                endDate.config.min.date = '';\r\n\t\t            }\r\n\t\t        }\r\n\t\t      });\r\n       \t\t\r\n\t\t      var endDate = laydate.render({\r\n\t\t        elem: '#laydate-endTime',\r\n\t\t        min: $('#laydate-startTime').val(),\r\n\t\t        theme: 'molv',\r\n\t\t        trigger: 'click',\r\n\t\t        done: function(value, date) {\r\n\t\t            // 开始时间小于结束时间\r\n\t\t            if (value !== '') {\r\n\t\t                startDate.config.max.year = date.year;\r\n\t\t                startDate.config.max.month = date.month - 1;\r\n\t\t                startDate.config.max.date = date.date;\r\n\t\t            } else {\r\n\t\t                startDate.config.max.year = '';\r\n\t\t                startDate.config.max.month = '';\r\n\t\t                startDate.config.max.date = '';\r\n\t\t            }\r\n\t\t        }\r\n\t\t      });\r\n       \t   });\r\n        });\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/duallistbox.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('左右互选组件')\" />\r\n\t<th:block th:include=\"include :: bootstrap-duallistbox-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-lg-12\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>双重列表框 <small>https://github.com/istvan-ujjmeszaros/bootstrap-duallistbox</small></h5>\r\n                    </div>  \r\n                    <div class=\"ibox-content\">\r\n                        <p>\r\n                            Bootstrap Dual Listbox是针对Twitter Bootstrap进行了优化的响应式双列表框。它适用于所有现代浏览器和触摸设备。\r\n                        </p>\r\n\r\n                        <form id=\"form\" action=\"#\" class=\"wizard-big\">\r\n                            <select class=\"form-control dual_select\" multiple>\r\n                                <option value=\"1\">若依1</option>\r\n                                <option value=\"2\">若依2</option>\r\n                                <option value=\"3\">若依3</option>\r\n                                <option selected value=\"4\">若依4</option>\r\n                                <option selected value=\"5\">若依5</option>\r\n                                <option value=\"6\">若依6</option>\r\n                                <option value=\"7\">若依7</option>\r\n                                <option value=\"8\">若依8</option>\r\n                                <option value=\"9\">若依9</option>\r\n                                <option value=\"10\">若依10</option>\r\n                                <option value=\"11\">若依11</option>\r\n                                <option value=\"12\">若依12</option>\r\n                            </select>\r\n                        </form>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-duallistbox\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-duallistbox</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: bootstrap-duallistbox-js\" />\r\n    <script type=\"text/javascript\">\r\n\t    $('.dual_select').bootstrapDualListbox({\r\n\t    \tnonSelectedListLabel: '未有用户',\r\n            selectedListLabel: '已有用户',\r\n            preserveSelectionOnMove: 'moved',\r\n            moveOnSelect: false,           // 出现一个剪头，表示可以一次选择一个\r\n            filterTextClear: '展示所有',\r\n            moveSelectedLabel: \"添加\",\r\n            moveAllLabel: '添加所有',\r\n            removeSelectedLabel: \"移除\",\r\n            removeAllLabel: '移除所有',\r\n            infoText: '共{0}个',\r\n            showFilterInputs: false,       // 是否带搜索\r\n\t        selectorMinimalHeight: 160\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/grid.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('栅格')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>栅格设置</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n\r\n                        <p>通过下表可以详细查看 Bootstrap 的栅格系统是如何在多种屏幕设备上工作的。</p>\r\n                        <div class=\"table-responsive\">\r\n                            <table class=\"table table-bordered table-striped\">\r\n                                <thead>\r\n                                    <tr>\r\n                                        <th></th>\r\n                                        <th>\r\n                                            超小屏幕\r\n                                            <small>手机 (&lt;768px)</small>\r\n                                        </th>\r\n                                        <th>\r\n                                            小屏幕\r\n                                            <small>平板 (≥768px)</small>\r\n                                        </th>\r\n                                        <th>\r\n                                            中等屏幕\r\n                                            <small>桌面显示器 (≥992px)</small>\r\n                                        </th>\r\n                                        <th>\r\n                                            大屏幕\r\n                                            <small>大桌面显示器 (≥1200px)</small>\r\n                                        </th>\r\n                                    </tr>\r\n                                </thead>\r\n                                <tbody>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">栅格系统行为</th>\r\n                                        <td>总是水平排列</td>\r\n                                        <td colspan=\"3\">开始是堆叠在一起的，当大于这些阈值时将变为水平排列C</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\"><code>.container</code> 最大宽度</th>\r\n                                        <td>None （自动）</td>\r\n                                        <td>750px</td>\r\n                                        <td>970px</td>\r\n                                        <td>1170px</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">类前缀</th>\r\n                                        <td><code>.col-xs-</code>\r\n                                        </td>\r\n                                        <td><code>.col-sm-</code>\r\n                                        </td>\r\n                                        <td><code>.col-md-</code>\r\n                                        </td>\r\n                                        <td><code>.col-lg-</code>\r\n                                        </td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">列（column）数</th>\r\n                                        <td colspan=\"4\">12</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">最大列（column）宽</th>\r\n                                        <td class=\"text-muted\">自动</td>\r\n                                        <td>~62px</td>\r\n                                        <td>~81px</td>\r\n                                        <td>~97px</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">槽（gutter）宽</th>\r\n                                        <td colspan=\"4\">30px （每列左右均有 15px）</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">可嵌套</th>\r\n                                        <td colspan=\"4\">是</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">偏移（Offsets）</th>\r\n                                        <td colspan=\"4\">是</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <th class=\"text-nowrap\">列排序</th>\r\n                                        <td colspan=\"4\">是</td>\r\n                                    </tr>\r\n                                </tbody>\r\n                            </table>\r\n                        </div>\r\n\r\n\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>从堆叠到水平排列</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n\r\n                        <p>使用单一的一组 <code>.col-md-*</code> 栅格类，就可以创建一个基本的栅格系统，在手机和平板设备上一开始是堆叠在一起的（超小屏幕到小屏幕这一范围），在桌面（中等）屏幕设备上变为水平排列。所有“列（column）必须放在 ” <code>.row</code> 内。</p>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                            <div class=\"col-md-1\">.col-md-1</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-8\">.col-md-8</div>\r\n                            <div class=\"col-md-4\">.col-md-4</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-4\">.col-md-4</div>\r\n                            <div class=\"col-md-4\">.col-md-4</div>\r\n                            <div class=\"col-md-4\">.col-md-4</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-6\">.col-md-6</div>\r\n                            <div class=\"col-md-6\">.col-md-6</div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>移动设备和桌面屏幕</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n\r\n                        <p>是否不希望在小屏幕设备上所有列都堆叠在一起？那就使用针对超小屏幕和中等屏幕设备所定义的类吧，即 <code>.col-xs-*</code> 和 <code>.col-md-*</code>。请看下面的实例，研究一下这些是如何工作的。</p>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-xs-12 col-md-8\">.col-xs-12 .col-md-8</div>\r\n                            <div class=\"col-xs-6 col-md-4\">.col-xs-6 .col-md-4</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-xs-6 col-md-4\">.col-xs-6 .col-md-4</div>\r\n                            <div class=\"col-xs-6 col-md-4\">.col-xs-6 .col-md-4</div>\r\n                            <div class=\"col-xs-6 col-md-4\">.col-xs-6 .col-md-4</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-xs-6\">.col-xs-6</div>\r\n                            <div class=\"col-xs-6\">.col-xs-6</div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>手机、平板、桌面</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n\r\n                        <p>在上面案例的基础上，通过使用针对平板设备的 <code>.col-sm-*</code> 类，我们来创建更加动态和强大的布局吧。</p>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-xs-12 col-sm-6 col-md-8\">.col-xs-12 .col-sm-6 .col-md-8</div>\r\n                            <div class=\"col-xs-6 col-md-4\">.col-xs-6 .col-md-4</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-xs-6 col-sm-4\">.col-xs-6 .col-sm-4</div>\r\n                            <div class=\"col-xs-6 col-sm-4\">.col-xs-6 .col-sm-4</div>\r\n                            <!-- Optional: clear the XS cols if their content doesn't match in height -->\r\n                            <div class=\"clearfix visible-xs\"></div>\r\n                            <div class=\"col-xs-6 col-sm-4\">.col-xs-6 .col-sm-4</div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>多余的列（column）将另起一行排列</h5>\r\n\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <p>在等宽的4网格中，网格不等高会碰到问题，为了解决这个问题，可使用<code>.clearfix</code>。<a href=\"#responsive-utilities\">响应实用工具类</a>\r\n                        </p>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-xs-6 col-sm-3\">\r\n                                .col-xs-6 .col-sm-3\r\n                                <br>调整窗口大小或者在手机上查看本示例\r\n                            </div>\r\n                            <div class=\"col-xs-6 col-sm-3\">.col-xs-6 .col-sm-3</div>\r\n\r\n                            <!-- Add the extra clearfix for only the required viewport -->\r\n                            <div class=\"clearfix visible-xs\"></div>\r\n\r\n                            <div class=\"col-xs-6 col-sm-3\">.col-xs-6 .col-sm-3</div>\r\n                            <div class=\"col-xs-6 col-sm-3\">.col-xs-6 .col-sm-3</div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>列偏移</h5>\r\n\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n\r\n                        <p>使用 <code>.col-md-offset-*</code> 类可以将列向右侧偏移。这些类实际是通过使用 <code>*</code> 选择器为当前元素增加了左侧的边距（margin）。例如，<code>.col-md-offset-4</code> 类将 <code>.col-md-4</code> 元素向右侧偏移了4个列（column）的宽度。</p>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-4\">.col-md-4</div>\r\n                            <div class=\"col-md-4 col-md-offset-4\">.col-md-4 .col-md-offset-4</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-3 col-md-offset-3\">.col-md-3 .col-md-offset-3</div>\r\n                            <div class=\"col-md-3 col-md-offset-3\">.col-md-3 .col-md-offset-3</div>\r\n                        </div>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-6 col-md-offset-3\">.col-md-6 .col-md-offset-3</div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>嵌套列</h5>\r\n\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <p>为了使用内置的栅格系统将内容再次嵌套，可以通过添加一个新的 <code>.row</code> 元素和一系列 <code>.col-sm-*</code> 元素到已经存在的 <code>.col-sm-*</code> 元素内。被嵌套的行（row）所包含的列（column）的个数不能超过12（其实，没有要求你必须占满12列）。</p>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-9\">\r\n                                第一级： .col-md-9\r\n                                <div class=\"row show-grid\">\r\n                                    <div class=\"col-md-6\">\r\n                                        第二级： .col-md-6\r\n                                    </div>\r\n                                    <div class=\"col-md-6\">\r\n                                        第二级： .col-md-6\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>列排序</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <p>通过使用 <code>.col-md-push-*</code> 和 <code>.col-md-pull-*</code> 类就可以很容易的改变列（column）的顺序。</p>\r\n                        <div class=\"row show-grid\">\r\n                            <div class=\"col-md-9 col-md-push-3\">.col-md-9 .col-md-push-3</div>\r\n                            <div class=\"col-md-3 col-md-pull-9\">.col-md-3 .col-md-pull-9</div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/invoice.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('单据打印')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox-content p-xl\">\r\n                    <div class=\"row\">\r\n                        <div class=\"col-sm-6\">\r\n                            <address>\r\n                                        <strong>北京百度在线网络技术有限公司</strong><br>\r\n                                        北京市海淀区上地十街10号<br>\r\n                                        <abbr title=\"Phone\">总机：</abbr> (+86 10) 5992 8888\r\n                                    </address>\r\n                        </div>\r\n\r\n                        <div class=\"col-sm-6 text-right\">\r\n                            <h4>单据编号：</h4>\r\n                            <h4 class=\"text-navy\">H+-000567F7-00</h4>\r\n                            <address>\r\n                                        <strong>阿里巴巴集团</strong><br>\r\n                                        中国杭州市华星路99号东部软件园创业大厦6层(310099)<br>\r\n                                        <abbr title=\"Phone\">总机：</abbr> (86) 571-8502-2088\r\n                                    </address>\r\n                            <p>\r\n                                <span><strong>日期：</strong> 2014-11-11</span>\r\n                            </p>\r\n                        </div>\r\n                    </div>\r\n\r\n                    <div class=\"table-responsive m-t\">\r\n                        <table class=\"table invoice-table\">\r\n                            <thead>\r\n                                <tr>\r\n                                    <th>清单</th>\r\n                                    <th>数量</th>\r\n                                    <th>单价</th>\r\n                                    <th>税率</th>\r\n                                    <th>总价</th>\r\n                                </tr>\r\n                            </thead>\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td>\r\n                                        <div><strong>尚都比拉2013冬装新款女装 韩版修身呢子大衣 秋冬气质羊毛呢外套</strong>\r\n                                        </div>\r\n                                    </td>\r\n                                    <td>1</td>\r\n                                    <td>&yen;26.00</td>\r\n                                    <td>&yen;1.20</td>\r\n                                    <td>&yen;31,98</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <div><strong>11*11夏娜 新款斗篷毛呢外套 女秋冬呢子大衣 韩版大码宽松呢大衣</strong>\r\n                                        </div>\r\n                                        <small>双十一特价\r\n                                            </small>\r\n                                    </td>\r\n                                    <td>2</td>\r\n                                    <td>&yen;80.00</td>\r\n                                    <td>&yen;1.20</td>\r\n                                    <td>&yen;196.80</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <div><strong>2013秋装 新款女装韩版学生秋冬加厚加绒保暖开衫卫衣 百搭女外套</strong>\r\n                                        </div>\r\n                                    </td>\r\n                                    <td>3</td>\r\n                                    <td>&yen;420.00</td>\r\n                                    <td>&yen;1.20</td>\r\n                                    <td>&yen;1033.20</td>\r\n                                </tr>\r\n\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                    <!-- /table-responsive -->\r\n\r\n                    <table class=\"table invoice-total\">\r\n                        <tbody>\r\n                            <tr>\r\n                                <td><strong>总价：</strong>\r\n                                </td>\r\n                                <td>&yen;1026.00</td>\r\n                            </tr>\r\n                            <tr>\r\n                                <td><strong>税：</strong>\r\n                                </td>\r\n                                <td>&yen;235.98</td>\r\n                            </tr>\r\n                            <tr>\r\n                                <td><strong>总计</strong>\r\n                                </td>\r\n                                <td>&yen;1261.98</td>\r\n                            </tr>\r\n                        </tbody>\r\n                    </table>\r\n                    <!-- 打印网页时通过hidden-print隐藏元素 -->\r\n                    <div class=\"text-right hidden-print\">\r\n                        <button class=\"btn btn-primary\" onclick=\"printPage()\"><i class=\"fa fa-print\"></i> 打印</button>\r\n                    </div>\r\n\r\n                    <div class=\"well m-t\"><strong>注意：</strong> 请在30日内完成付款，否则订单会自动取消。\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n        function printPage() {\r\n            window.print();\r\n        }\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/jasny.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('功能扩展')\" />\r\n\t<th:block th:include=\"include :: jasny-bootstrap-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n<div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>文件上传控件 <small>https://github.com/jasny/bootstrap</small></h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                    \t<div class=\"form-group\">\r\n                            <label class=\"font-noraml\">输入组示例</label>\r\n                            \r\n\t                        <div class=\"fileinput fileinput-new input-group\" data-provides=\"fileinput\">\r\n\t                            <div class=\"form-control\" data-trigger=\"fileinput\"><i class=\"glyphicon glyphicon-file fileinput-exists\"></i> <span class=\"fileinput-filename\"></span></div>\r\n\t                            <span class=\"input-group-addon btn btn-white btn-file\"><span class=\"fileinput-new\">选择文件</span><span class=\"fileinput-exists\">更改</span><input type=\"file\"></span>\r\n\t                            <a href=\"javascript:;\" class=\"input-group-addon btn btn-white fileinput-exists\" data-dismiss=\"fileinput\">清除</a>\r\n\t                        </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">按钮示例</label>\r\n                            <br/>\r\n\t                        <div class=\"fileinput fileinput-new\" data-provides=\"fileinput\">\r\n\t                            <span class=\"btn btn-white btn-file\"><span class=\"fileinput-new\">选择文件</span><span class=\"fileinput-exists\">更改</span><input type=\"file\" name=\"...\"></span>\r\n\t                            <span class=\"fileinput-filename\"></span>\r\n\t                            <a href=\"javascript:;\" class=\"close fileinput-exists\" data-dismiss=\"fileinput\" style=\"float: none\">&times;</a>\r\n\t                        </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">图片上传示例</label>\r\n                            <br/>\r\n\t                        <div class=\"fileinput fileinput-new\" data-provides=\"fileinput\">\r\n\t\t\t\t\t            <div class=\"fileinput-preview thumbnail\" data-trigger=\"fileinput\" style=\"width: 200px; height: 150px;\"></div>\r\n\t\t\t\t\t            <div>\r\n\t\t\t\t\t                <span class=\"btn btn-white btn-file\"><span class=\"fileinput-new\">选择图片</span><span class=\"fileinput-exists\">更改</span><input type=\"file\"></span>\r\n\t\t\t\t\t                <a href=\"javascript:;\" class=\"btn btn-white fileinput-exists\" data-dismiss=\"fileinput\">清除</a>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t        </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">图片预览示例</label>\r\n                            <br/>\r\n\t                        <div class=\"fileinput fileinput-new\" data-provides=\"fileinput\">\r\n\t\t\t\t\t\t        <div class=\"fileinput-new thumbnail\" style=\"width: 140px; height: 140px;\">\r\n\t\t\t\t\t\t          <img th:src=\"@{/img/profile.jpg}\">\r\n\t\t\t\t\t\t        </div>\r\n\t\t\t\t\t\t        <div class=\"fileinput-preview fileinput-exists thumbnail\" style=\"max-width: 200px; max-height: 150px;\"></div>\r\n\t\t\t\t\t\t        <div>\r\n\t\t\t\t\t\t          <span class=\"btn btn-white btn-file\"><span class=\"fileinput-new\">选择图片</span><span class=\"fileinput-exists\">更改</span><input type=\"file\"></span>\r\n\t\t\t\t\t\t          <a href=\"javascript:;\" class=\"btn btn-white fileinput-exists\" data-dismiss=\"fileinput\">清除</a>\r\n\t\t\t\t\t\t        </div>\r\n\t\t\t\t\t\t      </div>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jasny-bootstrap\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jasny-bootstrap</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>固定格式文本 <small>https://github.com/jasny/bootstrap</small></h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">手机号码格式</label>\r\n                             <input type=\"text\" class=\"form-control\" data-mask=\"999-9999-9999\" placeholder=\"请输入手机号码\">\r\n                             <span class=\"help-block\">158-8888-88888</span>\r\n                       \t </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">电话号码格式</label>\r\n                            <input type=\"text\" class=\"form-control\" data-mask=\"9999-9999999\" placeholder=\"请输入电话号码\">\r\n                            <span class=\"help-block\">0730-8888888</span>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">日期格式</label>\r\n                            <input type=\"text\" class=\"form-control\" data-mask=\"9999-99-99\" placeholder=\"请输入日期格式\">\r\n                            <span class=\"help-block\">yyyy-mm-dd</span>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">IPV4格式</label>\r\n                            <input type=\"text\" class=\"form-control\" data-mask=\"999.999.999.999\" placeholder=\"请输入IP地址\">\r\n                            <span class=\"help-block\">192.168.100.200</span>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">税务代码格式</label>\r\n                            <input type=\"text\" class=\"form-control\" data-mask=\"99-9999999\" placeholder=\"请输入税务代码\">\r\n                            <span class=\"help-block\">99-9999999</span>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jasny-bootstrap\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jasny-bootstrap</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: jasny-bootstrap-js\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/labels_tips.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('标签 & 提示')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeIn\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>徽章 (Badges)</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <p>\r\n                            要添加徽章，只需要在元素上添加<code>.badge</code>即可，改变徽章的颜色可使用如下class，如<code>.badge-primary</code>。\r\n                        </p>\r\n                        <p><span class=\"badge\">空</span>\r\n                        </p>\r\n                        <p><span class=\"badge badge-primary\">badge-primary</span>\r\n                        </p>\r\n                        <p><span class=\"badge badge-info\">badge-info</span>\r\n                        </p>\r\n                        <p><span class=\"badge badge-success\">badge-success</span>\r\n                        </p>\r\n                        <p><span class=\"badge badge-warning\">badge-warning</span>\r\n                        </p>\r\n                        <p><span class=\"badge badge-danger\">badge-danger</span>\r\n                        </p>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>标签 (Labels)</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <p>\r\n                            要添加徽章，只需要在元素上添加class<code>.label</code>即可，如果需要修改颜色，添加如下class，如<code>.label-primary</code>\r\n                        </p>\r\n                        <p><span class=\"label\">空</span>\r\n                        </p>\r\n                        <p><span class=\"label label-primary\">label-primary</span>\r\n                        </p>\r\n                        <p><span class=\"label label-info\">label-info</span>\r\n                        </p>\r\n                        <p><span class=\"label label-success\">label-success</span>\r\n                        </p>\r\n                        <p><span class=\"label label-warning\">label-warning</span>\r\n                        </p>\r\n                        <p><span class=\"label label-danger\">label-danger</span>\r\n                        </p>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        \r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>通知样式</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"alert alert-success\">\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                        <div class=\"alert alert-info\">\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                        <div class=\"alert alert-warning\">\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                        <div class=\"alert alert-danger\">\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>带关闭按钮的通知样式</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"alert alert-success alert-dismissable\">\r\n                            <button aria-hidden=\"true\" data-dismiss=\"alert\" class=\"close\" type=\"button\">×</button>\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                        <div class=\"alert alert-info alert-dismissable\">\r\n                            <button aria-hidden=\"true\" data-dismiss=\"alert\" class=\"close\" type=\"button\">×</button>\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                        <div class=\"alert alert-warning alert-dismissable\">\r\n                            <button aria-hidden=\"true\" data-dismiss=\"alert\" class=\"close\" type=\"button\">×</button>\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                        <div class=\"alert alert-danger alert-dismissable\">\r\n                            <button aria-hidden=\"true\" data-dismiss=\"alert\" class=\"close\" type=\"button\">×</button>\r\n                            RuoYi是一个很棒的后台UI框架 <a class=\"alert-link\" href=\"javascript:;\">了解更多</a>.\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        \r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>工具提示</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"text-center\">\r\n                        <h4>工具提示示例 <small>深色背景</small></h4>\r\n                        <div>\r\n                            <button type=\"button\" class=\"btn btn-default\" data-toggle=\"tooltip\" data-placement=\"left\" title=\"这里是提示内容\">左侧提示</button>\r\n                            <button type=\"button\" class=\"btn btn-default\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"这里是提示内容\">顶部提示</button>\r\n                            <button type=\"button\" class=\"btn btn-default\" data-toggle=\"tooltip\" data-placement=\"bottom\" title=\"这里是提示内容\">底部提示</button>\r\n                            <button type=\"button\" class=\"btn btn-default\" data-toggle=\"tooltip\" data-placement=\"right\" title=\"这里是提示内容\">右侧提示</button>\r\n                        </div>\r\n                        <br>\r\n                        <h4>工具提示 - 单击提示</h4>\r\n                        <div class=\"text-center\" >\r\n                            <button type=\"button\" class=\"btn btn-primary\"  data-toggle=\"popover\" data-placement=\"auto left\" data-content=\"气泡提示\">\r\n                                气泡提示左\r\n                            </button>\r\n                            <button type=\"button\" class=\"btn btn-primary\"  data-toggle=\"popover\" data-placement=\"auto top\" data-content=\"气泡提示\">\r\n                                气泡提示顶部\r\n                            </button>\r\n                            <button type=\"button\" class=\"btn btn-primary\"  data-toggle=\"popover\" data-placement=\"auto bottom\" data-content=\"气泡提示\">\r\n                                气泡提示底部\r\n                            </button>\r\n                            <button type=\"button\" class=\"btn btn-primary\" data-toggle=\"popover\" data-placement=\"auto right\" data-content=\"气泡提示\">\r\n                                气泡提示右\r\n                            </button>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        \r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n\t    $(\"[data-toggle='tooltip']\").tooltip();\r\n\t    $(\"[data-toggle=popover]\").popover();\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/localrefresh.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n<th:block th:include=\"include :: header('局部刷新')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-4\">\r\n\t\t\t\t<div class=\"ibox\">\r\n\t\t\t\t\t<div class=\"ibox-content\">\r\n\t\t\t\t\t\t<h3>任务列表</h3>\r\n\t\t\t\t\t\t<p class=\"small\">\r\n\t\t\t\t\t\t\t<i class=\"fa fa-hand-o-up\"></i>\r\n\t\t\t\t\t\t\t点击刷新按钮刷新数据到列表中\r\n\t\t\t\t\t\t</p>\r\n\r\n\t\t\t\t\t\t<div class=\"input-group\">\r\n\t\t\t\t\t\t\t<input id=\"task-name\" type=\"text\" placeholder=\"任务名称\" class=\"input input-sm form-control\">\r\n\t\t\t\t\t\t\t<span class=\"input-group-btn\">\r\n\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-sm btn-white\" onclick=\"refresh()\">\r\n\t\t\t\t\t\t\t\t\t<i class=\"fa fa-refresh\"></i>\r\n\t\t\t\t\t\t\t\t\t刷新\r\n\t\t\t\t\t\t\t\t</button>\r\n\t\t\t\t\t\t\t</span>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t<div id=\"tasklist\">\r\n\t\t\t\t\t\t\t<ul class=\"sortable-list connectList agile-list\" th:fragment=\"fragment-tasklist\">\r\n\t\t\t\t\t\t\t\t<li th:if=\"${tasks != null}\" th:each=\"item : ${tasks}\" class=\"warning-element\">\r\n\t\t\t\t\t\t\t\t\t[[${item.name}]]\r\n\t\t\t\t\t\t\t\t\t<div class=\"agile-detail\">\r\n\t\t\t\t\t\t\t\t\t\t<a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">[[${item.type}]]</a>\r\n\t\t\t\t\t\t\t\t\t\t<i class=\"fa fa-clock-o\"></i>\r\n\t\t\t\t\t\t\t\t\t\t[[${item.date}]]\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script>\r\n\t\tfunction refresh(){\r\n\t\t\t$.ajax({\r\n\t\t\t\ttype: \"post\",\r\n\t\t\t\turl: ctx + \"demo/form/localrefresh/task\",\r\n\t\t\t\tdata: {\r\n\t\t\t\t\t\"taskName\": $(\"#task-name\").val()\r\n\t\t\t\t},\r\n\t\t\t\tsuccess: function(data) {\r\n\t\t\t\t\t$(\"#tasklist\").html(data);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/progress_bars.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('进度条')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>进度条 (Progress Bars)</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <!-- style: progress-bar-success/progress-bar-info/progress-bar-warning/progress-bar-danger -->\r\n                        <h5>基本</h5>\r\n                        <div class=\"progress\">\r\n                            <div style=\"width: 35%\" aria-valuemax=\"100\" aria-valuemin=\"0\" aria-valuenow=\"35\" role=\"progressbar\" class=\"progress-bar progress-bar-success\">\r\n                                <span class=\"sr-only\">35% Complete (success)</span>\r\n                            </div>\r\n                        </div>\r\n\r\n                        <div class=\"progress progress-bar-default\">\r\n                            <div style=\"width: 43%\" aria-valuemax=\"100\" aria-valuemin=\"0\" aria-valuenow=\"43\" role=\"progressbar\" class=\"progress-bar\">\r\n                                <span class=\"sr-only\">43% Complete (success)</span>\r\n                            </div>\r\n                        </div>\r\n\r\n                        <h5>条纹效果</h5>\r\n                        <div class=\"progress progress-striped\">\r\n                            <div style=\"width: 50%\" aria-valuemax=\"100\" aria-valuemin=\"0\" aria-valuenow=\"50\" role=\"progressbar\" class=\"progress-bar progress-bar-warning\">\r\n                                <span class=\"sr-only\">50% Complete (success)</span>\r\n                            </div>\r\n                        </div>\r\n\r\n                        <h5>动画效果</h5>\r\n                        <div class=\"progress progress-striped active\">\r\n                            <div style=\"width: 75%\" aria-valuemax=\"100\" aria-valuemin=\"0\" aria-valuenow=\"75\" role=\"progressbar\" class=\"progress-bar progress-bar-danger\">\r\n                                <span class=\"sr-only\">75% Complete (success)</span>\r\n                            </div>\r\n                        </div>\r\n\r\n                        <h5>堆叠效果</h5>\r\n                        <div class=\"progress progress-striped active\">\r\n                            <div style=\"width: 30%\" class=\"progress-bar progress-bar-success\">\r\n                                <span class=\"sr-only\">30% Complete (success)</span>\r\n                            </div>\r\n                            <div style=\"width: 20%\" class=\"progress-bar progress-bar-warning\">\r\n                                <span class=\"sr-only\">20% Complete (warning)</span>\r\n                            </div>\r\n                            <div style=\"width: 40%\" class=\"progress-bar progress-bar-danger\">\r\n                                <span class=\"sr-only\">40% Complete (danger)</span>\r\n                            </div>\r\n                        </div>\r\n                        \r\n                        <h5>带有提示标签的进度条</h5>\r\n                        <div class=\"progress\">\r\n                            <div class=\"progress-bar\" role=\"progressbar\" aria-valuenow=\"95\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 95%;\">\r\n                                95%\r\n                            </div>\r\n                        </div>\r\n\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n\t    $(\"[data-toggle='tooltip']\").tooltip();\r\n\t    $(\"[data-toggle=popover]\").popover();\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/select.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('下拉框')\" />\r\n\t<th:block th:include=\"include :: select2-css\" />\r\n\t<th:block th:include=\"include :: bootstrap-select-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <form>\r\n      <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>下拉框 <small>https://github.com/select2/select2</small></h5>\r\n                    </div>  \r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">单选</label>\r\n                            <select class=\"form-control\">\r\n                            \t<option value=\"\">--请选择开发语言--</option>\r\n                            \t<option value=\"Java\">Java</option>\r\n                            \t<option value=\"PHP\">PHP</option>\r\n                            \t<option value=\".NET\">.NET</option>\r\n                            </select>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                             <label class=\"font-noraml\">分组单选</label>\r\n                             <select class=\"form-control\">\r\n                               <optgroup label=\"--请选择开发语言--\">\r\n\t\t\t\t\t\t\t\t <option value=\"Java\">Java</option>\r\n                                 <option value=\"PHP\">PHP</option>\r\n                                 <option value=\".NET\">.NET</option>\r\n\t\t\t\t\t\t\t   </optgroup>\r\n\t\t\t\t\t\t\t   <optgroup label=\"--请选择数据库--\">\r\n\t\t\t\t\t\t\t     <option value=\"Oracle\">Oracle</option>\r\n                                 <option value=\"Mysql\">Mysql</option>\r\n                                 <option value=\"Sysbase\">Sysbase</option>\r\n\t\t\t\t\t\t       </optgroup>\r\n                             </select>\r\n                        </div>\r\n\t\t\t\t\t\t  \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">多选</label>\r\n                            <select class=\"form-control select2-multiple\" multiple>\r\n                            \t<option value=\"\">请选择开发语言</option>\r\n                            \t<option value=\"Java\">Java</option>\r\n                            \t<option value=\"PHP\">PHP</option>\r\n                            \t<option value=\".NET\">.NET</option>\r\n                            </select>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                             <label class=\"font-noraml\">分组多选</label>\r\n                             <select class=\"form-control select2-multiple\" multiple>\r\n                               <optgroup label=\"--请选择开发语言--\">\r\n\t\t\t\t\t\t\t\t <option value=\"Java\">Java</option>\r\n                                 <option value=\"PHP\">PHP</option>\r\n                                 <option value=\".NET\">.NET</option>\r\n\t\t\t\t\t\t\t   </optgroup>\r\n\t\t\t\t\t\t\t   <optgroup label=\"--请选择数据库--\">\r\n\t\t\t\t\t\t\t     <option value=\"Oracle\">Oracle</option>\r\n                                 <option value=\"Mysql\">Mysql</option>\r\n                                 <option value=\"Sysbase\">Sysbase</option>\r\n\t\t\t\t\t\t       </optgroup>\r\n                             </select>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#select2\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#select2</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>下拉框 <small>https://github.com/snapappointments/bootstrap-select</small></h5>\r\n                    </div>\r\n                     <div class=\"ibox-content\">\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">单选</label>\r\n                            <select class=\"form-control noselect2 selectpicker\">\r\n                            \t<option value=\"\">--请选择开发语言--</option>\r\n                            \t<option value=\"Java\">Java</option>\r\n                            \t<option value=\"PHP\">PHP</option>\r\n                            \t<option value=\".NET\">.NET</option>\r\n                            </select>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                             <label class=\"font-noraml\">分组单选</label>\r\n                             <select class=\"form-control noselect2 selectpicker\">\r\n                               <optgroup label=\"--请选择开发语言--\">\r\n\t\t\t\t\t\t\t\t <option value=\"Java\">Java</option>\r\n                                 <option value=\"PHP\">PHP</option>\r\n                                 <option value=\".NET\">.NET</option>\r\n\t\t\t\t\t\t\t   </optgroup>\r\n\t\t\t\t\t\t\t   <optgroup label=\"--请选择数据库--\">\r\n\t\t\t\t\t\t\t     <option value=\"Oracle\">Oracle</option>\r\n                                 <option value=\"Mysql\">Mysql</option>\r\n                                 <option value=\"Sysbase\">Sysbase</option>\r\n\t\t\t\t\t\t       </optgroup>\r\n                             </select>\r\n                        </div>\r\n\t\t\t\t\t\t  \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">多选</label>\r\n                            <select class=\"form-control noselect2 selectpicker\" data-none-selected-text=\"请选择开发语言\" multiple>\r\n                            \t<option value=\"Java\">Java</option>\r\n                            \t<option value=\"PHP\">PHP</option>\r\n                            \t<option value=\".NET\">.NET</option>\r\n                            </select>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                             <label class=\"font-noraml\">分组多选</label>\r\n                             <select class=\"form-control noselect2 selectpicker\" data-none-selected-text=\"请选择\" multiple>\r\n                               <optgroup label=\"--请选择开发语言--\">\r\n\t\t\t\t\t\t\t\t <option value=\"Java\">Java</option>\r\n                                 <option value=\"PHP\">PHP</option>\r\n                                 <option value=\".NET\">.NET</option>\r\n\t\t\t\t\t\t\t   </optgroup>\r\n\t\t\t\t\t\t\t   <optgroup label=\"--请选择数据库--\">\r\n\t\t\t\t\t\t\t     <option value=\"Oracle\">Oracle</option>\r\n                                 <option value=\"Mysql\">Mysql</option>\r\n                                 <option value=\"Sysbase\">Sysbase</option>\r\n\t\t\t\t\t\t       </optgroup>\r\n                             </select>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-select\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-select</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n   </form>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: select2-js\" />\r\n    <th:block th:include=\"include :: bootstrap-select-js\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/sortable.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('拖动排序')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content  animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h3>任务列表</h3>\r\n                        <p class=\"small\"><i class=\"fa fa-hand-o-up\"></i> 在列表之间拖动任务面板</p>\r\n\r\n                        <div class=\"input-group\">\r\n                            <input type=\"text\" placeholder=\"添加新任务\" class=\"input input-sm form-control\">\r\n                            <span class=\"input-group-btn\">\r\n                                        <button type=\"button\" class=\"btn btn-sm btn-white\"> <i class=\"fa fa-plus\"></i> 添加</button>\r\n                                </span>\r\n                        </div>\r\n\r\n                        <ul class=\"sortable-list connectList agile-list\">\r\n                            <li class=\"warning-element\">\r\n                                加强过程管理，及时统计教育经费使用情况，做到底码清楚，\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标签</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.01\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"success-element\">\r\n                                支持财会人员的继续培训工作。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.05.12\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"info-element\">\r\n                                协同教导处搞好助学金、减免教科书费的工作。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.10\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"danger-element\">\r\n                                要求会计、出纳人员严格执行财务制度，遵守岗位职责，按时上报各种资料。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-primary\">确定</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.06.10\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"warning-element\">\r\n                                做好职工公费医疗工作，按时发放门诊费。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标签</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.09\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"warning-element\">\r\n                                有计划地把课本复习三至五遍。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-primary\">确定</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.08.04\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"success-element\">\r\n                                看一本高质量的高中语法书\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.05.12\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"info-element\">\r\n                                选择一份较好的英语报纸，通过阅读提高英语学习效果。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.10\r\n                                </div>\r\n                            </li>\r\n                        </ul>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h3>进行中</h3>\r\n                        <p class=\"small\"><i class=\"fa fa-hand-o-up\"></i> 在列表之间拖动任务面板</p>\r\n                        <ul class=\"sortable-list connectList agile-list\">\r\n                            <li class=\"success-element\">\r\n                                全面、较深入地掌握我们“产品”的功能、特色和优势并做到应用自如。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标签</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.01\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"success-element\">\r\n                                根据自己以前所了解的和从其他途径搜索到的信息，录入客户资料150家。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.05.12\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"warning-element\">\r\n                                锁定有意向客户20家。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.10\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"warning-element\">\r\n                                力争完成销售指标。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标签</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.09\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"info-element\">\r\n                                在总结和摸索中前进。\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-primary\">确定</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.08.04\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"success-element\">\r\n                                不断学习行业知识、产品知识，为客户带来实用介绍内容\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.05.12\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"danger-element\">\r\n                                先友后单：与客户发展良好友谊，转换销售员角色，处处为客户着想\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.11.04\r\n                                </div>\r\n                            </li>\r\n                        </ul>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h3>已完成</h3>\r\n                        <p class=\"small\"><i class=\"fa fa-hand-o-up\"></i> 在列表之间拖动任务面板</p>\r\n                        <ul class=\"sortable-list connectList agile-list\">\r\n                            <li class=\"info-element\">\r\n                                制定工作日程表\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.10\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"warning-element\">\r\n                                每天坚持打40个有效电话，挖掘潜在客户\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标签</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.09\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"warning-element\">\r\n                                拜访客户之前要对该客户做全面的了解(客户的潜在需求、职位、权限以及个人性格和爱好)\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标签</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.09.09\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"warning-element\">\r\n                                提高自己电话营销技巧，灵活专业地与客户进行电话交流\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-primary\">确定</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.08.04\r\n                                </div>\r\n                            </li>\r\n                            <li class=\"success-element\">\r\n                                通过电话销售过程中了解各盛市的设备仪器使用、采购情况及相关重要追踪人\r\n                                <div class=\"agile-detail\">\r\n                                    <a href=\"javascript:;\" class=\"pull-right btn btn-xs btn-white\">标记</a>\r\n                                    <i class=\"fa fa-clock-o\"></i> 2018.05.12\r\n                                </div>\r\n                            </li>\r\n\r\n                        </ul>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script th:src=\"@{/js/jquery-ui-1.10.4.min.js}\"></script>\r\n    <script>\r\n\t    $(document).ready(function () {\r\n\t        $(\".sortable-list\").sortable({connectWith: \".connectList\"}).disableSelection()\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/summernote.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n\t<th:block th:include=\"include :: header('Summernote富文本编辑器')\" />\n\t<th:block th:include=\"include :: summernote-css\" />\n</head>\n<body class=\"gray-bg\">\n    <div class=\"wrapper wrapper-content\">\n        <div class=\"row\">\n            <div class=\"col-sm-12\">\n                <div class=\"ibox float-e-margins\">\n                    <div class=\"ibox-title\">\n                        <h5>Summernote 富文本编辑器</h5>\n                    </div>\n                    <div class=\"ibox-content no-padding\">\n                        <div class=\"summernote\">\n                            <h2>若依后台管理系统</h2>\n                            <p>ruoyi是一个完全响应式，基于Bootstrap3.4.1最新版本开发的扁平化主题，她采用了主流的左右两栏式布局，使用了Html5+CSS3等现代技术，她提供了诸多的强大的可以重新组合的UI组件，并集成了最新的jQuery版本(v2.1.1)，当然，也集成了很多功能强大，用途广泛的就jQuery插件，她可以用于所有的Web应用程序，如<b>网站管理后台</b>，<b>网站会员中心</b>，<b>CMS</b>，<b>CRM</b>，<b>OA</b>等等，当然，您也可以对她进行深度定制，以做出更强系统。</p>\n                            <p>\n                                <b>当前版本：</b>v4.8.2\n                            </p>\n                            <p>\n                                <span class=\"label label-warning\">免费开源</span>\n                            </p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-sm-12\">\n                <div class=\"ibox float-e-margins\">\n                    <div class=\"ibox-content\">\n                        <h2>Summernote</h2>\n                        <p>\n                            Summernote是一个简单的基于Bootstrap的WYSIWYG富文本编辑器\n                        </p>\n                        <div class=\"alert alert-warning\"> 官方文档请参考：\n                            <a href=\"https://github.com/summernote/summernote\">https://github.com/summernote/summernote</a>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-sm-12\">\n                <div class=\"ibox float-e-margins\">\n                    <div class=\"ibox-title\">\n                        <h5>编辑/保存为html代码示例</h5>\n                        <button id=\"edit\" class=\"btn btn-primary btn-xs m-l-sm\" onclick=\"edit()\" type=\"button\">编辑</button>\n                        <button id=\"save\" class=\"btn btn-primary  btn-xs\" onclick=\"save()\" type=\"button\">保存</button>\n                    </div>\n                    <div class=\"ibox-content\" id=\"eg\">\n\n                        <div class=\"click2edit wrapper\">\n                            <h3>你好，若依 </h3>\n                            <p>H+是一个完全响应式，基于Bootstrap3.4.1最新版本开发的扁平化主题，她采用了主流的左右两栏式布局，使用了Html5+CSS3等现代技术，她提供了诸多的强大的可以重新组合的UI组件，并集成了最新的jQuery版本(v2.1.1)，当然，也集成了很多功能强大，用途广泛的就jQuery插件，她可以用于所有的Web应用程序，如<b>网站管理后台</b>，<b>网站会员中心</b>，<b>CMS</b>，<b>CRM</b>，<b>OA</b>等等，当然，您也可以对她进行深度定制，以做出更强系统。</p>\n                            <p>\n                                <b>当前版本：</b>v4.8.2\n                            </p>\n                            <p>\n                                <span class=\"label label-warning\">开源免费</span>\n                            </p>\n                        </div>\n\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n    <th:block th:include=\"include :: footer\" />\n    <th:block th:include=\"include :: summernote-js\" />\n    <script>\n        $(document).ready(function () {\n            $('.summernote').summernote({\n                lang: 'zh-CN'\n            });\n        });\n        var edit = function () {\n            $(\"#eg\").addClass(\"no-padding\");\n            $('.click2edit').summernote({\n                lang: 'zh-CN',\n                focus: true\n            });\n        };\n        var save = function () {\n            $(\"#eg\").removeClass(\"no-padding\");\n            var aHTML = $('.click2edit').summernote('code');\n            $('.click2edit').summernote('destroy');\n        };\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/tabs_panels.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('选项卡 & 面板')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeIn\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>基本面板 <small class=\"m-l-sm\">这是一个自定义面板</small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <h2>\r\n                            Bootstrap<br/>\r\n                        </h2>\r\n                        <p>\r\n                            简洁、直观、强悍的前端开发框架，让web开发更迅速、简单。</p>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"tabs-container\">\r\n                    <ul class=\"nav nav-tabs\">\r\n                        <li class=\"active\"><a data-toggle=\"tab\" href=\"#tab-1\" aria-expanded=\"true\"> 第一个选项卡</a>\r\n                        </li>\r\n                        <li class=\"\"><a data-toggle=\"tab\" href=\"#tab-2\" aria-expanded=\"false\">第二个选项卡</a>\r\n                        </li>\r\n                    </ul>\r\n                    <div class=\"tab-content\">\r\n                        <div id=\"tab-1\" class=\"tab-pane active\">\r\n                            <div class=\"panel-body\">\r\n                                <strong>HTML5 文档类型</strong>\r\n                                <p>Bootstrap 使用到的某些 HTML 元素和 CSS 属性需要将页面设置为 HTML5 文档类型。在你项目中的每个页面都要参照下面的格式进行设置。</p>\r\n                            </div>\r\n                        </div>\r\n                        <div id=\"tab-2\" class=\"tab-pane\">\r\n                            <div class=\"panel-body\">\r\n                                <strong>移动设备优先</strong>\r\n                                <p>在 Bootstrap 2 中，我们对框架中的某些关键部分增加了对移动设备友好的样式。而在 Bootstrap 3 中，我们重写了整个框架，使其一开始就是对移动设备友好的。这次不是简单的增加一些可选的针对移动设备的样式，而是直接融合进了框架的内核中。也就是说，Bootstrap 是移动设备优先的。针对移动设备的样式融合进了框架的每个角落，而不是增加一个额外的文件。</p>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n\r\n\r\n                </div>\r\n            </div>\r\n\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"panel blank-panel\">\r\n\r\n                    <div class=\"panel-heading\">\r\n                        <div class=\"panel-title m-b-md\">\r\n                            <h4>图标选项卡</h4>\r\n                        </div>\r\n                        <div class=\"panel-options\">\r\n\r\n                            <ul class=\"nav nav-tabs\">\r\n                                <li class=\"active\"><a data-toggle=\"tab\" href=\"#tab-4\"><i class=\"fa fa-laptop\"></i></a>\r\n                                </li>\r\n                                <li class=\"\"><a data-toggle=\"tab\" href=\"#tab-5\"><i class=\"fa fa-desktop\"></i></a>\r\n                                </li>\r\n                                <li class=\"\"><a data-toggle=\"tab\" href=\"#tab-6\"><i class=\"fa fa-signal\"></i></a>\r\n                                </li>\r\n                                <li class=\"\"><a data-toggle=\"tab\" href=\"#tab-7\"><i class=\"fa fa-bar-chart-o\"></i></a>\r\n                                </li>\r\n                            </ul>\r\n                        </div>\r\n                    </div>\r\n\r\n                    <div class=\"panel-body\">\r\n                        <div class=\"tab-content\">\r\n                            <div id=\"tab-4\" class=\"tab-pane active\">\r\n                                <strong>排版与链接</strong>\r\n\r\n                                <p>Bootstrap 排版、链接样式设置了基本的全局样式。分别是： 为 body 元素设置 background-color: #fff; 使用 @font-family-base、@font-size-base 和 @line-height-base a变量作为排版的基本参数 为所有链接设置了基本颜色 @link-color ，并且当链接处于 :hover 状态时才添加下划线 这些样式都能在 scaffolding.less 文件中找到对应的源码。</p>\r\n                            </div>\r\n\r\n                            <div id=\"tab-5\" class=\"tab-pane\">\r\n                                <strong>Normalize.css</strong>\r\n\r\n                                <p>为了增强跨浏览器表现的一致性，我们使用了 Normalize.css，这是由 Nicolas Gallagher 和 Jonathan Neal 维护的一个CSS 重置样式库。</p>\r\n                            </div>\r\n                            <div id=\"tab-6\" class=\"tab-pane\">\r\n                                <strong>布局容器</strong>\r\n\r\n                                <p>Bootstrap 需要为页面内容和栅格系统包裹一个 .container 容器。我们提供了两个作此用处的类。注意，由于 padding 等属性的原因，这两种 容器类不能互相嵌套。</p>\r\n                            </div>\r\n                            <div id=\"tab-7\" class=\"tab-pane\">\r\n                                <strong>栅格系统</strong>\r\n\r\n                                <p>Bootstrap 提供了一套响应式、移动设备优先的流式栅格系统，随着屏幕或视口（viewport）尺寸的增加，系统会自动分为最多12列。它包含了易于使用的预定义类，还有强大的mixin 用于生成更具语义的布局。</p>\r\n                            </div>\r\n                        </div>\r\n\r\n                    </div>\r\n\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row m-b-lg\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"tabs-container\">\r\n\r\n                    <div class=\"tabs-left\">\r\n                        <ul class=\"nav nav-tabs\">\r\n                            <li class=\"active\"><a data-toggle=\"tab\" href=\"#tab-8\"> 第一个选项卡</a>\r\n                            </li>\r\n                            <li class=\"\"><a data-toggle=\"tab\" href=\"#tab-9\"> 第二个选项卡</a>\r\n                            </li>\r\n                        </ul>\r\n                        <div class=\"tab-content \">\r\n                            <div id=\"tab-8\" class=\"tab-pane active\">\r\n                                <div class=\"panel-body\">\r\n                                    <strong>排版与链接</strong>\r\n\r\n                                    <p>Bootstrap 排版、链接样式设置了基本的全局样式。分别是： 为 body 元素设置 background-color: #fff; 使用 @font-family-base、@font-size-base 和 @line-height-base a变量作为排版的基本参数 为所有链接设置了基本颜色 @link-color ，并且当链接处于 :hover 状态时才添加下划线 这些样式都能在 scaffolding.less 文件中找到对应的源码。</p>\r\n                                </div>\r\n                            </div>\r\n                            <div id=\"tab-9\" class=\"tab-pane\">\r\n                                <div class=\"panel-body\">\r\n                                    <strong>栅格系统</strong>\r\n\r\n                                    <p>Bootstrap 提供了一套响应式、移动设备优先的流式栅格系统，随着屏幕或视口（viewport）尺寸的增加，系统会自动分为最多12列。它包含了易于使用的预定义类，还有强大的mixin 用于生成更具语义的布局。</p>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n\r\n                    </div>\r\n\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"tabs-container\">\r\n                    <div class=\"tabs-right\">\r\n                        <ul class=\"nav nav-tabs\">\r\n                            <li class=\"active\"><a data-toggle=\"tab\" href=\"#tab-10\">第一个选项卡</a>\r\n                            </li>\r\n                            <li class=\"\"><a data-toggle=\"tab\" href=\"#tab-11\"> 第二个选项卡</a>\r\n                            </li>\r\n                        </ul>\r\n                        <div class=\"tab-content \">\r\n                            <div id=\"tab-10\" class=\"tab-pane active\">\r\n                                <div class=\"panel-body\">\r\n                                    <strong>排版与链接</strong>\r\n\r\n                                    <p>Bootstrap 排版、链接样式设置了基本的全局样式。分别是： 为 body 元素设置 background-color: #fff; 使用 @font-family-base、@font-size-base 和 @line-height-base a变量作为排版的基本参数 为所有链接设置了基本颜色 @link-color ，并且当链接处于 :hover 状态时才添加下划线 这些样式都能在 scaffolding.less 文件中找到对应的源码。</p>\r\n                                </div>\r\n                            </div>\r\n                            <div id=\"tab-11\" class=\"tab-pane\">\r\n                                <div class=\"panel-body\">\r\n                                    <strong>栅格系统</strong>\r\n\r\n                                    <p>Bootstrap 提供了一套响应式、移动设备优先的流式栅格系统，随着屏幕或视口（viewport）尺寸的增加，系统会自动分为最多12列。它包含了易于使用的预定义类，还有强大的mixin 用于生成更具语义的布局。</p>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>Bootstrap面板 <small>自定义背景</small></h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n\r\n                        <div class=\"row\">\r\n                            <div class=\"col-sm-4\">\r\n                                <div class=\"panel panel-default\">\r\n                                    <div class=\"panel-heading\">\r\n                                        默认面板\r\n                                    </div>\r\n                                    <div class=\"panel-body\">\r\n                                        <p>通过 .panel-heading 可以很简单地为面板加入一个标题容器。你也可以通过添加设置了 .panel-title 类的标签，添加一个预定义样式的标题。 为了给链接设置合适的颜色，务必将链接放到带有 .panel-title 类的标题标签内。</p>\r\n                                    </div>\r\n\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"col-sm-4\">\r\n                                <div class=\"panel panel-primary\">\r\n                                    <div class=\"panel-heading\">\r\n                                        主要\r\n                                    </div>\r\n                                    <div class=\"panel-body\">\r\n                                        <p>通过 .panel-heading 可以很简单地为面板加入一个标题容器。你也可以通过添加设置了 .panel-title 类的标签，添加一个预定义样式的标题。 为了给链接设置合适的颜色，务必将链接放到带有 .panel-title 类的标题标签内。</p>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"col-sm-4\">\r\n                                <div class=\"panel panel-success\">\r\n                                    <div class=\"panel-heading\">\r\n                                        成功\r\n                                    </div>\r\n                                    <div class=\"panel-body\">\r\n                                        <p>通过 .panel-heading 可以很简单地为面板加入一个标题容器。你也可以通过添加设置了 .panel-title 类的标签，添加一个预定义样式的标题。 为了给链接设置合适的颜色，务必将链接放到带有 .panel-title 类的标题标签内。</p>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"row\">\r\n                            <div class=\"col-sm-4\">\r\n                                <div class=\"panel panel-info\">\r\n                                    <div class=\"panel-heading\">\r\n                                        <i class=\"fa fa-info-circle\"></i> 信息\r\n                                    </div>\r\n                                    <div class=\"panel-body\">\r\n                                        <p>通过 .panel-heading 可以很简单地为面板加入一个标题容器。你也可以通过添加设置了 .panel-title 类的标签，添加一个预定义样式的标题。 为了给链接设置合适的颜色，务必将链接放到带有 .panel-title 类的标题标签内。</p>\r\n                                    </div>\r\n\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"col-sm-4\">\r\n                                <div class=\"panel panel-warning\">\r\n                                    <div class=\"panel-heading\">\r\n                                        <i class=\"fa fa-warning\"></i> 警告\r\n                                    </div>\r\n                                    <div class=\"panel-body\">\r\n                                        <p>通过 .panel-heading 可以很简单地为面板加入一个标题容器。你也可以通过添加设置了 .panel-title 类的标签，添加一个预定义样式的标题。 为了给链接设置合适的颜色，务必将链接放到带有 .panel-title 类的标题标签内。</p>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"col-sm-4\">\r\n                                <div class=\"panel panel-danger\">\r\n                                    <div class=\"panel-heading\">\r\n                                        危险\r\n                                    </div>\r\n                                    <div class=\"panel-body\">\r\n                                        <p>通过 .panel-heading 可以很简单地为面板加入一个标题容器。你也可以通过添加设置了 .panel-title 类的标签，添加一个预定义样式的标题。 为了给链接设置合适的颜色，务必将链接放到带有 .panel-title 类的标题标签内。</p>\r\n                                    </div>\r\n                                    <div class=\"panel-footer\">\r\n                                        面板Footer\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>折叠面板</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"panel-body\">\r\n                            <div class=\"panel-group\" id=\"accordion\">\r\n                                <div class=\"panel panel-default\">\r\n                                    <div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n                                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseOne\">标题 #1</a>\r\n                                            </h5>\r\n                                    </div>\r\n                                    <div id=\"collapseOne\" class=\"panel-collapse collapse in\">\r\n                                        <div class=\"panel-body\">\r\n                                            Bootstrap相关优质项目推荐 这些项目或者是对Bootstrap进行了有益的补充，或者是基于Bootstrap开发的\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"panel panel-default\">\r\n                                    <div class=\"panel-heading\">\r\n                                        <h4 class=\"panel-title\">\r\n                                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseTwo\">标题 #2</a>\r\n                                            </h4>\r\n                                    </div>\r\n                                    <div id=\"collapseTwo\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            Bootstrap相关优质项目推荐 这些项目或者是对Bootstrap进行了有益的补充，或者是基于Bootstrap开发的\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"panel panel-default\">\r\n                                    <div class=\"panel-heading\">\r\n                                        <h4 class=\"panel-title\">\r\n                                                <a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapseThree\">标题 #3</a>\r\n                                            </h4>\r\n                                    </div>\r\n                                    <div id=\"collapseThree\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            Bootstrap相关优质项目推荐 这些项目或者是对Bootstrap进行了有益的补充，或者是基于Bootstrap开发的\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"jumbotron\">\r\n                    <h1>超大屏幕</h1>\r\n                    <p>Bootstrap 支持的另一个特性，超大屏幕（Jumbotron）。顾名思义该组件可以增加标题的大小，并为登录页面内容添加更多的外边距（margin）。使用超大屏幕（Jumbotron）的步骤如下：</p>\r\n                    <div class=\"alert alert-warning\">\r\n                        <ol>\r\n                            <li>创建一个带有 class .jumbotron. 的容器</li>\r\n                            <li>除了更大的 &lt;h1&gt;，字体粗细 font-weight 被减为 200px。</li>\r\n                        </ol>\r\n                    </div>\r\n\r\n                    <p><a role=\"button\" class=\"btn btn-primary btn-lg\">了解更多</a>\r\n                    </p>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/timeline.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>时间轴</title>\n\t<link href=\"../static/css/bootstrap.min.css\" th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../static/css/font-awesome.min.css\" th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../static/css/animate.min.css\" th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../static/css/style.min.css\" th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\n</head>\n<body class=\"gray-bg\">\n    <div class=\"row animated fadeInRight\">\n        <div class=\"ibox float-e-margins\">\n            <div class=\"text-center float-e-margins p-md\">\n                <span>打开/关闭颜色/背景或方向版本: </span>\n                <a href=\"javascript:;\" class=\"btn btn-xs btn-primary\" id=\"lightVersion\">轻型版本 </a>\n                <a href=\"javascript:;\" class=\"btn btn-xs btn-primary\" id=\"darkVersion\">黑色版本 </a>\n            </div>\n            <div id=\"ibox-content\">\n                 <div id=\"vertical-timeline\" class=\"vertical-container light-timeline\">\n                     <div class=\"vertical-timeline-block\">\n                         <div class=\"vertical-timeline-icon navy-bg\">\n                             <i class=\"fa fa-briefcase\"></i>\n                         </div>\n\n                         <div class=\"vertical-timeline-content\">\n                             <h2>会议</h2>\n                             <p>上一年的销售业绩发布会。总结产品营销和销售趋势及销售的现状。\n                             </p>\n                             <a href=\"javascript:;\" class=\"btn btn-sm btn-primary\"> 更多信息</a>\n                             <span class=\"vertical-date\">\n                         \t今天 <br>\n                         <small>2月3日</small>\n                     </span>\n                         </div>\n                     </div>\n\n                     <div class=\"vertical-timeline-block\">\n                         <div class=\"vertical-timeline-icon blue-bg\">\n                             <i class=\"fa fa-file-text\"></i>\n                         </div>\n\n                         <div class=\"vertical-timeline-content\">\n                             <h2>给张三发送文档</h2>\n                             <p>发送上年度《销售业绩报告》</p>\n                             <a href=\"javascript:;\" class=\"btn btn-sm btn-success\"> 下载文档 </a>\n                             <span class=\"vertical-date\">\n                         \t今天 <br>\n                         <small>2月3日</small>\n                     </span>\n                         </div>\n                     </div>\n\n                     <div class=\"vertical-timeline-block\">\n                         <div class=\"vertical-timeline-icon lazur-bg\">\n                             <i class=\"fa fa-coffee\"></i>\n                         </div>\n\n                         <div class=\"vertical-timeline-content\">\n                             <h2>喝咖啡休息</h2>\n                             <p>喝咖啡啦，啦啦啦~~</p>\n                             <a href=\"javascript:;\" class=\"btn btn-sm btn-info\">更多</a>\n                             <span class=\"vertical-date\"> 昨天 <br><small>2月2日</small></span>\n                         </div>\n                     </div>\n\n                     <div class=\"vertical-timeline-block\">\n                         <div class=\"vertical-timeline-icon yellow-bg\">\n                             <i class=\"fa fa-phone\"></i>\n                         </div>\n\n                         <div class=\"vertical-timeline-content\">\n                             <h2>给李四打电话</h2>\n                             <p>给李四打电话分配本月工作任务</p>\n                             <span class=\"vertical-date\">昨天 <br><small>2月2日</small></span>\n                         </div>\n                     </div>\n\n                     <div class=\"vertical-timeline-block\">\n                         <div class=\"vertical-timeline-icon lazur-bg\">\n                             <i class=\"fa fa-user-md\"></i>\n                         </div>\n\n                         <div class=\"vertical-timeline-content\">\n                             <h2>公司年会</h2>\n                             <p>发年终奖啦，啦啦啦~~</p>\n                             <span class=\"vertical-date\">前天 <br><small>2月1日</small></span>\n                         </div>\n                     </div>\n                 </div>\n             </div>\n        </div>\n    </div>\n    <th:block th:include=\"include :: footer\" />\n    <script>\n        $(document).ready(function(){\n            $('#lightVersion').click(function(event) {\n                event.preventDefault()\n                $('#ibox-content').removeClass('ibox-content');\n                $('#vertical-timeline').removeClass('dark-timeline');\n                $('#vertical-timeline').addClass('light-timeline');\n            });\n            $('#darkVersion').click(function(event) {\n                event.preventDefault()\n                $('#ibox-content').addClass('ibox-content');\n                $('#vertical-timeline').removeClass('light-timeline');\n                $('#vertical-timeline').addClass('dark-timeline');\n            });\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/upload.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('文件上传')\" />\r\n\t<th:block th:include=\"include :: bootstrap-fileinput-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n<div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>文件上传控件 <small>https://github.com/kartik-v/bootstrap-fileinput</small></h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                    \t<div class=\"form-group\">\r\n                            <label class=\"font-noraml\">单文件上传</label>\r\n\t                        <div class=\"file-loading\">\r\n\t\t\t\t\t            <input id=\"singleFile\" name=\"file\" type=\"file\">\r\n\t\t\t\t\t        </div>\r\n                        </div>\r\n                        \r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">多文件上传</label>\r\n\t                        <div class=\"file-loading\">\r\n\t\t\t\t\t            <input id=\"multipleFile\" name=\"files\" type=\"file\" multiple>\r\n\t\t\t\t\t        </div>\r\n                        </div>\r\n                        <hr>\r\n                        <div class=\"form-group\">\r\n                            <label class=\"font-noraml\">相关参数详细信息</label>\r\n                            <div><a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-fileinput\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#bootstrap-fileinput</a></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: bootstrap-fileinput-js\" />\r\n    <script th:inline=\"javascript\">\r\n    \r\n    $(document).ready(function () {\r\n    \t// 单图上传\r\n    \t$(\"#singleFile\").fileinput({\r\n            uploadUrl: ctx + 'common/upload',\r\n            maxFileCount: 1,\r\n            autoReplace: true\r\n        }).on('fileuploaded', function (event, data, previewId, index) {\r\n        \tvar rsp = data.response;\r\n            log.info(\"return url：\" + rsp.url)\r\n            log.info(\"reutrn fileName：\" + rsp.fileName)\r\n            log.info(\"reutrn newFileName：\" + rsp.newFileName)\r\n            log.info(\"return originalFilename：\" + rsp.originalFilename)\r\n        }).on('fileremoved', function (event, id, index) {\r\n            $(\"input[name='\" + event.currentTarget.id + \"']\").val('')\r\n        })\r\n        \r\n        // 多图上传\r\n        $(\"#multipleFile\").fileinput({\r\n            uploadUrl: ctx + 'common/uploads',\r\n            uploadAsync: false\r\n        }).on('filebatchuploadsuccess', function (event, data, previewId, index) {\r\n        \tvar rsp = data.response;\r\n        \tlog.info(\"return urls：\" + rsp.urls)\r\n            log.info(\"reutrn fileNames：\" + rsp.fileNames)\r\n            log.info(\"reutrn newFileNames：\" + rsp.newFileNames)\r\n            log.info(\"return originalFilenames：\" + rsp.originalFilenames)\r\n        }).on('fileremoved', function (event, id, index) {\r\n            $(\"input[name='\" + event.currentTarget.id + \"']\").val('')\r\n        })\r\n    });\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/validate.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表单校验')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n<div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>jQuery Validate 简介</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <p>jquery.validate.js 是一款优秀的jQuery表单验证插件。它具有如下特点：</p>\r\n                        <ul>\r\n                            <li>安装简单</li>\r\n                            <li>内置超过20种数据验证方法</li>\r\n                            <li>直列错误提示信息</li>\r\n                            <li>可扩展的数据验证方法</li>\r\n                            <li>使用内置的元数据或插件选项来指定您的验证规则</li>\r\n                            <li>优雅的交互设计</li>\r\n                        </ul>\r\n                        <p>官网：<a href=\"http://jqueryvalidation.org/\" target=\"_blank\">http://jqueryvalidation.org/</a>\r\n                        </p>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>简单示例</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <form class=\"form-horizontal m-t\" id=\"commentForm\">\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">姓名：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"cname\" name=\"name\" minlength=\"2\" type=\"text\" class=\"form-control\" required>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">E-mail：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"cemail\" type=\"email\" class=\"form-control\" name=\"email\" required>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">网站：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"curl\" type=\"url\" class=\"form-control\" name=\"url\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">说明：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <textarea id=\"ccomment\" name=\"comment\" class=\"form-control\" required></textarea>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <div class=\"col-sm-4 col-sm-offset-3\">\r\n                                    <button class=\"btn btn-primary\" type=\"submit\">提交</button>\r\n                                </div>\r\n                            </div>\r\n                        </form>\r\n                    </div>\r\n                </div>\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-content\">\r\n                        <p class=\"m-t\">更多示例请访问官方示例页面：<a href=\"http://jqueryvalidation.org/files/demo/\" target=\"_blank\">查看</a>\r\n                        </p>\r\n                        <p>中文API可参考：<a href=\"http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jquery-validate\" target=\"_blank\">http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jquery-validate</a>\r\n                        </p>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>完整验证表单</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <form class=\"form-horizontal m-t\" id=\"signupForm\">\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">姓氏：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"firstname\" name=\"firstname\" class=\"form-control\" type=\"text\">\r\n                                    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 这里写点提示的内容</span>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">名字：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"lastname\" name=\"lastname\" class=\"form-control\" type=\"text\" required>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">用户名：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"username\" name=\"username\" class=\"form-control\" type=\"text\" required>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">密码：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"password\" name=\"password\" class=\"form-control\" type=\"password\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">确认密码：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"confirm_password\" name=\"confirm_password\" class=\"form-control\" type=\"password\">\r\n                                    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 请再次输入您的密码</span>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <label class=\"col-sm-3 control-label\">E-mail：</label>\r\n                                <div class=\"col-sm-8\">\r\n                                    <input id=\"email\" name=\"email\" class=\"form-control\" type=\"email\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group\">\r\n                                <div class=\"col-sm-8 col-sm-offset-3\">\r\n                                    <button class=\"btn btn-primary\" type=\"submit\">提交</button>\r\n                                </div>\r\n                            </div>\r\n                        </form>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n    $(function(){\r\n        $(\"#commentForm\").validate();\r\n\r\n        var icon = \"<i class='fa fa-times-circle'></i> \";\r\n        $(\"#signupForm\").validate({\r\n            rules: {\r\n                firstname: \"required\",\r\n                lastname: \"required\",\r\n                username: {\r\n                    required: true,\r\n                    minlength: 2\r\n                },\r\n                password: {\r\n                    required: true,\r\n                    minlength: 5\r\n                },\r\n                confirm_password: {\r\n                    required: true,\r\n                    minlength: 5,\r\n                    equalTo: \"#password\"\r\n                },\r\n                email: {\r\n                    required: true,\r\n                    email: true\r\n                }\r\n            },\r\n            messages: {\r\n                firstname: icon + \"请输入你的姓\",\r\n                lastname: icon + \"请输入您的名字\",\r\n                username: {\r\n                    required: icon + \"请输入您的用户名\",\r\n                    minlength: icon + \"用户名必须两个字符以上\"\r\n                },\r\n                password: {\r\n                    required: icon + \"请输入您的密码\",\r\n                    minlength: icon + \"密码必须5个字符以上\"\r\n                },\r\n                confirm_password: {\r\n                    required: icon + \"请再次输入密码\",\r\n                    minlength: icon + \"密码必须5个字符以上\",\r\n                    equalTo: icon + \"两次输入的密码不一致\"\r\n                },\r\n                email: icon + \"请输入您的E-mail\"\r\n            }\r\n        });\r\n\r\n        $(\"#username\").focus(function () {\r\n            var firstname = $(\"#firstname\").val();\r\n            var lastname = $(\"#lastname\").val();\r\n            if (firstname && lastname && !this.value) {\r\n                this.value = firstname + \".\" + lastname;\r\n            }\r\n        });\r\n    });\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/form/wizard.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n<th:block th:include=\"include :: header('表单向导')\" />\r\n<th:block th:include=\"include :: jquery-smartwizard-css\" />\r\n<style type=\"text/css\">\r\n/* 如果要让工具栏固定在页面底部,使用下面的样式,不需要的可以注释 */\r\n.sw>.toolbar-bottom{\r\n\tz-index: 100;\r\n    bottom: 0px;\r\n    left: 0;\r\n    width: 100%;\r\n    position: fixed;\r\n    text-align: right;\r\n    background: #fff;\r\n    box-shadow: 0 -2px 6px 1px hsla(223,8%,83%,.5);\r\n    border-top: 1px solid #e3e4e8;\r\n}\r\n/* 如果设置了是否自动调节高度为false,需要加滚动条 */\r\n.sw>.tab-content{\r\n\toverflow-x: hidden;\r\n    overflow-y: auto;\r\n}\r\n/* 解决工具栏无法固定底部的问题（如果页面没有animated类可以不写这部分代码） */\r\n.animated {\r\n    animation-fill-mode: none;\r\n    -webkit-animation-fill-mode: none;\r\n    -moz-animation-fill-mode: none;\r\n    -o-animation-fill-mode: none;\r\n}\r\n</style>\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight\" style=\"height: 100%;\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12\">\r\n\t\t\t\t<div class=\"ibox\">\r\n\t\t\t\t\t<div class=\"ibox-title\">\r\n\t\t\t\t\t\t<h5>\r\n\t\t\t\t\t\t\t表单向导\r\n\t\t\t\t\t\t\t<small>https://github.com/techlab/jquery-smartwizard</small>\r\n\t\t\t\t\t\t</h5>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"ibox-content\">\r\n\t\t\t\t\t\t<div class=\"row select-list\" style=\"padding-left: 15px; margin-bottom: 10px;\">\r\n\t\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t\t选择样式：\r\n\t\t\t\t\t\t\t\t\t<select id=\"theme-selector\">\r\n\t\t\t\t\t\t\t\t\t\t<option value=\"default\">Default</option>\r\n\t\t\t\t\t\t\t\t\t\t<option value=\"arrows\" selected>Arrows</option>\r\n\t\t\t\t\t\t\t\t\t\t<option value=\"dots\">Dots</option>\r\n\t\t\t\t\t\t\t\t\t\t<option value=\"progress\">Progress</option>\r\n\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<!-- 快速操作栏按钮 -->\r\n\t\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t\t<div class=\"btn-group-sm\" role=\"group\">\r\n\t\t\t\t\t\t\t\t\t\t<a class=\"btn btn-info\" id=\"prev-btn\"> 上一步 </a>\r\n\t\t\t\t\t\t\t\t\t\t<a class=\"btn btn-success\" id=\"next-btn\"> 下一步 </a>\r\n\t\t\t\t\t\t\t\t\t\t<a class=\"btn btn-danger\" id=\"reset-btn\"> 重置 </a>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t</ul>\r\n\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t<div id=\"smartwizard\">\r\n\t\t\t\t\t\t\t<ul class=\"nav\">\r\n\t\t\t\t\t\t\t\t<li class=\"nav-item\">\r\n\t\t\t\t\t\t\t\t\t<a class=\"nav-link\" href=\"#step-1\"> 第一步 </a>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<li class=\"nav-item\">\r\n\t\t\t\t\t\t\t\t\t<a class=\"nav-link\" href=\"#step-2\"> 第二步 </a>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<li class=\"nav-item\">\r\n\t\t\t\t\t\t\t\t\t<a class=\"nav-link\" href=\"#step-3\"> 第三步 </a>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<li class=\"nav-item\">\r\n\t\t\t\t\t\t\t\t\t<a class=\"nav-link\" href=\"#step-4\"> 第四步 </a>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t\t\t<div class=\"tab-content\">\r\n\t\t\t\t\t\t\t\t<div id=\"step-1\" class=\"tab-pane\" role=\"tabpanel\" aria-labelledby=\"step-1\">\r\n\t\t\t\t\t\t\t\t\t<div>\r\n\t\t\t\t\t\t\t\t\t\t<form class=\"form form-horizontal m-t\">\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">姓氏：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input id=\"firstname\" name=\"firstname\" class=\"form-control\" type=\"text\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"help-block m-b-none\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa fa-info-circle\"></i>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t这里写点提示的内容\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label is-required\">名字：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input id=\"lastname\" name=\"lastname\" class=\"form-control\" type=\"text\" required>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label is-required\">用户名：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input id=\"username\" name=\"username\" class=\"form-control\" type=\"text\" required>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">密码：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input id=\"password\" name=\"password\" class=\"form-control\" type=\"password\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">确认密码：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input id=\"confirm_password\" name=\"confirm_password\" class=\"form-control\" type=\"password\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"help-block m-b-none\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa fa-info-circle\"></i>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t请再次输入您的密码\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">E-mail：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input id=\"email\" name=\"email\" class=\"form-control\" type=\"email\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t</form>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"step-2\" class=\"tab-pane\" role=\"tabpanel\" aria-labelledby=\"step-2\">\r\n\t\t\t\t\t\t\t\t\t<div>\r\n\t\t\t\t\t\t\t\t\t\t<form class=\"form form-horizontal m-t\">\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">性别：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<select name=\"sex\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_user_sex')}\">\r\n\t\t\t\t                \t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t            \t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">时间：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input id=\"time\" name=\"time\" class=\"form-control time-input\" type=\"text\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"form-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t</form>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"step-3\" class=\"tab-pane\" role=\"tabpanel\" aria-labelledby=\"step-3\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"m-t-md\">\r\n\t\t\t\t\t\t\t\t\t\t<p>1、如果不需要工具栏固定在页面底部, 将style中下面的部分取消注释<blockquote>.sw>.toolbar-bottom </blockquote></p>\r\n\t\t\t\t\t\t\t\t\t\t<p>2、如果设置了自动调节高度(autoAdjustHeight)为true, 将style中下面的部分取消注释<blockquote>.sw>.tab-content </blockquote></p>\r\n\t\t\t\t\t\t\t\t\t\t<p>3、工具栏的按钮样式会被表单插件中.btn样式覆盖导致bootstrap中的按钮样式无效, 如果需要改变按钮样式可以自己定义并提高优先级</blockquote></p>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"step-4\" class=\"tab-pane\" role=\"tabpanel\" aria-labelledby=\"step-4\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"m-t-md\">\r\n\t\t\t\t\t\t\t\t\t\t<h3>测试多行显示</h3>\r\n\t\t\t\t\t\t\t\t\t\t<pre style=\"overflow-x: hidden;\">\r\n$('#smartwizard').smartWizard({\r\n  selected: 0, // Initial selected step, 0 = first step\r\n  theme: 'default', // theme for the wizard, related css need to include for other than default theme\r\n  justified: true, // Nav menu justification. true/false\r\n  darkMode:false, // Enable/disable Dark Mode if the theme supports. true/false\r\n  autoAdjustHeight: true, // Automatically adjust content height\r\n  cycleSteps: false, // Allows to cycle the navigation of steps\r\n  backButtonSupport: true, // Enable the back button support\r\n  enableURLhash: true, // Enable selection of the step based on url hash\r\n  transition: {\r\n      animation: 'none', // Effect on navigation, none/fade/slide-horizontal/slide-vertical/slide-swing\r\n      speed: '400', // Transition animation speed\r\n      easing:'' // Transition animation easing. Not supported without a jQuery easing plugin\r\n  },\r\n  toolbarSettings: {\r\n      toolbarPosition: 'bottom', // none, top, bottom, both\r\n      toolbarButtonPosition: 'right', // left, right, center\r\n      showNextButton: true, // show/hide a Next button\r\n      showPreviousButton: true, // show/hide a Previous button\r\n      toolbarExtraButtons: [] // Extra buttons to show on toolbar, array of jQuery input/buttons elements\r\n  },\r\n  anchorSettings: {\r\n      anchorClickable: true, // Enable/Disable anchor navigation\r\n      enableAllAnchors: false, // Activates all anchors clickable all times\r\n      markDoneStep: true, // Add done state on navigation\r\n      markAllPreviousStepsAsDone: true, // When a step selected by url hash, all previous steps are marked done\r\n      removeDoneStepOnNavigateBack: false, // While navigate back done step after active step will be cleared\r\n      enableAnchorOnDoneStep: true // Enable/Disable the done steps navigation\r\n  },\r\n  keyboardSettings: {\r\n      keyNavigation: true, // Enable/Disable keyboard navigation(left and right keys are used if enabled)\r\n      keyLeft: [37], // Left key code\r\n      keyRight: [39] // Right key code\r\n  },\r\n  lang: { // Language variables for button\r\n      next: 'Next',\r\n      previous: 'Previous'\r\n  },\r\n  disabledSteps: [], // Array Steps disabled\r\n  errorSteps: [], // Highlight step with errors\r\n  hiddenSteps: [] // Hidden steps\r\n});\r\n\t\t\t\t\t\t\t\t\t\t</pre>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: jquery-smartwizard-js\" />\r\n\t<script>\r\n\t\t$(document).ready(function() {\r\n\t\t\t// 工具栏按钮\r\n            var btnFinish = $('<a id=\"btn-finish\"></a>').text('完成')\r\n                                             .addClass('btn btn-info')\r\n                                             .on('click', function(){ submit(); });\r\n            var btnCancel = $('<a id=\"btn-cancel\"></a>').text('取消')\r\n                                             .addClass('btn btn-danger')\r\n                                             .on('click', function(){ $('#smartwizard').smartWizard(\"reset\"); });\r\n           \t// 下面两个按钮是为了因为插件默认的是botton,这里换成<a>,也可以选择用样式替换,或者不替换\r\n            var btnNext = $('<a id=\"btn-next\"></a>').text('下一步')\r\n\t\t\t\t\t\t\t\t\t\t\t .addClass('btn btn-info')\r\n\t\t\t\t\t\t\t\t\t\t\t .on('click', function(){ $('#smartwizard').smartWizard(\"next\");});\r\n\t\t\tvar btnPrev = $('<a id=\"btn-prev\"></a>').text('上一步')\r\n\t\t\t\t\t\t\t\t\t\t\t .addClass('btn btn-success disabled')\r\n\t\t\t\t\t\t\t\t\t\t\t .on('click', function(){ $('#smartwizard').smartWizard(\"prev\"); });\r\n            // 初始化表单向导组件\r\n            $('#smartwizard').smartWizard({\r\n                theme: 'arrows', // default, arrows, dots, progress\r\n                autoAdjustHeight : false, // 自动调整高度, 默认true\r\n                enableURLhash:false, //开启URL hash,开启后点击浏览器前进后退按钮会执行下一步和上一步操作\r\n                transition: {\r\n                    animation: 'slide-horizontal', // Effect on navigation, none/fade/slide-horizontal/slide-vertical/slide-swing\r\n                },\r\n                toolbarSettings: {\r\n                \tshowNextButton: false,// 因为上面自定义了下一步按钮, 所以隐藏掉插件自带的按钮, 如果不使用自定义按钮, 需要改为true或者去掉该属性\r\n    \t\t\t\tshowPreviousButton: false,// 因为上面自定义了上一步按钮, 所以隐藏掉插件自带的按钮, 如果不使用自定义按钮, 需要改为true或者去掉该属性\r\n                    toolbarExtraButtons: [btnCancel,btnPrev,btnNext,btnFinish]// 扩展的按钮集合\r\n                }\r\n            });\r\n\t\t});\r\n\t\t\r\n\t\tfunction submit(){\r\n\t\t\tvar data = {};\r\n\t\t\t$('.form').each(function (index, form){\r\n\t\t\t\t// 这里可以使用$.common.formToJSON(formId);  需要在form上加id\r\n                $.each($(form).serializeArray(), function(i, field) {\r\n                 \t if(data[field.name]) {\r\n                 \t\tdata[field.name] += (\",\" + field.value);\r\n\t\t\t\t\t } else {\r\n\t\t\t\t\t\tdata[field.name] = field.value;\r\n                     }\r\n                });\r\n\t\t\t});\r\n\t\t\talert(JSON.stringify(data))\r\n\t\t}\r\n\t\t// 显示步骤时将触发事件\r\n        $(\"#smartwizard\").on(\"showStep\", function(e, anchorObject, stepNumber, stepDirection, stepPosition) {\r\n        \t// 下面按钮是快速操作栏的\r\n        \t$(\"#prev-btn\").removeClass('disabled');\r\n            $(\"#next-btn\").removeClass('disabled');\r\n        \t// 下面按钮是工具栏的\r\n        \t$(\"#btn-prev\").removeClass('disabled');\r\n            $(\"#btn-next\").removeClass('disabled');\r\n            $(\"#btn-finish\").removeClass('disabled');\r\n            if(stepPosition === 'first') {\r\n            \t$(\"#prev-btn\").addClass('disabled');// 快速操作栏（演示用）\r\n            \t$(\"#btn-prev\").addClass('disabled');\r\n\t\t\t\t$(\"#btn-finish\").addClass('disabled');\r\n            } else if(stepPosition === 'last') {\r\n            \t$(\"#next-btn\").addClass('disabled');// 快速操作栏（演示用）\r\n                $(\"#btn-next\").addClass('disabled');\r\n            } else {\r\n            \t$(\"#prev-btn\").removeClass('disabled');// 快速操作栏（演示用）\r\n                $(\"#next-btn\").removeClass('disabled');// 快速操作栏（演示用）\r\n                $(\"#btn-prev\").removeClass('disabled');\r\n                $(\"#btn-next\").removeClass('disabled');\r\n                $(\"#btn-finish\").addClass('disabled');\r\n            }\r\n        });\r\n\t\t\r\n\t\t// 该事件在离开某个步骤之前触发\r\n\t\t$(\"#smartwizard\").on(\"leaveStep\", function(e, anchorObject, currentStepNumber, nextStepNumber, stepDirection) {\r\n\t\t\tif(stepDirection == 'forward'){\r\n\t\t\t\tvar form = $(\"#step-\" + (currentStepNumber + 1)).find('.form');\r\n\t\t\t\tif(form.length > 0){\r\n\t\t\t\t\treturn form.validate().form();\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t});\r\n\t\t\r\n\t\t$(\"#theme-selector\").on(\"change\", function() {\r\n\t\t\t// Change theme\r\n\t\t\tvar options = {\r\n\t\t\t\ttheme : $(this).val()\r\n\t\t\t};\r\n\t\t\t$('#smartwizard').smartWizard(\"setOptions\", options);\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\t$(\"#reset-btn\").on(\"click\", function() {\r\n            // Reset wizard\r\n            $('#smartwizard').smartWizard(\"reset\");\r\n            return true;\r\n        });\r\n\r\n        $(\"#prev-btn\").on(\"click\", function() {\r\n            // Navigate previous\r\n            $('#smartwizard').smartWizard(\"prev\");\r\n            return true;\r\n        });\r\n\r\n        $(\"#next-btn\").on(\"click\", function() {\r\n            // Navigate next\r\n            $('#smartwizard').smartWizard(\"next\");\r\n            return true;\r\n        });\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/icon/fontawesome.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('fontawesome图标')\" />\r\n\t<style type=\"text/css\">\r\n\t\t.fontawesome-icon-list .fa-hover{cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;color:#222222;line-height:32px;height:32px;padding-left:10px;border-radius:4px;}\r\n\t\t.fontawesome-icon-list .fa-hover .fa{width:32px;font-size:14px;display:inline-block;text-align:right;margin-right:10px}\r\n\t\t.fontawesome-icon-list .fa-hover:hover{background-color:#1d9d74;color:#fff;text-decoration:none}\r\n\t\t.fontawesome-icon-list .fa-hover:hover .fa{font-size:30px !important;vertical-align:-6px}\r\n\t\t.fontawesome-icon-list .fa-hover .text-muted{color:#bbe2d5}\r\n\t</style>\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>所有图标 <small class=\"m-l-sm\">所有图标集合 - <a target=\"_blank\" href=\"http://fortawesome.github.io/Font-Awesome/icons/\">Font Awesome</a> </small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content icons-box\">\r\n\t                    <section id=\"web-application\">\r\n\t                        <h2 class=\"page-header\">Web应用程序图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-address-book\" aria-hidden=\"true\"></i>address-book</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-address-book-o\" aria-hidden=\"true\"></i>address-book-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-address-card\" aria-hidden=\"true\"></i>address-card</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-address-card-o\" aria-hidden=\"true\"></i>address-card-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-adjust\" aria-hidden=\"true\"></i>adjust</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-american-sign-language-interpreting\" aria-hidden=\"true\"></i>american-sign-language-interpreting</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-anchor\" aria-hidden=\"true\"></i>anchor</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-archive\" aria-hidden=\"true\"></i>archive</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-area-chart\" aria-hidden=\"true\"></i>area-chart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows\" aria-hidden=\"true\"></i>arrows</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows-h\" aria-hidden=\"true\"></i>arrows-h</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows-v\" aria-hidden=\"true\"></i>arrows-v</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-asl-interpreting\" aria-hidden=\"true\"></i>asl-interpreting <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-assistive-listening-systems\" aria-hidden=\"true\"></i>assistive-listening-systems</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-asterisk\" aria-hidden=\"true\"></i>asterisk</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-at\" aria-hidden=\"true\"></i>at</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-audio-description\" aria-hidden=\"true\"></i>audio-description</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-automobile\" aria-hidden=\"true\"></i>automobile <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-balance-scale\" aria-hidden=\"true\"></i>balance-scale</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ban\" aria-hidden=\"true\"></i>ban</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bank\" aria-hidden=\"true\"></i>bank <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bar-chart\" aria-hidden=\"true\"></i>bar-chart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bar-chart-o\" aria-hidden=\"true\"></i>bar-chart-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-barcode\" aria-hidden=\"true\"></i>barcode</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bars\" aria-hidden=\"true\"></i>bars</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bath\" aria-hidden=\"true\"></i>bath</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bathtub\" aria-hidden=\"true\"></i>bathtub <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery\" aria-hidden=\"true\"></i>battery <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-0\" aria-hidden=\"true\"></i>battery-0 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-1\" aria-hidden=\"true\"></i>battery-1 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-2\" aria-hidden=\"true\"></i>battery-2 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-3\" aria-hidden=\"true\"></i>battery-3 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-4\" aria-hidden=\"true\"></i>battery-4 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-empty\" aria-hidden=\"true\"></i>battery-empty</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-full\" aria-hidden=\"true\"></i>battery-full</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-half\" aria-hidden=\"true\"></i>battery-half</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-quarter\" aria-hidden=\"true\"></i>battery-quarter</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-battery-three-quarters\" aria-hidden=\"true\"></i>battery-three-quarters</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bed\" aria-hidden=\"true\"></i>bed</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-beer\" aria-hidden=\"true\"></i>beer</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bell\" aria-hidden=\"true\"></i>bell</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bell-o\" aria-hidden=\"true\"></i>bell-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bell-slash\" aria-hidden=\"true\"></i>bell-slash</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bell-slash-o\" aria-hidden=\"true\"></i>bell-slash-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bicycle\" aria-hidden=\"true\"></i>bicycle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-binoculars\" aria-hidden=\"true\"></i>binoculars</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-birthday-cake\" aria-hidden=\"true\"></i> birthday-cake</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-blind\" aria-hidden=\"true\"></i> blind</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bluetooth\" aria-hidden=\"true\"></i> bluetooth</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bluetooth-b\" aria-hidden=\"true\"></i> bluetooth-b</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bolt\" aria-hidden=\"true\"></i> bolt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bomb\" aria-hidden=\"true\"></i> bomb</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-book\" aria-hidden=\"true\"></i> book</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bookmark\" aria-hidden=\"true\"></i> bookmark</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bookmark-o\" aria-hidden=\"true\"></i> bookmark-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-braille\" aria-hidden=\"true\"></i> braille</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-briefcase\" aria-hidden=\"true\"></i> briefcase</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bug\" aria-hidden=\"true\"></i> bug</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-building\" aria-hidden=\"true\"></i> building</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-building-o\" aria-hidden=\"true\"></i> building-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bullhorn\" aria-hidden=\"true\"></i> bullhorn</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bullseye\" aria-hidden=\"true\"></i> bullseye</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bus\" aria-hidden=\"true\"></i> bus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cab\" aria-hidden=\"true\"></i> cab <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-calculator\" aria-hidden=\"true\"></i> calculator</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-calendar\" aria-hidden=\"true\"></i> calendar</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-calendar-check-o\" aria-hidden=\"true\"></i> calendar-check-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-calendar-minus-o\" aria-hidden=\"true\"></i> calendar-minus-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-calendar-o\" aria-hidden=\"true\"></i> calendar-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-calendar-plus-o\" aria-hidden=\"true\"></i> calendar-plus-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-calendar-times-o\" aria-hidden=\"true\"></i> calendar-times-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-camera\" aria-hidden=\"true\"></i> camera</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-camera-retro\" aria-hidden=\"true\"></i> camera-retro</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-car\" aria-hidden=\"true\"></i> car</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-down\" aria-hidden=\"true\"></i> caret-square-o-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-left\" aria-hidden=\"true\"></i> caret-square-o-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-right\" aria-hidden=\"true\"></i> caret-square-o-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-up\" aria-hidden=\"true\"></i> caret-square-o-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cart-arrow-down\" aria-hidden=\"true\"></i> cart-arrow-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cart-plus\" aria-hidden=\"true\"></i> cart-plus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc\" aria-hidden=\"true\"></i> cc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-certificate\" aria-hidden=\"true\"></i> certificate</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-check\" aria-hidden=\"true\"></i> check</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-check-circle\" aria-hidden=\"true\"></i> check-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-check-circle-o\" aria-hidden=\"true\"></i> check-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-check-square\" aria-hidden=\"true\"></i> check-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-check-square-o\" aria-hidden=\"true\"></i> check-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-child\" aria-hidden=\"true\"></i> child</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-circle\" aria-hidden=\"true\"></i> circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-circle-o\" aria-hidden=\"true\"></i> circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-circle-o-notch\" aria-hidden=\"true\"></i> circle-o-notch</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-circle-thin\" aria-hidden=\"true\"></i> circle-thin</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-clock-o\" aria-hidden=\"true\"></i> clock-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-clone\" aria-hidden=\"true\"></i> clone</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-close\" aria-hidden=\"true\"></i> close <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cloud\" aria-hidden=\"true\"></i> cloud</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cloud-download\" aria-hidden=\"true\"></i> cloud-download</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cloud-upload\" aria-hidden=\"true\"></i> cloud-upload</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-code\" aria-hidden=\"true\"></i> code</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-code-fork\" aria-hidden=\"true\"></i> code-fork</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-coffee\" aria-hidden=\"true\"></i> coffee</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cog\" aria-hidden=\"true\"></i> cog</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cogs\" aria-hidden=\"true\"></i> cogs</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-comment\" aria-hidden=\"true\"></i> comment</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-comment-o\" aria-hidden=\"true\"></i> comment-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-commenting\" aria-hidden=\"true\"></i> commenting</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-commenting-o\" aria-hidden=\"true\"></i> commenting-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-comments\" aria-hidden=\"true\"></i> comments</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-comments-o\" aria-hidden=\"true\"></i> comments-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-compass\" aria-hidden=\"true\"></i> compass</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-copyright\" aria-hidden=\"true\"></i> copyright</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-creative-commons\" aria-hidden=\"true\"></i> creative-commons</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-credit-card\" aria-hidden=\"true\"></i> credit-card</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-credit-card-alt\" aria-hidden=\"true\"></i> credit-card-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-crop\" aria-hidden=\"true\"></i> crop</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-crosshairs\" aria-hidden=\"true\"></i> crosshairs</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cube\" aria-hidden=\"true\"></i> cube</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cubes\" aria-hidden=\"true\"></i> cubes</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cutlery\" aria-hidden=\"true\"></i> cutlery</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dashboard\" aria-hidden=\"true\"></i> dashboard <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-database\" aria-hidden=\"true\"></i> database</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-deaf\" aria-hidden=\"true\"></i> deaf</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-deafness\" aria-hidden=\"true\"></i> deafness <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-desktop\" aria-hidden=\"true\"></i> desktop</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-diamond\" aria-hidden=\"true\"></i> diamond</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dot-circle-o\" aria-hidden=\"true\"></i> dot-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-download\" aria-hidden=\"true\"></i> download</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-drivers-license\" aria-hidden=\"true\"></i> drivers-license <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-drivers-license-o\" aria-hidden=\"true\"></i> drivers-license-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-edit\" aria-hidden=\"true\"></i> edit <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ellipsis-h\" aria-hidden=\"true\"></i> ellipsis-h</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ellipsis-v\" aria-hidden=\"true\"></i> ellipsis-v</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-envelope\" aria-hidden=\"true\"></i> envelope</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-envelope-o\" aria-hidden=\"true\"></i> envelope-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-envelope-open\" aria-hidden=\"true\"></i> envelope-open</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-envelope-open-o\" aria-hidden=\"true\"></i> envelope-open-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-envelope-square\" aria-hidden=\"true\"></i> envelope-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eraser\" aria-hidden=\"true\"></i> eraser</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-exchange\" aria-hidden=\"true\"></i> exchange</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-exclamation\" aria-hidden=\"true\"></i> exclamation</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-exclamation-circle\" aria-hidden=\"true\"></i> exclamation-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-exclamation-triangle\" aria-hidden=\"true\"></i> exclamation-triangle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-external-link\" aria-hidden=\"true\"></i> external-link</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-external-link-square\" aria-hidden=\"true\"></i> external-link-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eye\" aria-hidden=\"true\"></i> eye</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eye-slash\" aria-hidden=\"true\"></i> eye-slash</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eyedropper\" aria-hidden=\"true\"></i> eyedropper</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fax\" aria-hidden=\"true\"></i> fax</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-feed\" aria-hidden=\"true\"></i> feed <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-female\" aria-hidden=\"true\"></i> female</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fighter-jet\" aria-hidden=\"true\"></i> fighter-jet</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-archive-o\" aria-hidden=\"true\"></i> file-archive-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-audio-o\" aria-hidden=\"true\"></i> file-audio-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-code-o\" aria-hidden=\"true\"></i> file-code-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-excel-o\" aria-hidden=\"true\"></i> file-excel-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-image-o\" aria-hidden=\"true\"></i> file-image-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-movie-o\" aria-hidden=\"true\"></i> file-movie-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-pdf-o\" aria-hidden=\"true\"></i> file-pdf-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-photo-o\" aria-hidden=\"true\"></i> file-photo-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-picture-o\" aria-hidden=\"true\"></i> file-picture-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-powerpoint-o\" aria-hidden=\"true\"></i> file-powerpoint-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-sound-o\" aria-hidden=\"true\"></i> file-sound-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-video-o\" aria-hidden=\"true\"></i> file-video-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-word-o\" aria-hidden=\"true\"></i> file-word-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-zip-o\" aria-hidden=\"true\"></i> file-zip-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-film\" aria-hidden=\"true\"></i> film</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-filter\" aria-hidden=\"true\"></i> filter</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fire\" aria-hidden=\"true\"></i> fire</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fire-extinguisher\" aria-hidden=\"true\"></i> fire-extinguisher</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-flag\" aria-hidden=\"true\"></i> flag</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-flag-checkered\" aria-hidden=\"true\"></i> flag-checkered</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-flag-o\" aria-hidden=\"true\"></i> flag-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-flash\" aria-hidden=\"true\"></i> flash <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-flask\" aria-hidden=\"true\"></i> flask</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-folder\" aria-hidden=\"true\"></i> folder</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-folder-o\" aria-hidden=\"true\"></i> folder-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-folder-open\" aria-hidden=\"true\"></i> folder-open</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-folder-open-o\" aria-hidden=\"true\"></i> folder-open-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-frown-o\" aria-hidden=\"true\"></i> frown-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-futbol-o\" aria-hidden=\"true\"></i> futbol-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gamepad\" aria-hidden=\"true\"></i> gamepad</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gavel\" aria-hidden=\"true\"></i> gavel</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gear\" aria-hidden=\"true\"></i> gear <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gears\" aria-hidden=\"true\"></i> gears <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gift\" aria-hidden=\"true\"></i> gift</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-glass\" aria-hidden=\"true\"></i> glass</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-globe\" aria-hidden=\"true\"></i> globe</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-graduation-cap\" aria-hidden=\"true\"></i> graduation-cap</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-group\" aria-hidden=\"true\"></i> group <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-grab-o\" aria-hidden=\"true\"></i> hand-grab-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-lizard-o\" aria-hidden=\"true\"></i> hand-lizard-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-paper-o\" aria-hidden=\"true\"></i> hand-paper-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-peace-o\" aria-hidden=\"true\"></i> hand-peace-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-pointer-o\" aria-hidden=\"true\"></i> hand-pointer-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-rock-o\" aria-hidden=\"true\"></i> hand-rock-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-scissors-o\" aria-hidden=\"true\"></i> hand-scissors-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-spock-o\" aria-hidden=\"true\"></i> hand-spock-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-stop-o\" aria-hidden=\"true\"></i> hand-stop-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-handshake-o\" aria-hidden=\"true\"></i> handshake-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hard-of-hearing\" aria-hidden=\"true\"></i> hard-of-hearing <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hashtag\" aria-hidden=\"true\"></i> hashtag</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hdd-o\" aria-hidden=\"true\"></i> hdd-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-headphones\" aria-hidden=\"true\"></i> headphones</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-heart\" aria-hidden=\"true\"></i> heart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-heart-o\" aria-hidden=\"true\"></i> heart-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-heartbeat\" aria-hidden=\"true\"></i> heartbeat</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-history\" aria-hidden=\"true\"></i> history</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-home\" aria-hidden=\"true\"></i> home</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hotel\" aria-hidden=\"true\"></i> hotel <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass\" aria-hidden=\"true\"></i> hourglass</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass-1\" aria-hidden=\"true\"></i> hourglass-1 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass-2\" aria-hidden=\"true\"></i> hourglass-2 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass-3\" aria-hidden=\"true\"></i> hourglass-3 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass-end\" aria-hidden=\"true\"></i> hourglass-end</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass-half\" aria-hidden=\"true\"></i> hourglass-half</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass-o\" aria-hidden=\"true\"></i> hourglass-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hourglass-start\" aria-hidden=\"true\"></i> hourglass-start</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-i-cursor\" aria-hidden=\"true\"></i> i-cursor</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-id-badge\" aria-hidden=\"true\"></i> id-badge</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-id-card\" aria-hidden=\"true\"></i> id-card</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-id-card-o\" aria-hidden=\"true\"></i> id-card-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-image\" aria-hidden=\"true\"></i> image <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-inbox\" aria-hidden=\"true\"></i> inbox</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-industry\" aria-hidden=\"true\"></i> industry</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-info\" aria-hidden=\"true\"></i> info</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i> info-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-institution\" aria-hidden=\"true\"></i> institution <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-key\" aria-hidden=\"true\"></i> key</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-keyboard-o\" aria-hidden=\"true\"></i> keyboard-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-language\" aria-hidden=\"true\"></i> language</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-laptop\" aria-hidden=\"true\"></i> laptop</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-leaf\" aria-hidden=\"true\"></i> leaf</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-legal\" aria-hidden=\"true\"></i> legal <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-lemon-o\" aria-hidden=\"true\"></i> lemon-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-level-down\" aria-hidden=\"true\"></i> level-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-level-up\" aria-hidden=\"true\"></i> level-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-life-bouy\" aria-hidden=\"true\"></i> life-bouy <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-life-buoy\" aria-hidden=\"true\"></i> life-buoy <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-life-ring\" aria-hidden=\"true\"></i> life-ring</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-life-saver\" aria-hidden=\"true\"></i> life-saver <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-lightbulb-o\" aria-hidden=\"true\"></i> lightbulb-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-line-chart\" aria-hidden=\"true\"></i> line-chart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-location-arrow\" aria-hidden=\"true\"></i> location-arrow</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-lock\" aria-hidden=\"true\"></i> lock</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-low-vision\" aria-hidden=\"true\"></i> low-vision</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-magic\" aria-hidden=\"true\"></i> magic</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-magnet\" aria-hidden=\"true\"></i> magnet</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mail-forward\" aria-hidden=\"true\"></i> mail-forward <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mail-reply\" aria-hidden=\"true\"></i> mail-reply <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mail-reply-all\" aria-hidden=\"true\"></i> mail-reply-all <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-male\" aria-hidden=\"true\"></i> male</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-map\" aria-hidden=\"true\"></i> map</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-map-marker\" aria-hidden=\"true\"></i> map-marker</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-map-o\" aria-hidden=\"true\"></i> map-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-map-pin\" aria-hidden=\"true\"></i> map-pin</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-map-signs\" aria-hidden=\"true\"></i> map-signs</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-meh-o\" aria-hidden=\"true\"></i> meh-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-microchip\" aria-hidden=\"true\"></i> microchip</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-microphone\" aria-hidden=\"true\"></i> microphone</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-microphone-slash\" aria-hidden=\"true\"></i> microphone-slash</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-minus\" aria-hidden=\"true\"></i> minus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-minus-circle\" aria-hidden=\"true\"></i> minus-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-minus-square\" aria-hidden=\"true\"></i> minus-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-minus-square-o\" aria-hidden=\"true\"></i> minus-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mobile\" aria-hidden=\"true\"></i> mobile</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mobile-phone\" aria-hidden=\"true\"></i> mobile-phone <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-money\" aria-hidden=\"true\"></i> money</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-moon-o\" aria-hidden=\"true\"></i> moon-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mortar-board\" aria-hidden=\"true\"></i> mortar-board <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-motorcycle\" aria-hidden=\"true\"></i> motorcycle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mouse-pointer\" aria-hidden=\"true\"></i> mouse-pointer</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-music\" aria-hidden=\"true\"></i> music</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-navicon\" aria-hidden=\"true\"></i> navicon <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-newspaper-o\" aria-hidden=\"true\"></i> newspaper-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-object-group\" aria-hidden=\"true\"></i> object-group</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-object-ungroup\" aria-hidden=\"true\"></i> object-ungroup</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paint-brush\" aria-hidden=\"true\"></i> paint-brush</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paper-plane\" aria-hidden=\"true\"></i> paper-plane</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i> paper-plane-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paw\" aria-hidden=\"true\"></i> paw</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pencil\" aria-hidden=\"true\"></i> pencil</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pencil-square\" aria-hidden=\"true\"></i> pencil-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pencil-square-o\" aria-hidden=\"true\"></i> pencil-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-percent\" aria-hidden=\"true\"></i> percent</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-phone\" aria-hidden=\"true\"></i> phone</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-phone-square\" aria-hidden=\"true\"></i> phone-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-photo\" aria-hidden=\"true\"></i> photo <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-picture-o\" aria-hidden=\"true\"></i> picture-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pie-chart\" aria-hidden=\"true\"></i> pie-chart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plane\" aria-hidden=\"true\"></i> plane</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plug\" aria-hidden=\"true\"></i> plug</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plus\" aria-hidden=\"true\"></i> plus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> plus-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plus-square\" aria-hidden=\"true\"></i> plus-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plus-square-o\" aria-hidden=\"true\"></i> plus-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-podcast\" aria-hidden=\"true\"></i> podcast</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-power-off\" aria-hidden=\"true\"></i> power-off</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-print\" aria-hidden=\"true\"></i> print</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-puzzle-piece\" aria-hidden=\"true\"></i> puzzle-piece</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-qrcode\" aria-hidden=\"true\"></i> qrcode</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-question\" aria-hidden=\"true\"></i> question</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-question-circle\" aria-hidden=\"true\"></i> question-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-question-circle-o\" aria-hidden=\"true\"></i> question-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-quote-left\" aria-hidden=\"true\"></i> quote-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-quote-right\" aria-hidden=\"true\"></i> quote-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-random\" aria-hidden=\"true\"></i> random</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-recycle\" aria-hidden=\"true\"></i> recycle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-refresh\" aria-hidden=\"true\"></i> refresh</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-registered\" aria-hidden=\"true\"></i> registered</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-remove\" aria-hidden=\"true\"></i> remove <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-reorder\" aria-hidden=\"true\"></i> reorder <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-reply\" aria-hidden=\"true\"></i> reply</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-reply-all\" aria-hidden=\"true\"></i> reply-all</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-retweet\" aria-hidden=\"true\"></i> retweet</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-road\" aria-hidden=\"true\"></i> road</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rocket\" aria-hidden=\"true\"></i> rocket</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rss\" aria-hidden=\"true\"></i> rss</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rss-square\" aria-hidden=\"true\"></i> rss-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-s15\" aria-hidden=\"true\"></i> s15 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-search\" aria-hidden=\"true\"></i> search</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-search-minus\" aria-hidden=\"true\"></i> search-minus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-search-plus\" aria-hidden=\"true\"></i> search-plus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-send\" aria-hidden=\"true\"></i> send <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-send-o\" aria-hidden=\"true\"></i> send-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-server\" aria-hidden=\"true\"></i> server</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-share\" aria-hidden=\"true\"></i> share</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-share-alt\" aria-hidden=\"true\"></i> share-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-share-alt-square\" aria-hidden=\"true\"></i> share-alt-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-share-square\" aria-hidden=\"true\"></i> share-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-share-square-o\" aria-hidden=\"true\"></i> share-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-shield\" aria-hidden=\"true\"></i> shield</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ship\" aria-hidden=\"true\"></i> ship</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-shopping-bag\" aria-hidden=\"true\"></i> shopping-bag</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-shopping-basket\" aria-hidden=\"true\"></i> shopping-basket</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-shopping-cart\" aria-hidden=\"true\"></i> shopping-cart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-shower\" aria-hidden=\"true\"></i> shower</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sign-in\" aria-hidden=\"true\"></i> sign-in</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sign-language\" aria-hidden=\"true\"></i> sign-language</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sign-out\" aria-hidden=\"true\"></i> sign-out</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-signal\" aria-hidden=\"true\"></i> signal</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-signing\" aria-hidden=\"true\"></i> signing <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sitemap\" aria-hidden=\"true\"></i> sitemap</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sliders\" aria-hidden=\"true\"></i> sliders</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-smile-o\" aria-hidden=\"true\"></i> smile-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-snowflake-o\" aria-hidden=\"true\"></i> snowflake-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-soccer-ball-o\" aria-hidden=\"true\"></i> soccer-ball-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort\" aria-hidden=\"true\"></i> sort</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-alpha-asc\" aria-hidden=\"true\"></i> sort-alpha-asc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-alpha-desc\" aria-hidden=\"true\"></i> sort-alpha-desc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-amount-asc\" aria-hidden=\"true\"></i> sort-amount-asc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-amount-desc\" aria-hidden=\"true\"></i> sort-amount-desc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-asc\" aria-hidden=\"true\"></i> sort-asc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-desc\" aria-hidden=\"true\"></i> sort-desc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-down\" aria-hidden=\"true\"></i> sort-down <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-numeric-asc\" aria-hidden=\"true\"></i> sort-numeric-asc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-numeric-desc\" aria-hidden=\"true\"></i> sort-numeric-desc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sort-up\" aria-hidden=\"true\"></i> sort-up <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-space-shuttle\" aria-hidden=\"true\"></i> space-shuttle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-spinner\" aria-hidden=\"true\"></i> spinner</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-spoon\" aria-hidden=\"true\"></i> spoon</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-square\" aria-hidden=\"true\"></i> square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-square-o\" aria-hidden=\"true\"></i> square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-star\" aria-hidden=\"true\"></i> star</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-star-half\" aria-hidden=\"true\"></i> star-half</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-star-half-empty\" aria-hidden=\"true\"></i> star-half-empty <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-star-half-full\" aria-hidden=\"true\"></i> star-half-full <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-star-half-o\" aria-hidden=\"true\"></i> star-half-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-star-o\" aria-hidden=\"true\"></i> star-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sticky-note\" aria-hidden=\"true\"></i> sticky-note</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sticky-note-o\" aria-hidden=\"true\"></i> sticky-note-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-street-view\" aria-hidden=\"true\"></i> street-view</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-suitcase\" aria-hidden=\"true\"></i> suitcase</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sun-o\" aria-hidden=\"true\"></i> sun-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-support\" aria-hidden=\"true\"></i> support <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tablet\" aria-hidden=\"true\"></i> tablet</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tachometer\" aria-hidden=\"true\"></i> tachometer</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tag\" aria-hidden=\"true\"></i> tag</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tags\" aria-hidden=\"true\"></i> tags</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tasks\" aria-hidden=\"true\"></i> tasks</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-taxi\" aria-hidden=\"true\"></i> taxi</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-television\" aria-hidden=\"true\"></i> television</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-terminal\" aria-hidden=\"true\"></i> terminal</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer\" aria-hidden=\"true\"></i> thermometer <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-0\" aria-hidden=\"true\"></i> thermometer-0 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-1\" aria-hidden=\"true\"></i> thermometer-1 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-2\" aria-hidden=\"true\"></i> thermometer-2 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-3\" aria-hidden=\"true\"></i> thermometer-3 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-4\" aria-hidden=\"true\"></i> thermometer-4 <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-empty\" aria-hidden=\"true\"></i> thermometer-empty</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-full\" aria-hidden=\"true\"></i> thermometer-full</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-half\" aria-hidden=\"true\"></i> thermometer-half</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-quarter\" aria-hidden=\"true\"></i> thermometer-quarter</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thermometer-three-quarters\" aria-hidden=\"true\"></i> thermometer-three-quarters</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumb-tack\" aria-hidden=\"true\"></i> thumb-tack</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-down\" aria-hidden=\"true\"></i> thumbs-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-o-down\" aria-hidden=\"true\"></i> thumbs-o-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i> thumbs-o-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-up\" aria-hidden=\"true\"></i> thumbs-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ticket\" aria-hidden=\"true\"></i> ticket</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-times\" aria-hidden=\"true\"></i> times</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-times-circle\" aria-hidden=\"true\"></i> times-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-times-circle-o\" aria-hidden=\"true\"></i> times-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-times-rectangle\" aria-hidden=\"true\"></i> times-rectangle <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-times-rectangle-o\" aria-hidden=\"true\"></i> times-rectangle-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tint\" aria-hidden=\"true\"></i> tint</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-down\" aria-hidden=\"true\"></i> toggle-down <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-left\" aria-hidden=\"true\"></i> toggle-left <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-off\" aria-hidden=\"true\"></i> toggle-off</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-on\" aria-hidden=\"true\"></i> toggle-on</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-right\" aria-hidden=\"true\"></i> toggle-right <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-up\" aria-hidden=\"true\"></i> toggle-up <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-trademark\" aria-hidden=\"true\"></i> trademark</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-trash\" aria-hidden=\"true\"></i> trash</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-trash-o\" aria-hidden=\"true\"></i> trash-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tree\" aria-hidden=\"true\"></i> tree</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-trophy\" aria-hidden=\"true\"></i> trophy</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-truck\" aria-hidden=\"true\"></i> truck</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tty\" aria-hidden=\"true\"></i> tty</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tv\" aria-hidden=\"true\"></i> tv <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-umbrella\" aria-hidden=\"true\"></i> umbrella</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-universal-access\" aria-hidden=\"true\"></i> universal-access</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-university\" aria-hidden=\"true\"></i> university</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-unlock\" aria-hidden=\"true\"></i> unlock</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-unlock-alt\" aria-hidden=\"true\"></i> unlock-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-unsorted\" aria-hidden=\"true\"></i> unsorted <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-upload\" aria-hidden=\"true\"></i> upload</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user\" aria-hidden=\"true\"></i> user</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user-circle\" aria-hidden=\"true\"></i> user-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user-circle-o\" aria-hidden=\"true\"></i> user-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user-o\" aria-hidden=\"true\"></i> user-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user-plus\" aria-hidden=\"true\"></i> user-plus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user-secret\" aria-hidden=\"true\"></i> user-secret</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user-times\" aria-hidden=\"true\"></i> user-times</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-users\" aria-hidden=\"true\"></i> users</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-vcard\" aria-hidden=\"true\"></i> vcard <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-vcard-o\" aria-hidden=\"true\"></i> vcard-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-video-camera\" aria-hidden=\"true\"></i> video-camera</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-volume-control-phone\" aria-hidden=\"true\"></i> volume-control-phone</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-volume-down\" aria-hidden=\"true\"></i> volume-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-volume-off\" aria-hidden=\"true\"></i> volume-off</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-volume-up\" aria-hidden=\"true\"></i> volume-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-warning\" aria-hidden=\"true\"></i> warning <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair\" aria-hidden=\"true\"></i> wheelchair</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair-alt\" aria-hidden=\"true\"></i> wheelchair-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wifi\" aria-hidden=\"true\"></i> wifi</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-window-close\" aria-hidden=\"true\"></i> window-close</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-window-close-o\" aria-hidden=\"true\"></i> window-close-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-window-maximize\" aria-hidden=\"true\"></i> window-maximize</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-window-minimize\" aria-hidden=\"true\"></i> window-minimize</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-window-restore\" aria-hidden=\"true\"></i> window-restore</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wrench\" aria-hidden=\"true\"></i> wrench</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"accessibility\">\r\n\t                        <h2 class=\"page-header\">辅助图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-american-sign-language-interpreting\" aria-hidden=\"true\"></i> american-sign-language-interpreting</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-asl-interpreting\" aria-hidden=\"true\"></i> asl-interpreting <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-assistive-listening-systems\" aria-hidden=\"true\"></i> assistive-listening-systems</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-audio-description\" aria-hidden=\"true\"></i> audio-description</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-blind\" aria-hidden=\"true\"></i> blind</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-braille\" aria-hidden=\"true\"></i> braille</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc\" aria-hidden=\"true\"></i> cc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-deaf\" aria-hidden=\"true\"></i> deaf</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-deafness\" copyright=\"J2eeFAST\" aria-hidden=\"true\"></i> deafness <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hard-of-hearing\" aria-hidden=\"true\"></i> hard-of-hearing <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-low-vision\" aria-hidden=\"true\"></i> low-vision</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-question-circle-o\" aria-hidden=\"true\"></i> question-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sign-language\" aria-hidden=\"true\"></i> sign-language</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-signing\" aria-hidden=\"true\"></i> signing <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tty\" aria-hidden=\"true\"></i> tty</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-universal-access\" aria-hidden=\"true\"></i> universal-access</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-volume-control-phone\" aria-hidden=\"true\"></i> volume-control-phone</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair\" aria-hidden=\"true\"></i> wheelchair</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair-alt\" aria-hidden=\"true\"></i> wheelchair-alt</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"hand\">\r\n\t                        <h2 class=\"page-header\">手型图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-grab-o\" aria-hidden=\"true\"></i> hand-grab-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-lizard-o\" aria-hidden=\"true\"></i> hand-lizard-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-down\" aria-hidden=\"true\"></i> hand-o-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-left\" aria-hidden=\"true\"></i> hand-o-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-right\" aria-hidden=\"true\"></i> hand-o-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-up\" aria-hidden=\"true\"></i> hand-o-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-paper-o\" aria-hidden=\"true\"></i> hand-paper-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-peace-o\" aria-hidden=\"true\"></i> hand-peace-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-pointer-o\" aria-hidden=\"true\"></i> hand-pointer-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-rock-o\" aria-hidden=\"true\"></i> hand-rock-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-scissors-o\" aria-hidden=\"true\"></i> hand-scissors-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-spock-o\" aria-hidden=\"true\"></i> hand-spock-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-stop-o\" aria-hidden=\"true\"></i> hand-stop-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-down\" aria-hidden=\"true\"></i> thumbs-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-o-down\" aria-hidden=\"true\"></i> thumbs-o-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i> thumbs-o-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-thumbs-up\" aria-hidden=\"true\"></i> thumbs-up</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"transportation\">\r\n\t                        <h2 class=\"page-header\">交通运输图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ambulance\" aria-hidden=\"true\"></i> ambulance</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-automobile\" aria-hidden=\"true\"></i> automobile <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bicycle\" aria-hidden=\"true\"></i> bicycle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bus\" aria-hidden=\"true\"></i> bus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cab\" aria-hidden=\"true\"></i> cab <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-car\" aria-hidden=\"true\"></i> car</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fighter-jet\" aria-hidden=\"true\"></i> fighter-jet</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-motorcycle\" aria-hidden=\"true\"></i> motorcycle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plane\" aria-hidden=\"true\"></i> plane</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rocket\" aria-hidden=\"true\"></i> rocket</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ship\" aria-hidden=\"true\"></i> ship</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-space-shuttle\" aria-hidden=\"true\"></i> space-shuttle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-subway\" aria-hidden=\"true\"></i> subway</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-taxi\" aria-hidden=\"true\"></i> taxi</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-train\" aria-hidden=\"true\"></i> train</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-truck\" aria-hidden=\"true\"></i> truck</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair\" aria-hidden=\"true\"></i> wheelchair</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair-alt\" aria-hidden=\"true\"></i> wheelchair-alt</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"gender\">\r\n\t                        <h2 class=\"page-header\">性别图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-genderless\" aria-hidden=\"true\"></i> genderless</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-intersex\" aria-hidden=\"true\"></i> intersex <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mars\" aria-hidden=\"true\"></i> mars</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mars-double\" aria-hidden=\"true\"></i> mars-double</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mars-stroke\" aria-hidden=\"true\"></i> mars-stroke</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mars-stroke-h\" aria-hidden=\"true\"></i> mars-stroke-h</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mars-stroke-v\" aria-hidden=\"true\"></i> mars-stroke-v</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mercury\" aria-hidden=\"true\"></i> mercury</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-neuter\" aria-hidden=\"true\"></i> neuter</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-transgender\" aria-hidden=\"true\"></i> transgender</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-transgender-alt\" aria-hidden=\"true\"></i> transgender-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-venus\" aria-hidden=\"true\"></i> venus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-venus-double\" aria-hidden=\"true\"></i> venus-double</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-venus-mars\" aria-hidden=\"true\"></i> venus-mars</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"file-type\">\r\n\t                        <h2 class=\"page-header\">文件类型图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file\" aria-hidden=\"true\"></i> file</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-archive-o\" aria-hidden=\"true\"></i> file-archive-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-audio-o\" aria-hidden=\"true\"></i> file-audio-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-code-o\" aria-hidden=\"true\"></i> file-code-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-excel-o\" aria-hidden=\"true\"></i> file-excel-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-image-o\" aria-hidden=\"true\"></i> file-image-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-movie-o\" aria-hidden=\"true\"></i> file-movie-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> file-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-pdf-o\" aria-hidden=\"true\"></i> file-pdf-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-photo-o\" aria-hidden=\"true\"></i> file-photo-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-picture-o\" aria-hidden=\"true\"></i> file-picture-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-powerpoint-o\" aria-hidden=\"true\"></i> file-powerpoint-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-sound-o\" aria-hidden=\"true\"></i> file-sound-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-text\" aria-hidden=\"true\"></i> file-text</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-text-o\" aria-hidden=\"true\"></i> file-text-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-video-o\" aria-hidden=\"true\"></i> file-video-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-word-o\" aria-hidden=\"true\"></i> file-word-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-zip-o\" aria-hidden=\"true\"></i> file-zip-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"spinner\">\r\n\t                        <h2 class=\"page-header\">加载动画图标</h2>\r\n\t                        <div class=\"alert alert-success\">\r\n\t                            <ul class=\"fa-ul\">\r\n\t                                <li>\r\n                                        <i class=\"fa fa-info-circle fa-lg fa-li\"></i> 给这些图标加上\r\n                                        <code>fa-spin</code> class，就可以表现出加载动画了\r\n                                    </li>\r\n\t                            </ul>\r\n\t                        </div>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-circle-o-notch\" aria-hidden=\"true\"></i> circle-o-notch</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cog\" aria-hidden=\"true\"></i> cog</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gear\" aria-hidden=\"true\"></i> gear <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-refresh\" aria-hidden=\"true\"></i> refresh</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-spinner\" aria-hidden=\"true\"></i> spinner</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"form-control\">\r\n\t                        <h2 class=\"page-header\">表单图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-check-square\" aria-hidden=\"true\"></i> check-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-check-square-o\" aria-hidden=\"true\"></i> check-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-circle\" aria-hidden=\"true\"></i> circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-circle-o\" aria-hidden=\"true\"></i> circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dot-circle-o\" aria-hidden=\"true\"></i> dot-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-minus-square\" aria-hidden=\"true\"></i> minus-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-minus-square-o\" aria-hidden=\"true\"></i> minus-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plus-square\" aria-hidden=\"true\"></i> plus-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plus-square-o\" aria-hidden=\"true\"></i> plus-square-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-square\" aria-hidden=\"true\"></i> square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-square-o\" aria-hidden=\"true\"></i> square-o</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"payment\">\r\n\t                        <h2 class=\"page-header\">支付图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-amex\" aria-hidden=\"true\"></i> cc-amex</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-diners-club\" aria-hidden=\"true\"></i> cc-diners-club</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-discover\" aria-hidden=\"true\"></i> cc-discover</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-jcb\" aria-hidden=\"true\"></i> cc-jcb</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-mastercard\" aria-hidden=\"true\"></i> cc-mastercard</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-paypal\" aria-hidden=\"true\"></i> cc-paypal</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-stripe\" aria-hidden=\"true\"></i> cc-stripe</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-visa\" aria-hidden=\"true\"></i> cc-visa</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-credit-card\" aria-hidden=\"true\"></i> credit-card</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-credit-card-alt\" aria-hidden=\"true\"></i> credit-card-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-google-wallet\" aria-hidden=\"true\"></i> google-wallet</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paypal\" aria-hidden=\"true\"></i> paypal</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"chart\">\r\n\t                        <h2 class=\"page-header\">统计图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-area-chart\" aria-hidden=\"true\"></i> area-chart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bar-chart\" aria-hidden=\"true\"></i> bar-chart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bar-chart-o\" aria-hidden=\"true\"></i> bar-chart-o <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-line-chart\" aria-hidden=\"true\"></i> line-chart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pie-chart\" aria-hidden=\"true\"></i> pie-chart</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"currency\">\r\n\t                        <h2 class=\"page-header\">货币图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bitcoin\" aria-hidden=\"true\"></i> bitcoin <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-btc\" aria-hidden=\"true\"></i> btc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cny\" aria-hidden=\"true\"></i> cny <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dollar\" aria-hidden=\"true\"></i> dollar <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eur\" aria-hidden=\"true\"></i> eur</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-euro\" aria-hidden=\"true\"></i> euro <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gbp\" aria-hidden=\"true\"></i> gbp</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gg\" aria-hidden=\"true\"></i> gg</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gg-circle\" aria-hidden=\"true\"></i> gg-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ils\" aria-hidden=\"true\"></i> ils</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-inr\" aria-hidden=\"true\"></i> inr</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-jpy\" aria-hidden=\"true\"></i> jpy</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-krw\" aria-hidden=\"true\"></i> krw</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-money\" aria-hidden=\"true\"></i> money</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rmb\" aria-hidden=\"true\"></i> rmb <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rouble\" aria-hidden=\"true\"></i> rouble <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rub\" aria-hidden=\"true\"></i> rub</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ruble\" aria-hidden=\"true\"></i> ruble <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rupee\" aria-hidden=\"true\"></i> rupee <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-shekel\" aria-hidden=\"true\"></i> shekel <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sheqel\" aria-hidden=\"true\"></i> sheqel <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-try\" aria-hidden=\"true\"></i> try</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-turkish-lira\" aria-hidden=\"true\"></i> turkish-lira <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-usd\" aria-hidden=\"true\"></i> usd</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-won\" aria-hidden=\"true\"></i> won <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-yen\" aria-hidden=\"true\"></i> yen <span class=\"text-muted\">(alias)</span></div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"text-editor\">\r\n\t                        <h2 class=\"page-header\">文本编辑器图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-align-center\" aria-hidden=\"true\"></i> align-center</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-align-justify\" aria-hidden=\"true\"></i> align-justify</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-align-left\" aria-hidden=\"true\"></i> align-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-align-right\" aria-hidden=\"true\"></i> align-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bold\" aria-hidden=\"true\"></i> bold</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chain\" aria-hidden=\"true\"></i> chain <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chain-broken\" aria-hidden=\"true\"></i> chain-broken</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-clipboard\" aria-hidden=\"true\"></i> clipboard</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-columns\" aria-hidden=\"true\"></i> columns</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-copy\" aria-hidden=\"true\"></i> copy <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cut\" aria-hidden=\"true\"></i> cut <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dedent\" aria-hidden=\"true\"></i> dedent <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eraser\" aria-hidden=\"true\"></i> eraser</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file\" aria-hidden=\"true\"></i> file</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> file-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-text\" copyright=\"J2eeFAST\" aria-hidden=\"true\"></i> file-text</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-file-text-o\" aria-hidden=\"true\"></i> file-text-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-files-o\" aria-hidden=\"true\"></i> files-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-floppy-o\" aria-hidden=\"true\"></i> floppy-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-font\" aria-hidden=\"true\"></i> font</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-header\" aria-hidden=\"true\"></i> header</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-indent\" aria-hidden=\"true\"></i> indent</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-italic\" aria-hidden=\"true\"></i> italic</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-link\" aria-hidden=\"true\"></i> link</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-list\" aria-hidden=\"true\"></i> list</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-list-alt\" aria-hidden=\"true\"></i> list-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-list-ol\" aria-hidden=\"true\"></i> list-ol</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-list-ul\" aria-hidden=\"true\"></i> list-ul</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-outdent\" aria-hidden=\"true\"></i> outdent</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paperclip\" aria-hidden=\"true\"></i> paperclip</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paragraph\" aria-hidden=\"true\"></i> paragraph</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paste\" aria-hidden=\"true\"></i> paste <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-repeat\" aria-hidden=\"true\"></i> repeat</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rotate-left\" aria-hidden=\"true\"></i> rotate-left <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rotate-right\" aria-hidden=\"true\"></i> rotate-right <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-save\" aria-hidden=\"true\"></i> save <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-scissors\" aria-hidden=\"true\"></i> scissors</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-strikethrough\" aria-hidden=\"true\"></i> strikethrough</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-subscript\" aria-hidden=\"true\"></i> subscript</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-superscript\" aria-hidden=\"true\"></i> superscript</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-table\" aria-hidden=\"true\"></i> table</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-text-height\" aria-hidden=\"true\"></i> text-height</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-text-width\" aria-hidden=\"true\"></i> text-width</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-th\" aria-hidden=\"true\"></i> th</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-th-large\" aria-hidden=\"true\"></i> th-large</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-th-list\" aria-hidden=\"true\"></i> th-list</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-underline\" aria-hidden=\"true\"></i> underline</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-undo\" aria-hidden=\"true\"></i> undo</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-unlink\" aria-hidden=\"true\"></i> unlink <span class=\"text-muted\">(alias)</span></div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"directional\">\r\n\t                        <h2 class=\"page-header\">方向图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-double-down\" aria-hidden=\"true\"></i> angle-double-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-double-left\" aria-hidden=\"true\"></i> angle-double-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-double-right\" aria-hidden=\"true\"></i> angle-double-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-double-up\" aria-hidden=\"true\"></i> angle-double-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-down\" aria-hidden=\"true\"></i> angle-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-left\" aria-hidden=\"true\"></i> angle-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-right\" aria-hidden=\"true\"></i> angle-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angle-up\" aria-hidden=\"true\"></i> angle-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-down\" aria-hidden=\"true\"></i> arrow-circle-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-left\" aria-hidden=\"true\"></i> arrow-circle-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-o-down\" aria-hidden=\"true\"></i> arrow-circle-o-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-o-left\" aria-hidden=\"true\"></i> arrow-circle-o-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-o-right\" aria-hidden=\"true\"></i> arrow-circle-o-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-o-up\" aria-hidden=\"true\"></i> arrow-circle-o-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-right\" aria-hidden=\"true\"></i> arrow-circle-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-circle-up\" aria-hidden=\"true\"></i> arrow-circle-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-down\" aria-hidden=\"true\"></i> arrow-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-left\" aria-hidden=\"true\"></i> arrow-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-right\" aria-hidden=\"true\"></i> arrow-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrow-up\" aria-hidden=\"true\"></i> arrow-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows\" aria-hidden=\"true\"></i> arrows</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows-alt\" aria-hidden=\"true\"></i> arrows-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows-h\" aria-hidden=\"true\"></i> arrows-h</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows-v\" aria-hidden=\"true\"></i> arrows-v</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-down\" aria-hidden=\"true\"></i> caret-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-left\" aria-hidden=\"true\"></i> caret-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-right\" aria-hidden=\"true\"></i> caret-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-down\" aria-hidden=\"true\"></i> caret-square-o-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-left\" aria-hidden=\"true\"></i> caret-square-o-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-right\" aria-hidden=\"true\"></i> caret-square-o-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-square-o-up\" aria-hidden=\"true\"></i> caret-square-o-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-caret-up\" aria-hidden=\"true\"></i> caret-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-circle-down\" aria-hidden=\"true\"></i> chevron-circle-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-circle-left\" aria-hidden=\"true\"></i> chevron-circle-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-circle-right\" aria-hidden=\"true\"></i> chevron-circle-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-circle-up\" aria-hidden=\"true\"></i> chevron-circle-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-down\" aria-hidden=\"true\"></i> chevron-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-left\" aria-hidden=\"true\"></i> chevron-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-right\" aria-hidden=\"true\"></i> chevron-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chevron-up\" aria-hidden=\"true\"></i> chevron-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-exchange\" aria-hidden=\"true\"></i> exchange</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-down\" aria-hidden=\"true\"></i> hand-o-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-left\" aria-hidden=\"true\"></i> hand-o-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-right\" aria-hidden=\"true\"></i> hand-o-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hand-o-up\" aria-hidden=\"true\"></i> hand-o-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-long-arrow-down\" aria-hidden=\"true\"></i> long-arrow-down</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-long-arrow-left\" aria-hidden=\"true\"></i> long-arrow-left</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-long-arrow-right\" aria-hidden=\"true\"></i> long-arrow-right</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-long-arrow-up\" aria-hidden=\"true\"></i> long-arrow-up</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-down\" aria-hidden=\"true\"></i> toggle-down <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-left\" aria-hidden=\"true\"></i> toggle-left <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-right\" aria-hidden=\"true\"></i> toggle-right <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-toggle-up\" aria-hidden=\"true\"></i> toggle-up <span class=\"text-muted\">(alias)</span></div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"video-player\">\r\n\t                        <h2 class=\"page-header\">视频播放图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-arrows-alt\" aria-hidden=\"true\"></i> arrows-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-backward\" aria-hidden=\"true\"></i> backward</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-compress\" aria-hidden=\"true\"></i> compress</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eject\" aria-hidden=\"true\"></i> eject</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-expand\" aria-hidden=\"true\"></i> expand</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fast-backward\" aria-hidden=\"true\"></i> fast-backward</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fast-forward\" aria-hidden=\"true\"></i> fast-forward</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-forward\" aria-hidden=\"true\"></i> forward</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pause\" aria-hidden=\"true\"></i> pause</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pause-circle\" aria-hidden=\"true\"></i> pause-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pause-circle-o\" aria-hidden=\"true\"></i> pause-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-play\" aria-hidden=\"true\"></i> play</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-play-circle\" aria-hidden=\"true\"></i> play-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-play-circle-o\" aria-hidden=\"true\"></i> play-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-random\" aria-hidden=\"true\"></i> random</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-step-backward\" aria-hidden=\"true\"></i> step-backward</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-step-forward\" aria-hidden=\"true\"></i> step-forward</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stop\" aria-hidden=\"true\"></i> stop</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stop-circle\" aria-hidden=\"true\"></i> stop-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stop-circle-o\" aria-hidden=\"true\"></i> stop-circle-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-youtube-play\" aria-hidden=\"true\"></i> youtube-play</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"brand\">\r\n\t                        <h2 class=\"page-header\">品牌图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list margin-bottom-lg\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-500px\" aria-hidden=\"true\"></i> 500px</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-adn\" aria-hidden=\"true\"></i> adn</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-amazon\" aria-hidden=\"true\"></i> amazon</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-android\" aria-hidden=\"true\"></i> android</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-angellist\" aria-hidden=\"true\"></i> angellist</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-apple\" aria-hidden=\"true\"></i> apple</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bandcamp\" aria-hidden=\"true\"></i> bandcamp</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-behance\" aria-hidden=\"true\"></i> behance</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-behance-square\" aria-hidden=\"true\"></i> behance-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bitbucket\" aria-hidden=\"true\"></i> bitbucket</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bitbucket-square\" aria-hidden=\"true\"></i> bitbucket-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bitcoin\" aria-hidden=\"true\"></i> bitcoin <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-black-tie\" aria-hidden=\"true\"></i> black-tie</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bluetooth\" aria-hidden=\"true\"></i> bluetooth</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-bluetooth-b\" aria-hidden=\"true\"></i> bluetooth-b</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-btc\" aria-hidden=\"true\"></i> btc</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-buysellads\" aria-hidden=\"true\"></i> buysellads</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-amex\" aria-hidden=\"true\"></i> cc-amex</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-diners-club\" aria-hidden=\"true\"></i> cc-diners-club</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-discover\" aria-hidden=\"true\"></i> cc-discover</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-jcb\" aria-hidden=\"true\"></i> cc-jcb</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-mastercard\" aria-hidden=\"true\"></i> cc-mastercard</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-paypal\" aria-hidden=\"true\"></i> cc-paypal</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-stripe\" aria-hidden=\"true\"></i> cc-stripe</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-cc-visa\" aria-hidden=\"true\"></i> cc-visa</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-chrome\" aria-hidden=\"true\"></i> chrome</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-codepen\" aria-hidden=\"true\"></i> codepen</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-codiepie\" aria-hidden=\"true\"></i> codiepie</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-connectdevelop\" aria-hidden=\"true\"></i> connectdevelop</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-contao\" aria-hidden=\"true\"></i> contao</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-css3\" aria-hidden=\"true\"></i> css3</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dashcube\" aria-hidden=\"true\"></i> dashcube</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-delicious\" aria-hidden=\"true\"></i> delicious</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-deviantart\" aria-hidden=\"true\"></i> deviantart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-digg\" aria-hidden=\"true\"></i> digg</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dribbble\" aria-hidden=\"true\"></i> dribbble</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-dropbox\" aria-hidden=\"true\"></i> dropbox</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-drupal\" aria-hidden=\"true\"></i> drupal</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-edge\" aria-hidden=\"true\"></i> edge</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-eercast\" aria-hidden=\"true\"></i> eercast</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-empire\" aria-hidden=\"true\"></i> empire</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-envira\" aria-hidden=\"true\"></i> envira</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-etsy\" aria-hidden=\"true\"></i> etsy</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-expeditedssl\" aria-hidden=\"true\"></i> expeditedssl</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fa\" aria-hidden=\"true\"></i> fa <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-facebook\" aria-hidden=\"true\"></i> facebook</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-facebook-f\" aria-hidden=\"true\"></i> facebook-f <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-facebook-official\" aria-hidden=\"true\"></i> facebook-official</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-facebook-square\" aria-hidden=\"true\"></i> facebook-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-firefox\" aria-hidden=\"true\"></i> firefox</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-first-order\" aria-hidden=\"true\"></i> first-order</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-flickr\" aria-hidden=\"true\"></i> flickr</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-font-awesome\" aria-hidden=\"true\"></i> font-awesome</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fonticons\" aria-hidden=\"true\"></i> fonticons</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-fort-awesome\" aria-hidden=\"true\"></i> fort-awesome</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-forumbee\" aria-hidden=\"true\"></i> forumbee</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-foursquare\" aria-hidden=\"true\"></i> foursquare</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-free-code-camp\" aria-hidden=\"true\"></i> free-code-camp</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ge\" aria-hidden=\"true\"></i> ge <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-get-pocket\" aria-hidden=\"true\"></i> get-pocket</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gg\" aria-hidden=\"true\"></i> gg</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gg-circle\" aria-hidden=\"true\"></i> gg-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-git\" aria-hidden=\"true\"></i> git</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-git-square\" aria-hidden=\"true\"></i> git-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-github\" aria-hidden=\"true\"></i> github</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-github-alt\" aria-hidden=\"true\"></i> github-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-github-square\" aria-hidden=\"true\"></i> github-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gitlab\" aria-hidden=\"true\"></i> gitlab</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gittip\" aria-hidden=\"true\"></i> gittip <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-glide\" aria-hidden=\"true\"></i> glide</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-glide-g\" aria-hidden=\"true\"></i> glide-g</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-google\" aria-hidden=\"true\"></i> google</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-google-plus\" aria-hidden=\"true\"></i> google-plus</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-google-plus-circle\" aria-hidden=\"true\"></i> google-plus-circle <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-google-plus-official\" aria-hidden=\"true\"></i> google-plus-official</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-google-plus-square\" aria-hidden=\"true\"></i> google-plus-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-google-wallet\" aria-hidden=\"true\"></i> google-wallet</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-gratipay\" aria-hidden=\"true\"></i> gratipay</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-grav\" aria-hidden=\"true\"></i> grav</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hacker-news\" aria-hidden=\"true\"></i> hacker-news</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-houzz\" aria-hidden=\"true\"></i> houzz</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-html5\" aria-hidden=\"true\"></i> html5</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-imdb\" aria-hidden=\"true\"></i> imdb</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-instagram\" aria-hidden=\"true\"></i> instagram</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-internet-explorer\" aria-hidden=\"true\"></i> internet-explorer</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ioxhost\" aria-hidden=\"true\"></i> ioxhost</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-joomla\" aria-hidden=\"true\"></i> joomla</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-jsfiddle\" aria-hidden=\"true\"></i> jsfiddle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-lastfm\" aria-hidden=\"true\"></i> lastfm</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-lastfm-square\" aria-hidden=\"true\"></i> lastfm-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-leanpub\" aria-hidden=\"true\"></i> leanpub</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-linkedin\" aria-hidden=\"true\"></i> linkedin</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-linkedin-square\" aria-hidden=\"true\"></i> linkedin-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-linode\" aria-hidden=\"true\"></i> linode</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-linux\" aria-hidden=\"true\"></i> linux</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-maxcdn\" aria-hidden=\"true\"></i> maxcdn</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-meanpath\" aria-hidden=\"true\"></i> meanpath</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-medium\" aria-hidden=\"true\"></i> medium</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-meetup\" aria-hidden=\"true\"></i> meetup</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-mixcloud\" aria-hidden=\"true\"></i> mixcloud</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-modx\" aria-hidden=\"true\"></i> modx</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-odnoklassniki\" aria-hidden=\"true\"></i> odnoklassniki</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-odnoklassniki-square\" aria-hidden=\"true\"></i> odnoklassniki-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-opencart\" aria-hidden=\"true\"></i> opencart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-openid\" aria-hidden=\"true\"></i> openid</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-opera\" aria-hidden=\"true\"></i> opera</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-optin-monster\" aria-hidden=\"true\"></i> optin-monster</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pagelines\" copyright=\"J2eeFAST\" aria-hidden=\"true\"></i> pagelines</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-paypal\" aria-hidden=\"true\"></i> paypal</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pied-piper\" aria-hidden=\"true\"></i> pied-piper</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pied-piper-alt\" aria-hidden=\"true\"></i> pied-piper-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pied-piper-pp\" aria-hidden=\"true\"></i> pied-piper-pp</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pinterest\" aria-hidden=\"true\"></i> pinterest</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pinterest-p\" aria-hidden=\"true\"></i> pinterest-p</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-pinterest-square\" aria-hidden=\"true\"></i> pinterest-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-product-hunt\" aria-hidden=\"true\"></i> product-hunt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-qq\" aria-hidden=\"true\"></i> qq</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-quora\" aria-hidden=\"true\"></i> quora</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ra\" aria-hidden=\"true\"></i> ra <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ravelry\" aria-hidden=\"true\"></i> ravelry</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-rebel\" aria-hidden=\"true\"></i> rebel</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-reddit\" aria-hidden=\"true\"></i> reddit</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-reddit-alien\" aria-hidden=\"true\"></i> reddit-alien</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-reddit-square\" aria-hidden=\"true\"></i> reddit-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-renren\" aria-hidden=\"true\"></i> renren</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-resistance\" aria-hidden=\"true\"></i> resistance <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-safari\" aria-hidden=\"true\"></i> safari</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-scribd\" aria-hidden=\"true\"></i> scribd</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-sellsy\" aria-hidden=\"true\"></i> sellsy</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-share-alt\" aria-hidden=\"true\"></i> share-alt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-share-alt-square\" aria-hidden=\"true\"></i> share-alt-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-shirtsinbulk\" aria-hidden=\"true\"></i> shirtsinbulk</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-simplybuilt\" aria-hidden=\"true\"></i> simplybuilt</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-skyatlas\" aria-hidden=\"true\"></i> skyatlas</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-skype\" aria-hidden=\"true\"></i> skype</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-slack\" aria-hidden=\"true\"></i> slack</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-slideshare\" aria-hidden=\"true\"></i> slideshare</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-snapchat\" aria-hidden=\"true\"></i> snapchat</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-snapchat-ghost\" aria-hidden=\"true\"></i> snapchat-ghost</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-snapchat-square\" aria-hidden=\"true\"></i> snapchat-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-soundcloud\" aria-hidden=\"true\"></i> soundcloud</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-spotify\" aria-hidden=\"true\"></i> spotify</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stack-exchange\" aria-hidden=\"true\"></i> stack-exchange</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stack-overflow\" aria-hidden=\"true\"></i> stack-overflow</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-steam\" aria-hidden=\"true\"></i> steam</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-steam-square\" aria-hidden=\"true\"></i> steam-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stumbleupon\" copyright=\"J2eeFAST\" aria-hidden=\"true\"></i> stumbleupon</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stumbleupon-circle\" aria-hidden=\"true\"></i> stumbleupon-circle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-superpowers\" aria-hidden=\"true\"></i> superpowers</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-telegram\" aria-hidden=\"true\"></i> telegram</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tencent-weibo\" aria-hidden=\"true\"></i> tencent-weibo</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-themeisle\" aria-hidden=\"true\"></i> themeisle</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-trello\" aria-hidden=\"true\"></i> trello</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tripadvisor\" aria-hidden=\"true\"></i> tripadvisor</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tumblr\" aria-hidden=\"true\"></i> tumblr</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-tumblr-square\" aria-hidden=\"true\"></i> tumblr-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-twitch\" aria-hidden=\"true\"></i> twitch</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-twitter\" aria-hidden=\"true\"></i> twitter</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-twitter-square\" aria-hidden=\"true\"></i> twitter-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-usb\" aria-hidden=\"true\"></i> usb</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-viacoin\" aria-hidden=\"true\"></i> viacoin</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-viadeo\" aria-hidden=\"true\"></i> viadeo</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-viadeo-square\" aria-hidden=\"true\"></i> viadeo-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-vimeo\" aria-hidden=\"true\"></i> vimeo</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-vimeo-square\" aria-hidden=\"true\"></i> vimeo-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-vine\" aria-hidden=\"true\"></i> vine</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-vk\" aria-hidden=\"true\"></i> vk</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wechat\" aria-hidden=\"true\"></i> wechat <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-weibo\" aria-hidden=\"true\"></i> weibo</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-weixin\" aria-hidden=\"true\"></i> weixin</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-whatsapp\" aria-hidden=\"true\"></i> whatsapp</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wikipedia-w\" aria-hidden=\"true\"></i> wikipedia-w</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-windows\" aria-hidden=\"true\"></i> windows</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wordpress\" aria-hidden=\"true\"></i> wordpress</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wpbeginner\" aria-hidden=\"true\"></i> wpbeginner</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wpexplorer\" aria-hidden=\"true\"></i> wpexplorer</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wpforms\" aria-hidden=\"true\"></i> wpforms</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-xing\" aria-hidden=\"true\"></i> xing</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-xing-square\" aria-hidden=\"true\"></i> xing-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-y-combinator\" aria-hidden=\"true\"></i> y-combinator</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-y-combinator-square\" aria-hidden=\"true\"></i> y-combinator-square <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-yahoo\" aria-hidden=\"true\"></i> yahoo</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-yc\" aria-hidden=\"true\"></i> yc <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-yc-square\" aria-hidden=\"true\"></i> yc-square <span class=\"text-muted\">(alias)</span></div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-yelp\" aria-hidden=\"true\"></i> yelp</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-yoast\" aria-hidden=\"true\"></i> yoast</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-youtube\" aria-hidden=\"true\"></i> youtube</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-youtube-play\" aria-hidden=\"true\"></i> youtube-play</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-youtube-square\" aria-hidden=\"true\"></i> youtube-square</div>\r\n\t                        </div>\r\n\t                    </section>\r\n\t                    <section id=\"medical\">\r\n\t                        <h2 class=\"page-header\">医疗图标</h2>\r\n\t                        <div class=\"row fontawesome-icon-list\">\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-ambulance\" aria-hidden=\"true\"></i> ambulance</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-h-square\" aria-hidden=\"true\"></i> h-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-heart\" aria-hidden=\"true\"></i> heart</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-heart-o\" aria-hidden=\"true\"></i> heart-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-heartbeat\" aria-hidden=\"true\"></i> heartbeat</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-hospital-o\" aria-hidden=\"true\"></i> hospital-o</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-medkit\" copyright=\"J2eeFAST\" aria-hidden=\"true\"></i> medkit</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-plus-square\" aria-hidden=\"true\"></i> plus-square</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-stethoscope\" aria-hidden=\"true\"></i> stethoscope</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-user-md\" aria-hidden=\"true\"></i> user-md</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair\" aria-hidden=\"true\"></i> wheelchair</div>\r\n\t                            <div class=\"fa-hover col-md-3 col-sm-4\"><i class=\"fa fa-wheelchair-alt\" aria-hidden=\"true\"></i> wheelchair-alt</div>\r\n\t                        </div>\r\n\t                    </section>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/icon/glyphicons.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('glyphicons图标')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"float-e-margins\">\r\n                    <h2>Glyphicons 字体图标</h2> 包括250多个来自 Glyphicon Halflings 的字体图标。Glyphicons Halflings 一般是收费的，但是他们的作者允许 Bootstrap 免费使用。为了表示感谢，希望你在使用时尽量为 Glyphicons 添加一个友情链接。\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-9\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>所有图标 <small class=\"m-l-sm\">所有图标集合 - <a href=\"http://glyphicons.com/\" target=\"_blank\">Glyphicons</a> </small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content icons-box\">\r\n                        <div class=\"bs-glyphicons\">\r\n                            <ul class=\"bs-glyphicons-list\">\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-asterisk\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-asterisk</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-plus\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-plus</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-euro\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-euro</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-eur\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-eur</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-minus\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-minus</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-cloud\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-cloud</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-envelope\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-envelope</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-pencil\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-pencil</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-glass\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-glass</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-music\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-music</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-search\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-search</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-heart\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-heart</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-star\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-star</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-star-empty\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-star-empty</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-user\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-user</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-film\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-film</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-th-large\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-th-large</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-th\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-th</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-th-list\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-th-list</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-ok</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-remove</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-zoom-in\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-zoom-in</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-zoom-out\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-zoom-out</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-off\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-off</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-signal\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-signal</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-cog\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-cog</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-trash\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-trash</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-home\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-home</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-file\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-file</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-time\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-time</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-road\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-road</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-download-alt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-download-alt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-download\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-download</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-upload\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-upload</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-inbox\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-inbox</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-play-circle\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-play-circle</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-repeat\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-repeat</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-refresh\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-refresh</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-list-alt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-list-alt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-lock\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-lock</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-flag\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-flag</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-headphones\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-headphones</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-volume-off\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-volume-off</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-volume-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-volume-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-volume-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-volume-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-qrcode\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-qrcode</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-barcode\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-barcode</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tag\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tag</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tags\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tags</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-book\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-book</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-bookmark\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-bookmark</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-print\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-print</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-camera\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-camera</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-font\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-font</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-bold\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-bold</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-italic\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-italic</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-text-height\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-text-height</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-text-width\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-text-width</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-align-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-align-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-align-center\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-align-center</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-align-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-align-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-align-justify\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-align-justify</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-list\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-list</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-indent-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-indent-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-indent-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-indent-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-facetime-video\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-facetime-video</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-picture\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-picture</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-map-marker\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-map-marker</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-adjust\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-adjust</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tint\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tint</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-edit\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-edit</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-share\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-share</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-check\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-check</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-move\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-move</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-step-backward\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-step-backward</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-fast-backward\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-fast-backward</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-backward\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-backward</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-play\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-play</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-pause\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-pause</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-stop\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-stop</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-forward\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-forward</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-fast-forward\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-fast-forward</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-step-forward\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-step-forward</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-eject\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-eject</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-chevron-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-chevron-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-chevron-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-chevron-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-plus-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-plus-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-minus-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-minus-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-remove-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-remove-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-ok-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-ok-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-question-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-question-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-info-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-info-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-screenshot\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-screenshot</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-remove-circle\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-remove-circle</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-ok-circle\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-ok-circle</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-ban-circle\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-ban-circle</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-arrow-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-arrow-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-arrow-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-arrow-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-arrow-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-arrow-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-arrow-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-arrow-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-share-alt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-share-alt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-resize-full\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-resize-full</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-resize-small\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-resize-small</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-exclamation-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-exclamation-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-gift\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-gift</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-leaf\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-leaf</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-fire\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-fire</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-eye-open\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-eye-open</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-eye-close\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-eye-close</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-warning-sign\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-warning-sign</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-plane\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-plane</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-calendar\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-calendar</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-random\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-random</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-comment\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-comment</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-magnet\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-magnet</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-chevron-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-chevron-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-chevron-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-chevron-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-retweet\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-retweet</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-shopping-cart\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-shopping-cart</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-folder-close\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-folder-close</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-folder-open\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-folder-open</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-resize-vertical\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-resize-vertical</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-resize-horizontal\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-resize-horizontal</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-hdd\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-hdd</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-bullhorn\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-bullhorn</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-bell\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-bell</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-certificate\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-certificate</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-thumbs-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-thumbs-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-thumbs-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-thumbs-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-hand-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-hand-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-hand-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-hand-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-hand-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-hand-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-hand-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-hand-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-circle-arrow-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-circle-arrow-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-circle-arrow-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-circle-arrow-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-circle-arrow-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-circle-arrow-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-circle-arrow-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-circle-arrow-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-globe\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-globe</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-wrench\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-wrench</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tasks\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tasks</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-filter\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-filter</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-briefcase\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-briefcase</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-fullscreen\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-fullscreen</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-dashboard\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-dashboard</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-paperclip\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-paperclip</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-heart-empty\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-heart-empty</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-link\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-link</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-phone\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-phone</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-pushpin\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-pushpin</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-usd\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-usd</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-gbp\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-gbp</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sort\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sort</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sort-by-alphabet\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sort-by-alphabet</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sort-by-alphabet-alt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sort-by-alphabet-alt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sort-by-order\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sort-by-order</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sort-by-order-alt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sort-by-order-alt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sort-by-attributes\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sort-by-attributes</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sort-by-attributes-alt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sort-by-attributes-alt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-unchecked\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-unchecked</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-expand\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-expand</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-collapse-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-collapse-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-collapse-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-collapse-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-log-in\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-log-in</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-flash\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-flash</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-log-out\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-log-out</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-new-window\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-new-window</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-record\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-record</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-save\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-save</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-open\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-open</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-saved\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-saved</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-import\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-import</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-export\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-export</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-send\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-send</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-floppy-disk\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-floppy-disk</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-floppy-saved\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-floppy-saved</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-floppy-remove\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-floppy-remove</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-floppy-save\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-floppy-save</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-floppy-open\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-floppy-open</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-credit-card\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-credit-card</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-transfer\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-transfer</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-cutlery\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-cutlery</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-header\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-header</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-compressed\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-compressed</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-earphone\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-earphone</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-phone-alt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-phone-alt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tower\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tower</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-stats\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-stats</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sd-video\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sd-video</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-hd-video\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-hd-video</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-subtitles\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-subtitles</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sound-stereo\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sound-stereo</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sound-dolby\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sound-dolby</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sound-5-1\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sound-5-1</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sound-6-1\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sound-6-1</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sound-7-1\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sound-7-1</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-copyright-mark\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-copyright-mark</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-registration-mark\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-registration-mark</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-cloud-download\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-cloud-download</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-cloud-upload\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-cloud-upload</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tree-conifer\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tree-conifer</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tree-deciduous\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tree-deciduous</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-cd\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-cd</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-save-file\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-save-file</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-open-file\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-open-file</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-level-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-level-up</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-copy\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-copy</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-paste\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-paste</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-alert\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-alert</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-equalizer\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-equalizer</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-king\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-king</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-queen\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-queen</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-pawn\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-pawn</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-bishop\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-bishop</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-knight\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-knight</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-baby-formula\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-baby-formula</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-tent\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-tent</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-blackboard\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-blackboard</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-bed\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-bed</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-apple\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-apple</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-erase\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-erase</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-hourglass\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-hourglass</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-lamp\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-lamp</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-duplicate\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-duplicate</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-piggy-bank\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-piggy-bank</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-scissors\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-scissors</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-bitcoin\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-bitcoin</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-btc\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-btc</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-xbt\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-xbt</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-yen\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-yen</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-jpy\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-jpy</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-ruble\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-ruble</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-rub\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-rub</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-scale\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-scale</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-ice-lolly\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-ice-lolly</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-ice-lolly-tasted\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-ice-lolly-tasted</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-education\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-education</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-option-horizontal\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-option-horizontal</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-option-vertical\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-option-vertical</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-menu-hamburger\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-menu-hamburger</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-modal-window\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-modal-window</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-oil\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-oil</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-grain\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-grain</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-sunglasses\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-sunglasses</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-text-size\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-text-size</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-text-color\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-text-color</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-text-background\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-text-background</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-object-align-top\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-object-align-top</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-object-align-bottom\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-object-align-bottom</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-object-align-horizontal\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-object-align-horizontal</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-object-align-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-object-align-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-object-align-vertical\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-object-align-vertical</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-object-align-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-object-align-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-triangle-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-triangle-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-triangle-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-triangle-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-triangle-bottom\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-triangle-bottom</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-triangle-top\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-triangle-top</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-console\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-console</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-superscript\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-superscript</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-subscript\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-subscript</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-menu-left\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-menu-left</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-menu-right\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-menu-right</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-menu-down\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-menu-down</span>\r\n                                </li>\r\n\r\n                                <li>\r\n                                    <span class=\"glyphicon glyphicon-menu-up\" aria-hidden=\"true\"></span>\r\n                                    <span class=\"glyphicon-class\">glyphicon glyphicon-menu-up</span>\r\n                                </li>\r\n\r\n                            </ul>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/dialog.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('模态窗口')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n<div class=\"wrapper wrapper-content fadeInRight\">\r\n    <div class=\"row\">\r\n        <div class=\"col-sm-4\">\r\n            <div class=\"ibox \">\r\n                <div class=\"ibox-title\">\r\n                    <h5>模态窗口</h5>\r\n\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>创建自定义的RuoYi模态窗口可通过添加<code>.inmodal</code>类来实现。 </p>\r\n                    <div class=\"text-center\">\r\n                        <button type=\"button\" class=\"btn btn-primary\" data-toggle=\"modal\" data-target=\"#myModal\">打开示例窗口</button>\r\n                    </div>\r\n                    <div class=\"modal inmodal\" id=\"myModal\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\">\r\n                        <div class=\"modal-dialog\">\r\n                            <div class=\"modal-content animated bounceInRight\">\r\n                                <div class=\"modal-header\">\r\n                                    <button type=\"button\" class=\"close\" data-dismiss=\"modal\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">关闭</span>\r\n                                    </button>\r\n                                    <i class=\"fa fa-laptop modal-icon\"></i>\r\n                                    <h4 class=\"modal-title\">窗口标题</h4>\r\n                                    <small class=\"font-bold\">这里可以显示副标题。\r\n                                </div>\r\n                                <div class=\"modal-body\">\r\n                                    <p><strong>RuoYi</strong>是一个完全响应式，基于Bootstrap3.3.7最新版本开发的扁平化主题，她采用了主流的左右两栏式布局，使用了Html5+CSS3等现代技术，她提供了诸多的强大的可以重新组合的UI组件，并集成了最新的jQuery版本(v2.1.1)，当然，也集成了很多功能强大，用途广泛的jQuery插件，她可以用于所有的Web应用程序，如网站管理后台，网站会员中心，CMS，CRM，OA等等，当然，您也可以对她进行深度定制，以做出更强系统。</p>\r\n                                    <div class=\"form-group\">\r\n                                        <label>Email</label>\r\n                                        <input type=\"email\" placeholder=\"请输入您的Email\" class=\"form-control\">\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"modal-footer\">\r\n                                    <button type=\"button\" class=\"btn btn-white\" data-dismiss=\"modal\">关闭</button>\r\n                                    <button type=\"button\" class=\"btn btn-primary\">保存</button>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n\r\n                </div>\r\n            </div>\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title\">\r\n                    <h5>大小设置</h5>\r\n\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>模态窗口提供两种大小尺寸，可以通过为模态窗口的<code>.modal-dialog</code>添加类来实现 </p>\r\n\r\n                    <div class=\"text-center\">\r\n                        <button type=\"button\" class=\"btn btn-primary\" data-toggle=\"modal\" data-target=\"#myModal5\">大模态窗口</button>\r\n                        <button type=\"button\" class=\"btn btn-primary\" data-toggle=\"modal\" data-target=\"#myModal6\">小模态窗口</button>\r\n                    </div>\r\n                    <div class=\"modal inmodal fade\" id=\"myModal5\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\">\r\n                        <div class=\"modal-dialog modal-lg\">\r\n                            <div class=\"modal-content\">\r\n                                <div class=\"modal-header\">\r\n                                    <button type=\"button\" class=\"close\" data-dismiss=\"modal\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span>\r\n                                    </button>\r\n                                    <h4 class=\"modal-title\">窗口标题</h4>\r\n                                    <small class=\"font-bold\">这里可以显示副标题。\r\n                                </div>\r\n                                <div class=\"modal-body\">\r\n                                    <p><strong>RuoYi</strong>是一个完全响应式，基于Bootstrap3.3.7最新版本开发的扁平化主题，她采用了主流的左右两栏式布局，使用了Html5+CSS3等现代技术，她提供了诸多的强大的可以重新组合的UI组件，并集成了最新的jQuery版本(v2.1.1)，当然，也集成了很多功能强大，用途广泛的jQuery插件，她可以用于所有的Web应用程序，如网站管理后台，网站会员中心，CMS，CRM，OA等等，当然，您也可以对她进行深度定制，以做出更强系统。</p>\r\n                                </div>\r\n\r\n                                <div class=\"modal-footer\">\r\n                                    <button type=\"button\" class=\"btn btn-white\" data-dismiss=\"modal\">关闭</button>\r\n                                    <button type=\"button\" class=\"btn btn-primary\">保存</button>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"modal inmodal fade\" id=\"myModal6\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\">\r\n                        <div class=\"modal-dialog modal-sm\">\r\n                            <div class=\"modal-content\">\r\n                                <div class=\"modal-header\">\r\n                                    <button type=\"button\" class=\"close\" data-dismiss=\"modal\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span>\r\n                                    </button>\r\n                                    <h4 class=\"modal-title\">窗口标题</h4>\r\n                                </div>\r\n                                <div class=\"modal-body\">\r\n                                    <p><strong>RuoYi</strong>是一个完全响应式，基于Bootstrap3.3.7最新版本开发的扁平化主题，她采用了主流的左右两栏式布局，使用了Html5+CSS3等现代技术，她提供了诸多的强大的可以重新组合的UI组件，并集成了最新的jQuery版本(v2.1.1)，当然，也集成了很多功能强大，用途广泛的jQuery插件，她可以用于所有的Web应用程序，如网站管理后台，网站会员中心，CMS，CRM，OA等等，当然，您也可以对她进行深度定制，以做出更强系统。</p>\r\n                                </div>\r\n                                <div class=\"modal-footer\">\r\n                                    <button type=\"button\" class=\"btn btn-white\" data-dismiss=\"modal\">关闭</button>\r\n                                    <button type=\"button\" class=\"btn btn-primary\">保存</button>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"col-sm-8\">\r\n            <div class=\"ibox \">\r\n                <div class=\"ibox-title\">\r\n                    <h5>动画窗口</h5>\r\n\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>您可以通过为模态窗口的<code>.modal-content</code>添加类来实现动画效果 </p>\r\n\r\n                    <button type=\"button\" class=\"btn btn-primary\" data-toggle=\"modal\" data-target=\"#myModal2\">沿X轴转动</button>\r\n                    <div class=\"modal inmodal\" id=\"myModal2\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\">\r\n                        <div class=\"modal-dialog\">\r\n                            <div class=\"modal-content animated flipInY\">\r\n                                <div class=\"modal-header\">\r\n                                    <button type=\"button\" class=\"close\" data-dismiss=\"modal\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span>\r\n                                    </button>\r\n                                    <h4 class=\"modal-title\">窗口标题</h4>\r\n                                    <small class=\"font-bold\">这里可以显示副标题。\r\n                                </div>\r\n                                <div class=\"modal-body\">\r\n                                    <p><strong>RuoYi</strong>是一个完全响应式，基于Bootstrap3.3.7最新版本开发的扁平化主题，她采用了主流的左右两栏式布局，使用了Html5+CSS3等现代技术，她提供了诸多的强大的可以重新组合的UI组件，并集成了最新的jQuery版本(v2.1.1)，当然，也集成了很多功能强大，用途广泛的jQuery插件，她可以用于所有的Web应用程序，如网站管理后台，网站会员中心，CMS，CRM，OA等等，当然，您也可以对她进行深度定制，以做出更强系统。</p>\r\n                                </div>\r\n                                <div class=\"modal-footer\">\r\n                                    <button type=\"button\" class=\"btn btn-white\" data-dismiss=\"modal\">关闭</button>\r\n                                    <button type=\"button\" class=\"btn btn-primary\">保存</button>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n\r\n                    <button type=\"button\" class=\"btn btn-primary\" data-toggle=\"modal\" data-target=\"#myModal4\">基本动画</button>\r\n                    <div class=\"modal inmodal\" id=\"myModal4\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\">\r\n                        <div class=\"modal-dialog\">\r\n                            <div class=\"modal-content animated fadeIn\">\r\n                                <div class=\"modal-header\">\r\n                                    <button type=\"button\" class=\"close\" data-dismiss=\"modal\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span>\r\n                                    </button>\r\n                                    <i class=\"fa fa-clock-o modal-icon\"></i>\r\n                                    <h4 class=\"modal-title\">窗口标题</h4>\r\n                                    <small>这里可以显示副标题。\r\n                                </div>\r\n                                <div class=\"modal-body\">\r\n                                    <p><strong>RuoYi</strong>是一个完全响应式，基于Bootstrap3.3.7最新版本开发的扁平化主题，她采用了主流的左右两栏式布局，使用了Html5+CSS3等现代技术，她提供了诸多的强大的可以重新组合的UI组件，并集成了最新的jQuery版本(v2.1.1)，当然，也集成了很多功能强大，用途广泛的jQuery插件，她可以用于所有的Web应用程序，如网站管理后台，网站会员中心，CMS，CRM，OA等等，当然，您也可以对她进行深度定制，以做出更强系统。</p>\r\n                                </div>\r\n                                <div class=\"modal-footer\">\r\n                                    <button type=\"button\" class=\"btn btn-white\" data-dismiss=\"modal\">关闭</button>\r\n                                    <button type=\"button\" class=\"btn btn-primary\">保存</button>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n\r\n                </div>\r\n            </div>\r\n            <div class=\"ibox \">\r\n                <div class=\"ibox-title\">\r\n                    <h5>设置选项</h5>\r\n\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <p>可以通过数据绑定或者Javascript来实现模态窗口的相关功能，如果使用数据绑定，可以为元素添加<code>data-</code>，如<code>data-backdrop=\"\"</code>。</p>\r\n\r\n                    <div class=\"table-responsive\">\r\n                        <table class=\"table table-bordered table-striped\">\r\n                            <thead>\r\n                            <tr>\r\n                                <th style=\"width: 100px;\">名称</th>\r\n                                <th style=\"width: 50px;\">类型</th>\r\n                                <th style=\"width: 50px;\">默认值</th>\r\n                                <th>说明</th>\r\n                            </tr>\r\n                            </thead>\r\n                            <tbody>\r\n                            <tr>\r\n                                <td>backdrop</td>\r\n                                <td>boolean 或 string <code>'static'</code></td>\r\n                                <td>true</td>\r\n                                <td>遮罩层，或使用<code>'static'</code>指定遮罩层与关闭模态窗口不关联</td>\r\n                            </tr>\r\n                            <tr>\r\n                                <td>keyboard</td>\r\n                                <td>boolean</td>\r\n                                <td>true</td>\r\n                                <td>按Esc键时退出模态窗口</td>\r\n                            </tr>\r\n                            <tr>\r\n                                <td>show</td>\r\n                                <td>boolean</td>\r\n                                <td>true</td>\r\n                                <td>初始化完成后显示模态窗口</td>\r\n                            </tr>\r\n                            <tr>\r\n                                <td>remote</td>\r\n                                <td>path</td>\r\n                                <td>false</td>\r\n                                <td>\r\n                                    <p><strong class=\"text-danger\">推荐使用数据绑定方式，或使用\r\n                                        <a href=\"http://api.jquery.com/load/\">jQuery.load</a></p>\r\n                                    <p>远程URL示例：</p>\r\n                                    <div class=\"highlight\">\r\n                                        <pre><code class=\"language-html\" data-lang=\"html\"><span class=\"nt\">&lt;a</span> <span class=\"na\">data-toggle=</span><span class=\"s\">\"modal\"</span> <span class=\"na\">href=</span><span class=\"s\">\"remote.html\"</span> <span class=\"na\">data-target=</span><span class=\"s\">\"#modal\"</span><span class=\"nt\">&gt;</span>Click me<span class=\"nt\">&lt;/a&gt;</span></code></pre>\r\n                                    </div>\r\n                                </td>\r\n                            </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n</div>\r\n    <th:block th:include=\"include :: footer\" />\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/form.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增用户')\" />\r\n</head>\r\n<body>\r\n    <div class=\"main-content\">\r\n        <form id=\"form-user-add\" class=\"form-horizontal\">\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">用户名称：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"userName\" placeholder=\"请输入用户名称\" class=\"form-control\" type=\"text\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">归属部门：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                            \t<input name=\"deptName\" type=\"text\" placeholder=\"请选择归属部门\" class=\"form-control\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">手机号码：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"phonenumber\" placeholder=\"请输入手机号码\" class=\"form-control\" type=\"text\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">邮箱：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"email\" class=\"form-control\" type=\"text\" placeholder=\"请输入邮箱\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">登录账号：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"loginName\" placeholder=\"请输入登录账号\" class=\"form-control\" type=\"text\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">登录密码：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"password\" placeholder=\"请输入登录密码\" class=\"form-control\" type=\"password\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">用户性别：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\" style=\"width: 100%\">\r\n                                <select name=\"sex\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_user_sex')}\">\r\n\t\t\t\t                    <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t                </select>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">用户状态：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <label class=\"toggle-switch switch-solid\">\r\n\t                            <input type=\"checkbox\" id=\"status\" checked>\r\n\t                            <span></span>\r\n\t                        </label>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n        function submitHandler() {\r\n        \tif ($.validate.form()) {\r\n        \t\t$.modal.msgSuccess('保存成功！');\r\n            }\r\n        }\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/layer.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('弹层组件')\" />\r\n\t<style>\r\n        /* 解决layer相册层弹出时导致页面自动滚动 */\r\n        html {height: auto;}\r\n    </style>\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"wrapper wrapper-content fadeInRight\">\r\n\t    <div class=\"row\">\r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>信息框</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\" id=\"test\">\r\n\t                    <p>通过调用<code>$.modal.alert()</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" onclick=\"$.modal.alert('Hi，你好！')\">普通</button>\r\n\t                    <button type=\"button\" class=\"btn btn-success\" onclick=\"$.modal.alertSuccess('Hi，你好！')\">成功</button>\r\n\t                    <button type=\"button\" class=\"btn btn-warning\" onclick=\"$.modal.alertWarning('Hi，你好！')\">警告</button>\r\n\t                    <button type=\"button\" class=\"btn btn-danger\" onclick=\"$.modal.alertError('Hi，你好！')\">失败</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>提示框</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\">\r\n\t                    <p>通过调用<code>$.modal.msg()</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" onclick=\"$.modal.msg('Hi，你好！')\">普通</button>\r\n\t                    <button type=\"button\" class=\"btn btn-success\" onclick=\"$.modal.msgSuccess('Hi，你好！')\">成功</button>\r\n\t                    <button type=\"button\" class=\"btn btn-warning\" onclick=\"$.modal.msgWarning('Hi，你好！')\">警告</button>\r\n\t                    <button type=\"button\" class=\"btn btn-danger\" onclick=\"$.modal.msgError('Hi，你好！')\">失败</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t    </div>\r\n\t\r\n\t    <div class=\"row\">\r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>询问框</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\">\r\n\t                    <p>通过调用<code>$.modal.confirm()</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-confirm\">询问按钮</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox \">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>消息提示并刷新父窗体</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\">\r\n\t                    <p>通过调用<code>$.modal.msgReload()</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-msgReload\">提示刷新按钮</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>普通弹出层</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\">\r\n\t                    <p>通过调用<code>$.modal.open()</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-1\">默认</button>\r\n\t                    <button type=\"button\" class=\"btn btn-success\" id=\"button-open-2\">设置宽高</button>\r\n\t                    <button type=\"button\" class=\"btn btn-warning\" id=\"button-open-3\">回调函数</button>\r\n\t                    <button type=\"button\" class=\"btn btn-danger\" id=\"button-open-4\">自定义选项</button>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-5\">全屏弹出</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>选卡页方式</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\">\r\n\t                    <p>通过调用<code>$.modal.openTab()</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-6\">新窗口打开</button>\r\n\t                    <button type=\"button\" class=\"btn btn-warning\" id=\"button-open-7\">关闭当前</button>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-14\">选卡页同一页签打开</button>\r\n\t                    <button type=\"button\" class=\"btn btn-warning\" id=\"button-open-15\">关闭指定</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>其他内容</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\">\r\n\t                    <p>通过调用<code>layer</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-8\">tab层</button>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-9\">prompt层</button>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-10\">捕获页</button>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-16\">相册层</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-6\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>遮罩层</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\">\r\n\t                    <p>通过调用<code>blockUI</code>实现。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-11\">打开</button>\r\n\t                    <button type=\"button\" class=\"btn btn-warning\" id=\"button-open-12\">关闭</button>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" id=\"button-open-13\">layer遮罩</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-12\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n                        <label class=\"font-noraml\">相关参数详细信息</label>\r\n                        <div><a href=\"http://doc.ruoyi.vip/#/standard/zjwd?id=layer\" target=\"_blank\">http://doc.ruoyi.vip/#/standard/zjwd?id=layer</a></div>\r\n\t            </div>\r\n\t        </div>\r\n\t        \r\n\t    </div>\r\n\t</div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/modal\";\r\n        \r\n\t    $(\"#button-confirm\").click(function(){\r\n\t    \t$.modal.confirm(\"确认要点击确定吗?\", function() {\r\n\t    \t\t$.modal.alert(\"ok\");\r\n\t    \t});\r\n\t    })\r\n\t    \r\n\t    $(\"#button-msgReload\").click(function(){\r\n\t        $.modal.msgReload(\"保存成功,正在刷新数据请稍候……\", modal_status.SUCCESS);\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-1\").click(function(){\r\n\t    \t$.modal.open('添加用户', prefix + \"/form\");\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-2\").click(function(){\r\n\t    \t$.modal.open('添加用户', prefix + \"/form\", '900', '320');\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-3\").click(function(){\r\n\t    \t$.modal.open('添加用户', prefix + \"/form\", '900', '320', callback);\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-4\").click(function(){\r\n\t    \tvar btn = ['<i class=\"fa fa-check\"></i> 点我回调', '<i class=\"fa fa-close\"></i> 点我关闭'];\r\n\t\t\tvar options = {\r\n\t\t\t\ttitle: '添加用户',\r\n\t\t\t\twidth: \"900\",\r\n\t\t\t\theight: \"320\",\r\n\t\t\t\turl: prefix + \"/form\",\r\n\t\t\t\tbtn: btn,\r\n\t\t\t\tcallBack: doSubmit\r\n\t\t\t};\r\n\t\t\t$.modal.openOptions(options);\r\n\t    })\r\n\t    \r\n\t    function doSubmit(index, layero) {\r\n\t    \talert(\"进入了自定义选项提交方法\");\r\n\t    }\r\n\t    \r\n\t    function callback(index, layero) {\r\n\t    \talert(\"进入了回调函数提交方法\");\r\n\t    }\r\n\t    \r\n\t    $(\"#button-open-5\").click(function(){\r\n\t    \t$.modal.openFull('添加用户', prefix + \"/form\");\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-6\").click(function(){\r\n\t    \t$.modal.openTab('添加用户', prefix + \"/form\");\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-7\").click(function(){\r\n\t    \t$.modal.closeTab();\r\n\t    })\r\n\t    \r\n\t     $(\"#button-open-8\").click(function(){\r\n\t    \t//tab层\r\n\t    \t layer.tab({\r\n\t    \t     area: ['600px', '300px'],\r\n\t    \t     tab: [{\r\n\t    \t         title: 'TAB1',\r\n\t    \t         content: '内容1'\r\n\t    \t     },\r\n\t    \t     {\r\n\t    \t         title: 'TAB2',\r\n\t    \t         content: '内容2'\r\n\t    \t     },\r\n\t    \t     {\r\n\t    \t         title: 'TAB3',\r\n\t    \t         content: '内容3'\r\n\t    \t     }]\r\n\t    \t });\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-9\").click(function(){\r\n\t    \tlayer.prompt({title: '输入任何口令，并确认', formType: 1}, function(pass, index){\r\n\t    \t  layer.close(index);\r\n\t    \t  layer.prompt({title: '随便写点啥，并确认', formType: 2}, function(text, index){\r\n\t    \t    layer.close(index);\r\n\t    \t    layer.msg('演示完毕！您的口令：'+ pass +'<br>您最后写下了：'+text);\r\n\t    \t  });\r\n\t    \t});\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-10\").click(function(){\r\n\t    \tlayer.open({\r\n    \t\t  type: 1,\r\n    \t\t  shade: false,\r\n    \t\t  title: false, //不显示标题\r\n    \t\t  content: $('#test'), //捕获的元素，注意：最好该指定的元素要存放在body最外层，否则可能被其它的相对元素所影响\r\n    \t\t  cancel: function(){\r\n    \t\t    layer.msg('捕获就是从页面已经存在的元素上，包裹layer的结构', {time: 5000, icon:6});\r\n    \t\t  }\r\n    \t\t});\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-11\").click(function(){\r\n\t    \t$.modal.loading(\"数据加载中\");\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-12\").click(function(){\r\n\t    \t$.modal.closeLoading();\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-13\").click(function(){\r\n\t    \tlayer.load(0, {shade: false}); // 0代表加载的风格，支持0-2\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-14\").click(function(){\r\n\t    \t$.modal.parentTab('添加用户', prefix + \"/form\");\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-15\").click(function(){\r\n\t    \t// 需要关闭窗口的url\r\n\t    \t$.modal.closeTab(prefix + \"/form\");\r\n\t    })\r\n\t    \r\n\t    $(\"#button-open-16\").click(function(){\r\n            var json = {\r\n            \t\t\"title\": \"若依相册\", //相册标题\r\n            \t\t\"id\": 123, //相册id\r\n            \t\t\"start\": 0, //初始显示的图片序号，默认0\r\n            \t\t\"data\": [   //相册包含的图片，数组格式\r\n            \t\t    {\r\n            \t\t        \"alt\": \"默认头像\",\r\n            \t\t        \"pid\": 1, //图片id\r\n            \t\t        \"src\": ctx + \"img/profile.jpg\", //原图地址\r\n            \t\t        \"thumb\": ctx + \"img/profile.jpg\" //缩略图地址\r\n            \t\t    },\r\n            \t\t    {\r\n                            \"alt\": \"打赏\",\r\n                            \"pid\": 2, //图片id\r\n                            \"src\": ctx + \"img/pay.png\", //原图地址\r\n                            \"thumb\": ctx + \"img/pay.png\" //缩略图地址\r\n                        }\r\n            \t\t ]\r\n            };\r\n            layer.photos({\r\n                photos: json,\r\n                closeBtn: 0, //右上角按钮，可通过配置1和2来展示，如果不显示，则closeBtn: 0\r\n                anim: 5 //0-6的选择，指定弹出图片动画类型，默认随机（请注意，3.0之前的版本用shift参数）\r\n            });\r\n        })\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/table/check.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('check表格页')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        /* 添加用户-选择用户-提交 */\r\n\t\tfunction submitHandler() {\r\n\t\t\tvar rows = $.table.selectFirstColumns();\r\n\t\t\tif (rows.length == 0) {\r\n       \t\t\t$.modal.alertWarning(\"请至少选择一条记录\");\r\n       \t\t\treturn;\r\n       \t\t}\r\n\t\t\talert(rows.join());\r\n\t\t}\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/table/frame1.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('多层窗口A')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<form id=\"form-user-add\" class=\"form-horizontal\">\n\t            <div class=\"row\">\n\t            \t<div class=\"col-sm-12\" style=\"margin-top: 50px\">\n\t                    <div class=\"form-group\">\n\t                        <label class=\"col-sm-4 control-label\">用户名称：</label>\n\t                        <div class=\"col-sm-4\">\n\t                            <input id=\"name\" placeholder=\"请输入用户名称\" class=\"form-control\" type=\"text\">\n\t                        </div>\n\t                        <button type=\"button\" class=\"btn btn-primary\" onclick=\"selectUserToParentId()\">选择</button>\n\t                    </div>\n\t                </div>\n\t           </div>\n\t\t\t</form>\n\t\t</div>\n\t</div>\n    <div th:include=\"include :: footer\"></div>\n    <script th:inline=\"javascript\">\n        /* 提交 */\n\t\tfunction submitHandler() {\n        \tvar name = $(\"#name\").val();\n\t\t\tactiveWindow().$('#username').html(name);\n\t\t\t$.modal.close();\n\t\t}\n        \n\t\t// 根据父窗口ID获取\n\t\tfunction selectUserToParentId(){\n\t\t\tvar prefix = ctx + \"demo/modal\";\n            var options = {\n                width: '100px',\n                height: '100px',\n                title: '多层窗口B',\n                url: prefix + \"/frame2\",\n                callBack: doSubmit\n            };\n            $.modal.openOptions(options);\n        }\n\t\t\n\t\tfunction doSubmit(index, layero){\n\t\t\tvar body = $.modal.getChildFrame(index);\n   \t\t\t$(\"#name\").val(body.find('#name').val());\n   \t\t\t$.modal.close(index);\n\t\t}\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/table/frame2.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('多层窗口B')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<form id=\"form-user-add\" class=\"form-horizontal\">\n\t            <div class=\"row\">\n\t            \t<div class=\"col-sm-12\" style=\"margin-top: 20px\">\n\t                    <div class=\"form-group\">\n\t                        <label class=\"col-sm-4 control-label\">用户名称：</label>\n\t                        <div class=\"col-sm-4\">\n\t                            <input id=\"name\" placeholder=\"请输入用户名称\" class=\"form-control\" type=\"text\">\n\t                        </div>\n\t                    </div>\n\t                </div>\n\t           </div>\n\t\t\t</form>\n\t\t</div>\n\t</div>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/table/parent.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格传值给父页面')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <input type=\"hidden\" id=\"rowIds\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        /* 添加用户-选择用户-提交(子页面调用父页面形式) */\r\n\t\tfunction submitHandler(index, layero) {\r\n\t\t\tvar rows = $.table.selectFirstColumns();\r\n\t\t\tif (rows.length == 0) {\r\n       \t\t\t$.modal.alertWarning(\"请至少选择一条记录\");\r\n       \t\t\treturn;\r\n       \t\t}\r\n\t\t\t$.modal.close();\r\n\t\t\t// 父页面的方法\r\n\t\t\t// activeWindow().selectUsers();\r\n\t\t\t// 父页面的变量\r\n\t\t\tactiveWindow().$('#userids').html('我是通过方式一来的：' + rows.join());\r\n\t\t}\r\n        \r\n\t\t/* 添加用户-选择用户-提交(回调形式-父页面调用子页面) */\r\n\t\tfunction getSelections() {\r\n\t\t\treturn $.table.selectFirstColumns();\r\n\t\t}\r\n\r\n\t\t$(\"#bootstrap-table\").on(\"check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table\", function (e, rowsAfter, rowsBefore) {\r\n            var rows = $.common.equals(\"uncheck-all\", e.type) ? rowsBefore : rowsAfter;\r\n            var rowIds = $.table.affectedRowIds(rows);\r\n            $(\"#rowIds\").val(rowIds);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/table/radio.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('radio表格页')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            radio: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        /* 添加用户-选择用户-提交 */\r\n\t\tfunction submitHandler() {\r\n\t\t\tvar rows = $.table.selectFirstColumns();\r\n\t\t\tif (rows.length == 0) {\r\n       \t\t\t$.modal.alertWarning(\"请至少选择一条记录\");\r\n       \t\t\treturn;\r\n       \t\t}\r\n\t\t\talert(rows.join());\r\n\t\t}\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/modal/table.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('弹层表格')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"wrapper wrapper-content fadeInRight\">\r\n\t    <div class=\"row\">\r\n\t        <div class=\"col-sm-12\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>弹层框</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\" id=\"test\">\r\n\t                    <p>弹出复选框表格及单选框表格（点击提交后得到数据）。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" onclick=\"selectCheckUser()\">弹出表格（复选框）</button>\r\n\t                    <button type=\"button\" class=\"btn btn-success\" onclick=\"selectRadioUser()\">弹出表格（单选框）</button>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        <div class=\"col-sm-12\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>弹层框</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\" id=\"test\">\r\n\t                    <p>弹出层，点击提交后得到数据并回显到父窗体。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" onclick=\"selectUsersToParent()\">弹出表格（方式一）</button>\r\n\t                    <button type=\"button\" class=\"btn btn-success\" onclick=\"selectUsersToParentCallBack2()\">弹出表格（方式二）</button>\r\n\t                    <button type=\"button\" class=\"btn btn-info\" onclick=\"selectUsersToParentCallBack3()\">弹出表格（方式三）</button>\r\n\t                    <p id=\"userids\"> </p>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t        <div class=\"col-sm-12\">\r\n\t            <div class=\"ibox\">\r\n\t                <div class=\"ibox-title\">\r\n\t                <h5>弹层框</h5>\r\n\t                </div>\r\n\t                <div class=\"ibox-content\" id=\"test\">\r\n\t                    <p>多层弹出，点击提交后得到数据并回显到父窗体。 </p>\r\n\t                    <button type=\"button\" class=\"btn btn-primary\" onclick=\"selectUsersToParent4()\">弹出窗口（方式四）</button>\r\n\t                    <p id=\"username\"> </p>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t    </div>\r\n\t</div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n        var prefix = ctx + \"demo/modal\";\r\n\r\n        function selectCheckUser(){\r\n        \t$.modal.open(\"选择用户\", prefix + \"/check\");\r\n        }\r\n\r\n\t\tfunction selectRadioUser(){\r\n\t\t\t$.modal.open(\"选择用户\", prefix + \"/radio\");\r\n        }\r\n\r\n\t\t// 根据当前激活的选项卡获取（方式一）\r\n\t\tfunction selectUsersToParent(){\r\n\t\t\t$.modal.open(\"选择用户\", prefix + \"/parent\");\r\n        }\r\n\t\t\r\n\t\t// callBack获取父窗口方法（方式二）\r\n\t\tfunction selectUsersToParentCallBack2(){\r\n            var options = {\r\n                title: '选择用户',\r\n                url: prefix + \"/parent\",\r\n                callBack: doSubmit2\r\n             };\r\n             $.modal.openOptions(options);\r\n        }\r\n\r\n\t\t// callBack获取父窗口值（方式三）\r\n\t\tfunction selectUsersToParentCallBack3(){\r\n            var options = {\r\n                title: '选择用户',\r\n                url: prefix + \"/parent\",\r\n                callBack: doSubmit3\r\n             };\r\n             $.modal.openOptions(options);\r\n        }\r\n\t\t\r\n\t\t// callBack获取父窗口值（方式四）\r\n\t\tfunction selectUsersToParent4(){\r\n\t\t\tvar prefix = ctx + \"demo/modal\";\r\n            var options = {\r\n                title: '多层窗口A',\r\n                url: prefix + \"/frame1\",\r\n                callBack: doSubmit4\r\n            };\r\n            $.modal.openOptions(options);\r\n        }\r\n\t\t\r\n\t\tfunction doSubmit2(index, layero){\r\n\t\t    var rows = layero.find(\"iframe\")[0].contentWindow.getSelections();\r\n\t\t    if (rows.length == 0) {\r\n                $.modal.alertWarning(\"请至少选择一条记录\");\r\n                return;\r\n            }\r\n\t\t    $('#userids').html('我是通过方式二来的：' + rows.join())\r\n\t\t    $.modal.close(index);\r\n\t\t}\r\n\r\n\t\tfunction doSubmit3(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#userids\").html('我是通过方式三来的：' + body.find('#rowIds').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n\t\t\r\n\t\tfunction doSubmit4(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#username\").html('我是通过方式四来的：' + body.find('#name').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n\t\t\r\n\t\tfunction selectUsers(){\r\n\t\t\talert(1);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/operate/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增用户')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-user-add\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户编号：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userCode\" id=\"userCode\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户姓名：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userName\" id=\"userName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户性别：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <div class=\"input-group\" style=\"width: 100%\">\r\n                        <select name=\"userSex\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_user_sex')}\">\r\n\t\t\t                <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t            </select>\r\n                    </div>\r\n                </div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户手机：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userPhone\" id=\"userPhone\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户邮箱：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userEmail\" id=\"userEmail\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"demo/operate\";\r\n\t\t\r\n\t\t$(\"#form-user-add\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tuserPhone:{\r\n\t\t\t\t\tisPhone:true\r\n\t\t\t\t},\r\n\t\t\t\tuserEmail:{\r\n\t\t\t\t\temail:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/add\", $('#form-user-add').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/operate/detail.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('用户详细')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-user-edit\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户编号：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"form-control-static\" th:text=\"${user.userCode}\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户姓名：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"form-control-static\" th:text=\"${user.userName}\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户性别：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <div class=\"form-control-static\" th:text=\"${@dict.getLabel('sys_user_sex', user.status)}\"></div>\r\n                </div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户手机：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"form-control-static\" th:text=\"${user.userPhone}\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户邮箱：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"form-control-static\" th:text=\"${user.userEmail}\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"form-control-static\" th:text=\"${@dict.getLabel('sys_normal_disable', user.status)}\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"demo/operate\";\r\n\r\n\t\t$(\"#form-user-add\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tuserPhone:{\r\n\t\t\t\t\tisPhone:true\r\n\t\t\t\t},\r\n\t\t\t\tuserEmail:{\r\n\t\t\t\t\temail:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-user-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/operate/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改用户')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-user-edit\" th:object=\"${user}\">\r\n\t\t    <input name=\"userId\" type=\"hidden\"  th:field=\"*{userId}\" />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户编号：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userCode\" id=\"userCode\" th:field=\"*{userCode}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户姓名：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userName\" id=\"userName\" th:field=\"*{userName}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户性别：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <div class=\"input-group\" style=\"width: 100%\">\r\n                        <select name=\"userSex\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_user_sex')}\">\r\n\t\t\t                <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\" th:field=\"*{userSex}\"></option>\r\n\t\t\t            </select>\r\n                    </div>\r\n                </div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户手机：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userPhone\" th:field=\"*{userPhone}\" id=\"userPhone\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户邮箱：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"userEmail\" th:field=\"*{userEmail}\" id=\"userEmail\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">用户状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:field=\"*{status}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"demo/operate\";\r\n\t\t\r\n\t\t$(\"#form-user-add\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tuserPhone:{\r\n\t\t\t\t\tisPhone:true\r\n\t\t\t\t},\r\n\t\t\t\tuserEmail:{\r\n\t\t\t\t\temail:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-user-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/operate/other.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('其他操作')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t    <form class=\"form-horizontal\" id=\"form-demo-1\">\r\n\t        <div class=\"form-group\">\r\n\t            <label class=\"col-sm-2 control-label\">用户名称：</label>\r\n\t            <div class=\"col-sm-10\">\r\n\t                <input type=\"text\" class=\"form-control\" name=\"userName\" placeholder=\"请输入用户名称\">\r\n\t            </div>\r\n\t        </div>\r\n\t        <div class=\"form-group\">\r\n\t            <label class=\"col-sm-2 control-label\">手机号码：</label>\r\n\t            <div class=\"col-sm-10\">\r\n\t                <input type=\"text\" class=\"form-control\" name=\"phonenumber\" maxlength=\"11\" placeholder=\"请输入手机号码\">\r\n\t            </div>\r\n\t        </div>\r\n\t        <div class=\"form-group\">\r\n\t            <div class=\"col-sm-offset-2 col-sm-10\">\r\n\t                <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submit1()\"><i class=\"fa fa-check\"></i>保 存（不刷新当前页）</button>&nbsp;\r\n\t            </div>\r\n\t        </div>\r\n\t    </form>\r\n\t    <hr/>\r\n\t    <form class=\"form-horizontal\" id=\"form-demo-2\">\r\n\t        <div class=\"form-group\">\r\n\t            <label class=\"col-sm-2 control-label\">用户名称：</label>\r\n\t            <div class=\"col-sm-10\">\r\n\t                <input type=\"text\" class=\"form-control\" name=\"userName\" placeholder=\"请输入用户名称\">\r\n\t            </div>\r\n\t        </div>\r\n\t        <div class=\"form-group\">\r\n\t            <label class=\"col-sm-2 control-label\">手机号码：</label>\r\n\t            <div class=\"col-sm-10\">\r\n\t                <input type=\"text\" class=\"form-control\" name=\"phonenumber\" maxlength=\"11\" placeholder=\"请输入手机号码\">\r\n\t            </div>\r\n\t        </div>\r\n\t        <div class=\"form-group\">\r\n\t            <div class=\"col-sm-offset-2 col-sm-10\">\r\n\t                <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submit2()\"><i class=\"fa fa-check\"></i>保 存（刷新当前页）</button>&nbsp;\r\n\t            </div>\r\n\t        </div>\r\n\t    </form>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t    var prefix = ctx + \"demo/operate\";\r\n\t    function submit1(){\r\n\t    \t$.operate.saveModal(prefix + \"/edit\", $('#form-demo-1').serialize());\r\n\t    }\r\n\t    \r\n\t    function submit2(){\r\n\t    \t$.ajax({\r\n\t            url: prefix + \"/edit\",\r\n\t            data: $('#form-demo-2').serialize(),\r\n\t            type: \"post\",\r\n\t            success: function(result) {\r\n\t            \tif (result.code == web_status.SUCCESS) {\r\n\t            \t\tlayer.msg(\"保存成功,正在刷新数据请稍候……\", {\r\n\t\t            \t    icon: 1,\r\n\t\t            \t    time: 500,\r\n\t\t            \t    shade: [0.1, '#8F8F8F']\r\n\t\t            \t},function() {\r\n\t\t            \t\tlocation.reload();\r\n\t\t            \t});\r\n\t            \t} else {\r\n\t            \t\talert(result.msg);\r\n\t            \t}\r\n\t            }\r\n\t        })\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/operate/table.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('其他操作')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n     \t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t        <a class=\"btn btn-success\" onclick=\"$.operate.add()\">\r\n\t            <i class=\"fa fa-plus\"></i> 新增\r\n\t        </a>\r\n\t        <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\">\r\n\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t        </a>\r\n\t        <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\">\r\n\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t        </a>\r\n\t        <a class=\"btn btn-info\" onclick=\"$.table.importExcel()\">\r\n\t            <i class=\"fa fa-upload\"></i> 导入\r\n\t        </a>\r\n\t        <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\">\r\n\t            <i class=\"fa fa-download\"></i> 导出\r\n\t        </a>\r\n\t        <a class=\"btn btn-info single disabled\" onclick=\"$.operate.detail()\">\r\n\t            <i class=\"fa fa-search\"></i> 详细\r\n\t        </a>\r\n\t        <a class=\"btn btn-danger\" onclick=\"$.operate.clean()\">\r\n\t            <i class=\"fa fa-trash\"></i> 清空\r\n\t        </a>\r\n        </div>\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/operate\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n                createUrl: prefix + \"/add\",\r\n                updateUrl: prefix + \"/edit/{id}\",\r\n                removeUrl: prefix + \"/remove\",\r\n                exportUrl: prefix + \"/export\",\r\n                importUrl: prefix + \"/importData\",\r\n                importTemplateUrl: prefix + \"/importTemplate\",\r\n                detailUrl: prefix + \"/detail/{id}\",\r\n                cleanUrl: prefix + \"/clean\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        search: true,\r\n\t\t        modalName: \"用户\",\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\" onclick=\"$.operate.edit(\\'' + row.userId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-info btn-xs\" href=\"javascript:;\" onclick=\"$.operate.detail(\\'' + row.userId + '\\')\"><i class=\"fa fa-search\"></i>详细</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\" onclick=\"$.operate.remove(\\'' + row.userId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n<!-- 导入区域 -->\r\n<script id=\"importTpl\" type=\"text/template\">\r\n<form enctype=\"multipart/form-data\" class=\"mt20 mb10\">\r\n\t<div class=\"col-xs-offset-1\">\r\n\t\t<input type=\"file\" id=\"file\" name=\"file\"/>\r\n\t\t<div class=\"mt10 pt5\">\r\n\t\t\t<input type=\"checkbox\" id=\"updateSupport\" name=\"updateSupport\" title=\"如果登录账户已经存在，更新这条数据。\"> 是否更新已经存在的用户数据\r\n\t\t\t &nbsp;\t<a onclick=\"$.table.importTemplate()\" class=\"btn btn-default btn-xs\"><i class=\"fa fa-file-excel-o\"></i> 下载模板</a>\r\n\t\t</div>\r\n\t\t<font color=\"red\" class=\"pull-left mt10\">\r\n\t\t\t提示：仅允许导入“xls”或“xlsx”格式文件！\r\n\t\t</font>\r\n\t</div>\r\n</form>\r\n</script>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/report/echarts.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('百度ECharts')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"row  border-bottom white-bg dashboard-header\">\r\n        <div class=\"col-sm-12\">\r\n            <p>ECharts开源来自百度商业前端数据可视化团队，基于html5 Canvas，是一个纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据可视化图表。创新的拖拽重计算、数据视图、值域漫游等特性大大增强了用户体验，赋予了用户对数据进行挖掘、整合的能力。 <a href=\"https://echarts.apache.org/handbook/zh/get-started/\" target=\"_blank\">了解更多</a>\r\n            </p>\r\n            <p>ECharts官网：<a href=\"https://echarts.apache.org/\" target=\"_blank\">https://echarts.apache.org/</a>\r\n            </p>\r\n\r\n        </div>\r\n    </div>\r\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>折线图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"echarts\" id=\"echarts-line-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>柱状图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n\r\n                        <div class=\"echarts\" id=\"echarts-bar-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>散点图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"echarts\" id=\"echarts-scatter-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>K线图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"echarts\" id=\"echarts-k-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>饼状图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"echarts\" id=\"echarts-pie-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>雷达图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"echarts\" id=\"echarts-radar-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>仪表盘</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"echarts\" id=\"echarts-gauge-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-6\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>漏斗图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"echarts\" id=\"echarts-funnel-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>中国地图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div style=\"height:600px\" id=\"echarts-map-chart\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: echarts-js\" />\r\n    <script type=\"text/javascript\">\r\n\t    $(function () {\r\n\t        var lineChart = echarts.init(document.getElementById(\"echarts-line-chart\"));\r\n\t        var lineoption = {\r\n\t            title : {\r\n\t                text: '未来一周气温变化'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'axis'\r\n\t            },\r\n\t            legend: {\r\n\t                data:['最高气温','最低气温']\r\n\t            },\r\n\t            grid:{\r\n\t                x:40,\r\n\t                x2:40,\r\n\t                y2:24\r\n\t            },\r\n\t            calculable : true,\r\n\t            xAxis : [\r\n\t                {\r\n\t                    type : 'category',\r\n\t                    boundaryGap : false,\r\n\t                    data : ['周一','周二','周三','周四','周五','周六','周日']\r\n\t                }\r\n\t            ],\r\n\t            yAxis : [\r\n\t                {\r\n\t                    type : 'value',\r\n\t                    axisLabel : {\r\n\t                        formatter: '{value} °C'\r\n\t                    }\r\n\t                }\r\n\t            ],\r\n\t            series : [\r\n\t                {\r\n\t                    name:'最高气温',\r\n\t                    type:'line',\r\n\t                    data:[11, 11, 15, 13, 12, 13, 10],\r\n\t                    markPoint : {\r\n\t                        data : [\r\n\t                            {type : 'max', name: '最大值'},\r\n\t                            {type : 'min', name: '最小值'}\r\n\t                        ]\r\n\t                    },\r\n\t                    markLine : {\r\n\t                        data : [\r\n\t                            {type : 'average', name: '平均值'}\r\n\t                        ]\r\n\t                    }\r\n\t                },\r\n\t                {\r\n\t                    name:'最低气温',\r\n\t                    type:'line',\r\n\t                    data:[1, -2, 2, 5, 3, 2, 0],\r\n\t                    markPoint : {\r\n\t                        data : [\r\n\t                            {name : '周最低', value : -2, xAxis: 1, yAxis: -1.5}\r\n\t                        ]\r\n\t                    },\r\n\t                    markLine : {\r\n\t                        data : [\r\n\t                            {type : 'average', name : '平均值'}\r\n\t                        ]\r\n\t                    }\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t        lineChart.setOption(lineoption);\r\n\t        $(window).resize(lineChart.resize);\r\n\t\r\n\t        var barChart = echarts.init(document.getElementById(\"echarts-bar-chart\"));\r\n\t        var baroption = {\r\n\t            title : {\r\n\t                text: '某地区蒸发量和降水量'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'axis'\r\n\t            },\r\n\t            legend: {\r\n\t                data:['蒸发量','降水量']\r\n\t            },\r\n\t            grid:{\r\n\t                x:30,\r\n\t                x2:40,\r\n\t                y2:24\r\n\t            },\r\n\t            calculable : true,\r\n\t            xAxis : [\r\n\t                {\r\n\t                    type : 'category',\r\n\t                    data : ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月']\r\n\t                }\r\n\t            ],\r\n\t            yAxis : [\r\n\t                {\r\n\t                    type : 'value'\r\n\t                }\r\n\t            ],\r\n\t            series : [\r\n\t                {\r\n\t                    name:'蒸发量',\r\n\t                    type:'bar',\r\n\t                    data:[2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3],\r\n\t                    markPoint : {\r\n\t                        data : [\r\n\t                            {type : 'max', name: '最大值'},\r\n\t                            {type : 'min', name: '最小值'}\r\n\t                        ]\r\n\t                    },\r\n\t                    markLine : {\r\n\t                        data : [\r\n\t                            {type : 'average', name: '平均值'}\r\n\t                        ]\r\n\t                    }\r\n\t                },\r\n\t                {\r\n\t                    name:'降水量',\r\n\t                    type:'bar',\r\n\t                    data:[2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3],\r\n\t                    markPoint : {\r\n\t                        data : [\r\n\t                            {name : '年最高', value : 182.2, xAxis: 7, yAxis: 183, symbolSize:18},\r\n\t                            {name : '年最低', value : 2.3, xAxis: 11, yAxis: 3}\r\n\t                        ]\r\n\t                    },\r\n\t                    markLine : {\r\n\t                        data : [\r\n\t                            {type : 'average', name : '平均值'}\r\n\t                        ]\r\n\t                    }\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t        barChart.setOption(baroption);\r\n\t\r\n\t        window.onresize = barChart.resize;\r\n\t\r\n\t        var scatterChart = echarts.init(document.getElementById(\"echarts-scatter-chart\"));\r\n\t        var scatteroption = {\r\n\t            title : {\r\n\t                text: '男性女性身高体重分布',\r\n\t                subtext: '抽样调查来自: Heinz  2003'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'axis',\r\n\t                showDelay : 0,\r\n\t                axisPointer:{\r\n\t                    type : 'cross',\r\n\t                    lineStyle: {\r\n\t                        type : 'dashed',\r\n\t                        width : 1\r\n\t                    }\r\n\t                }\r\n\t            },\r\n\t            legend: {\r\n\t                data:['女性','男性']\r\n\t            },\r\n\t            grid:{\r\n\t                x:45,\r\n\t                x2:40,\r\n\t                y2:24\r\n\t            },\r\n\t            xAxis : [\r\n\t                {\r\n\t                    type : 'value',\r\n\t                    scale:true,\r\n\t                    axisLabel : {\r\n\t                        formatter: '{value} cm'\r\n\t                    }\r\n\t                }\r\n\t            ],\r\n\t            yAxis : [\r\n\t                {\r\n\t                    type : 'value',\r\n\t                    scale:true,\r\n\t                    axisLabel : {\r\n\t                        formatter: '{value} kg'\r\n\t                    }\r\n\t                }\r\n\t            ],\r\n\t            series : [\r\n\t                {\r\n\t                    name:'女性',\r\n\t                    type:'scatter',\r\n\t                    tooltip : {\r\n\t                        trigger: 'item',\r\n\t                        formatter : function (params) {\r\n\t                            if (params.value.length > 1) {\r\n\t                                return params.seriesName + ' :<br/>'\r\n\t                                   + params.value[0] + 'cm '\r\n\t                                   + params.value[1] + 'kg ';\r\n\t                            }\r\n\t                            else {\r\n\t                                return params.seriesName + ' :<br/>'\r\n\t                                   + params.name + ' : '\r\n\t                                   + params.value + 'kg ';\r\n\t                            }\r\n\t                        }\r\n\t                    },\r\n\t                    data: [\r\n\t                        [161.2, 51.6], [167.5, 59.0], [159.5, 49.2], [157.0, 63.0], [155.8, 53.6],\r\n\t                        [170.0, 59.0], [159.1, 47.6], [166.0, 69.8], [176.2, 66.8], [160.2, 75.2],\r\n\t                        [172.5, 55.2], [170.9, 54.2], [172.9, 62.5], [153.4, 42.0], [160.0, 50.0],\r\n\t                        [147.2, 49.8], [168.2, 49.2], [175.0, 73.2], [157.0, 47.8], [167.6, 68.8],\r\n\t                        [159.5, 50.6], [175.0, 82.5], [166.8, 57.2], [176.5, 87.8], [170.2, 72.8],\r\n\t                        [174.0, 54.5], [173.0, 59.8], [179.9, 67.3], [170.5, 67.8], [160.0, 47.0],\r\n\t                        [154.4, 46.2], [162.0, 55.0], [176.5, 83.0], [160.0, 54.4], [152.0, 45.8],\r\n\t                        [162.1, 53.6], [170.0, 73.2], [160.2, 52.1], [161.3, 67.9], [166.4, 56.6],\r\n\t                        [168.9, 62.3], [163.8, 58.5], [167.6, 54.5], [160.0, 50.2], [161.3, 60.3],\r\n\t                        [167.6, 58.3], [165.1, 56.2], [160.0, 50.2], [170.0, 72.9], [157.5, 59.8],\r\n\t                        [167.6, 61.0], [160.7, 69.1], [163.2, 55.9], [152.4, 46.5], [157.5, 54.3],\r\n\t                        [168.3, 54.8], [180.3, 60.7], [165.5, 60.0], [165.0, 62.0], [164.5, 60.3],\r\n\t                        [156.0, 52.7], [160.0, 74.3], [163.0, 62.0], [165.7, 73.1], [161.0, 80.0],\r\n\t                        [162.0, 54.7], [166.0, 53.2], [174.0, 75.7], [172.7, 61.1], [167.6, 55.7],\r\n\t                        [151.1, 48.7], [164.5, 52.3], [163.5, 50.0], [152.0, 59.3], [169.0, 62.5],\r\n\t                        [164.0, 55.7], [161.2, 54.8], [155.0, 45.9], [170.0, 70.6], [176.2, 67.2],\r\n\t                        [170.0, 69.4], [162.5, 58.2], [170.3, 64.8], [164.1, 71.6], [169.5, 52.8],\r\n\t                        [163.2, 59.8], [154.5, 49.0], [159.8, 50.0], [173.2, 69.2], [170.0, 55.9],\r\n\t                        [161.4, 63.4], [169.0, 58.2], [166.2, 58.6], [159.4, 45.7], [162.5, 52.2],\r\n\t                        [159.0, 48.6], [162.8, 57.8], [159.0, 55.6], [179.8, 66.8], [162.9, 59.4],\r\n\t                        [161.0, 53.6], [151.1, 73.2], [168.2, 53.4], [168.9, 69.0], [173.2, 58.4],\r\n\t                        [171.8, 56.2], [178.0, 70.6], [164.3, 59.8], [163.0, 72.0], [168.5, 65.2],\r\n\t                        [166.8, 56.6], [172.7, 105.2], [163.5, 51.8], [169.4, 63.4], [167.8, 59.0],\r\n\t                        [159.5, 47.6], [167.6, 63.0], [161.2, 55.2], [160.0, 45.0], [163.2, 54.0],\r\n\t                        [162.2, 50.2], [161.3, 60.2], [149.5, 44.8], [157.5, 58.8], [163.2, 56.4],\r\n\t                        [172.7, 62.0], [155.0, 49.2], [156.5, 67.2], [164.0, 53.8], [160.9, 54.4],\r\n\t                        [162.8, 58.0], [167.0, 59.8], [160.0, 54.8], [160.0, 43.2], [168.9, 60.5],\r\n\t                        [158.2, 46.4], [156.0, 64.4], [160.0, 48.8], [167.1, 62.2], [158.0, 55.5],\r\n\t                        [167.6, 57.8], [156.0, 54.6], [162.1, 59.2], [173.4, 52.7], [159.8, 53.2],\r\n\t                        [170.5, 64.5], [159.2, 51.8], [157.5, 56.0], [161.3, 63.6], [162.6, 63.2],\r\n\t                        [160.0, 59.5], [168.9, 56.8], [165.1, 64.1], [162.6, 50.0], [165.1, 72.3],\r\n\t                        [166.4, 55.0], [160.0, 55.9], [152.4, 60.4], [170.2, 69.1], [162.6, 84.5],\r\n\t                        [170.2, 55.9], [158.8, 55.5], [172.7, 69.5], [167.6, 76.4], [162.6, 61.4],\r\n\t                        [167.6, 65.9], [156.2, 58.6], [175.2, 66.8], [172.1, 56.6], [162.6, 58.6],\r\n\t                        [160.0, 55.9], [165.1, 59.1], [182.9, 81.8], [166.4, 70.7], [165.1, 56.8],\r\n\t                        [177.8, 60.0], [165.1, 58.2], [175.3, 72.7], [154.9, 54.1], [158.8, 49.1],\r\n\t                        [172.7, 75.9], [168.9, 55.0], [161.3, 57.3], [167.6, 55.0], [165.1, 65.5],\r\n\t                        [175.3, 65.5], [157.5, 48.6], [163.8, 58.6], [167.6, 63.6], [165.1, 55.2],\r\n\t                        [165.1, 62.7], [168.9, 56.6], [162.6, 53.9], [164.5, 63.2], [176.5, 73.6],\r\n\t                        [168.9, 62.0], [175.3, 63.6], [159.4, 53.2], [160.0, 53.4], [170.2, 55.0],\r\n\t                        [162.6, 70.5], [167.6, 54.5], [162.6, 54.5], [160.7, 55.9], [160.0, 59.0],\r\n\t                        [157.5, 63.6], [162.6, 54.5], [152.4, 47.3], [170.2, 67.7], [165.1, 80.9],\r\n\t                        [172.7, 70.5], [165.1, 60.9], [170.2, 63.6], [170.2, 54.5], [170.2, 59.1],\r\n\t                        [161.3, 70.5], [167.6, 52.7], [167.6, 62.7], [165.1, 86.3], [162.6, 66.4],\r\n\t                        [152.4, 67.3], [168.9, 63.0], [170.2, 73.6], [175.2, 62.3], [175.2, 57.7],\r\n\t                        [160.0, 55.4], [165.1, 104.1], [174.0, 55.5], [170.2, 77.3], [160.0, 80.5],\r\n\t                        [167.6, 64.5], [167.6, 72.3], [167.6, 61.4], [154.9, 58.2], [162.6, 81.8],\r\n\t                        [175.3, 63.6], [171.4, 53.4], [157.5, 54.5], [165.1, 53.6], [160.0, 60.0],\r\n\t                        [174.0, 73.6], [162.6, 61.4], [174.0, 55.5], [162.6, 63.6], [161.3, 60.9],\r\n\t                        [156.2, 60.0], [149.9, 46.8], [169.5, 57.3], [160.0, 64.1], [175.3, 63.6],\r\n\t                        [169.5, 67.3], [160.0, 75.5], [172.7, 68.2], [162.6, 61.4], [157.5, 76.8],\r\n\t                        [176.5, 71.8], [164.4, 55.5], [160.7, 48.6], [174.0, 66.4], [163.8, 67.3]\r\n\t                    ],\r\n\t                    markPoint : {\r\n\t                        data : [\r\n\t                            {type : 'max', name: '最大值'},\r\n\t                            {type : 'min', name: '最小值'}\r\n\t                        ]\r\n\t                    },\r\n\t                    markLine : {\r\n\t                        data : [\r\n\t                            {type : 'average', name: '平均值'}\r\n\t                        ]\r\n\t                    }\r\n\t                },\r\n\t                {\r\n\t                    name:'男性',\r\n\t                    type:'scatter',\r\n\t                    tooltip : {\r\n\t                        trigger: 'item',\r\n\t                        formatter : function (params) {\r\n\t                            if (params.value.length > 1) {\r\n\t                                return params.seriesName + ' :<br/>'\r\n\t                                   + params.value[0] + 'cm '\r\n\t                                   + params.value[1] + 'kg ';\r\n\t                            }\r\n\t                            else {\r\n\t                                return params.seriesName + ' :<br/>'\r\n\t                                   + params.name + ' : '\r\n\t                                   + params.value + 'kg ';\r\n\t                            }\r\n\t                        }\r\n\t                    },\r\n\t                    data: [\r\n\t                        [174.0, 65.6], [175.3, 71.8], [193.5, 80.7], [186.5, 72.6], [187.2, 78.8],\r\n\t                        [181.5, 74.8], [184.0, 86.4], [184.5, 78.4], [175.0, 62.0], [184.0, 81.6],\r\n\t                        [180.0, 76.6], [177.8, 83.6], [192.0, 90.0], [176.0, 74.6], [174.0, 71.0],\r\n\t                        [184.0, 79.6], [192.7, 93.8], [171.5, 70.0], [173.0, 72.4], [176.0, 85.9],\r\n\t                        [176.0, 78.8], [180.5, 77.8], [172.7, 66.2], [176.0, 86.4], [173.5, 81.8],\r\n\t                        [178.0, 89.6], [180.3, 82.8], [180.3, 76.4], [164.5, 63.2], [173.0, 60.9],\r\n\t                        [183.5, 74.8], [175.5, 70.0], [188.0, 72.4], [189.2, 84.1], [172.8, 69.1],\r\n\t                        [170.0, 59.5], [182.0, 67.2], [170.0, 61.3], [177.8, 68.6], [184.2, 80.1],\r\n\t                        [186.7, 87.8], [171.4, 84.7], [172.7, 73.4], [175.3, 72.1], [180.3, 82.6],\r\n\t                        [182.9, 88.7], [188.0, 84.1], [177.2, 94.1], [172.1, 74.9], [167.0, 59.1],\r\n\t                        [169.5, 75.6], [174.0, 86.2], [172.7, 75.3], [182.2, 87.1], [164.1, 55.2],\r\n\t                        [163.0, 57.0], [171.5, 61.4], [184.2, 76.8], [174.0, 86.8], [174.0, 72.2],\r\n\t                        [177.0, 71.6], [186.0, 84.8], [167.0, 68.2], [171.8, 66.1], [182.0, 72.0],\r\n\t                        [167.0, 64.6], [177.8, 74.8], [164.5, 70.0], [192.0, 101.6], [175.5, 63.2],\r\n\t                        [171.2, 79.1], [181.6, 78.9], [167.4, 67.7], [181.1, 66.0], [177.0, 68.2],\r\n\t                        [174.5, 63.9], [177.5, 72.0], [170.5, 56.8], [182.4, 74.5], [197.1, 90.9],\r\n\t                        [180.1, 93.0], [175.5, 80.9], [180.6, 72.7], [184.4, 68.0], [175.5, 70.9],\r\n\t                        [180.6, 72.5], [177.0, 72.5], [177.1, 83.4], [181.6, 75.5], [176.5, 73.0],\r\n\t                        [175.0, 70.2], [174.0, 73.4], [165.1, 70.5], [177.0, 68.9], [192.0, 102.3],\r\n\t                        [176.5, 68.4], [169.4, 65.9], [182.1, 75.7], [179.8, 84.5], [175.3, 87.7],\r\n\t                        [184.9, 86.4], [177.3, 73.2], [167.4, 53.9], [178.1, 72.0], [168.9, 55.5],\r\n\t                        [157.2, 58.4], [180.3, 83.2], [170.2, 72.7], [177.8, 64.1], [172.7, 72.3],\r\n\t                        [165.1, 65.0], [186.7, 86.4], [165.1, 65.0], [174.0, 88.6], [175.3, 84.1],\r\n\t                        [185.4, 66.8], [177.8, 75.5], [180.3, 93.2], [180.3, 82.7], [177.8, 58.0],\r\n\t                        [177.8, 79.5], [177.8, 78.6], [177.8, 71.8], [177.8, 116.4], [163.8, 72.2],\r\n\t                        [188.0, 83.6], [198.1, 85.5], [175.3, 90.9], [166.4, 85.9], [190.5, 89.1],\r\n\t                        [166.4, 75.0], [177.8, 77.7], [179.7, 86.4], [172.7, 90.9], [190.5, 73.6],\r\n\t                        [185.4, 76.4], [168.9, 69.1], [167.6, 84.5], [175.3, 64.5], [170.2, 69.1],\r\n\t                        [190.5, 108.6], [177.8, 86.4], [190.5, 80.9], [177.8, 87.7], [184.2, 94.5],\r\n\t                        [176.5, 80.2], [177.8, 72.0], [180.3, 71.4], [171.4, 72.7], [172.7, 84.1],\r\n\t                        [172.7, 76.8], [177.8, 63.6], [177.8, 80.9], [182.9, 80.9], [170.2, 85.5],\r\n\t                        [167.6, 68.6], [175.3, 67.7], [165.1, 66.4], [185.4, 102.3], [181.6, 70.5],\r\n\t                        [172.7, 95.9], [190.5, 84.1], [179.1, 87.3], [175.3, 71.8], [170.2, 65.9],\r\n\t                        [193.0, 95.9], [171.4, 91.4], [177.8, 81.8], [177.8, 96.8], [167.6, 69.1],\r\n\t                        [167.6, 82.7], [180.3, 75.5], [182.9, 79.5], [176.5, 73.6], [186.7, 91.8],\r\n\t                        [188.0, 84.1], [188.0, 85.9], [177.8, 81.8], [174.0, 82.5], [177.8, 80.5],\r\n\t                        [171.4, 70.0], [185.4, 81.8], [185.4, 84.1], [188.0, 90.5], [188.0, 91.4],\r\n\t                        [182.9, 89.1], [176.5, 85.0], [175.3, 69.1], [175.3, 73.6], [188.0, 80.5],\r\n\t                        [188.0, 82.7], [175.3, 86.4], [170.5, 67.7], [179.1, 92.7], [177.8, 93.6],\r\n\t                        [175.3, 70.9], [182.9, 75.0], [170.8, 93.2], [188.0, 93.2], [180.3, 77.7],\r\n\t                        [177.8, 61.4], [185.4, 94.1], [168.9, 75.0], [185.4, 83.6], [180.3, 85.5],\r\n\t                        [174.0, 73.9], [167.6, 66.8], [182.9, 87.3], [160.0, 72.3], [180.3, 88.6],\r\n\t                        [167.6, 75.5], [186.7, 101.4], [175.3, 91.1], [175.3, 67.3], [175.9, 77.7],\r\n\t                        [175.3, 81.8], [179.1, 75.5], [181.6, 84.5], [177.8, 76.6], [182.9, 85.0],\r\n\t                        [177.8, 102.5], [184.2, 77.3], [179.1, 71.8], [176.5, 87.9], [188.0, 94.3],\r\n\t                        [174.0, 70.9], [167.6, 64.5], [170.2, 77.3], [167.6, 72.3], [188.0, 87.3],\r\n\t                        [174.0, 80.0], [176.5, 82.3], [180.3, 73.6], [167.6, 74.1], [188.0, 85.9],\r\n\t                        [180.3, 73.2], [167.6, 76.3], [183.0, 65.9], [183.0, 90.9], [179.1, 89.1],\r\n\t                        [170.2, 62.3], [177.8, 82.7], [179.1, 79.1], [190.5, 98.2], [177.8, 84.1],\r\n\t                        [180.3, 83.2], [180.3, 83.2]\r\n\t                    ],\r\n\t                    markPoint : {\r\n\t                        data : [\r\n\t                            {type : 'max', name: '最大值'},\r\n\t                            {type : 'min', name: '最小值'}\r\n\t                        ]\r\n\t                    },\r\n\t                    markLine : {\r\n\t                        data : [\r\n\t                            {type : 'average', name: '平均值'}\r\n\t                        ]\r\n\t                    }\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t        scatterChart.setOption(scatteroption);\r\n\t        $(window).resize(scatterChart.resize);\r\n\t\r\n\t\r\n\t        var kChart = echarts.init(document.getElementById(\"echarts-k-chart\"));\r\n\t        var koption = {\r\n\t            title : {\r\n\t                text: '2013年上半年上证指数'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'axis',\r\n\t                formatter: function (params) {\r\n\t                    var res = params[0].seriesName + ' ' + params[0].name;\r\n\t                    res += '<br/>  开盘 : ' + params[0].value[0] + '  最高 : ' + params[0].value[3];\r\n\t                    res += '<br/>  收盘 : ' + params[0].value[1] + '  最低 : ' + params[0].value[2];\r\n\t                    return res;\r\n\t                }\r\n\t            },\r\n\t            legend: {\r\n\t                data:['上证指数']\r\n\t            },\r\n\t            grid:{\r\n\t                x:40,\r\n\t                x2:2\r\n\t            },\r\n\t            dataZoom : {\r\n\t                show : true,\r\n\t                realtime: true,\r\n\t                start : 50,\r\n\t                end : 100\r\n\t            },\r\n\t            xAxis : [\r\n\t                {\r\n\t                    type : 'category',\r\n\t                    boundaryGap : true,\r\n\t                    axisTick: {onGap:false},\r\n\t                    splitLine: {show:false},\r\n\t                    data : [\r\n\t                        \"2013/1/24\", \"2013/1/25\", \"2013/1/28\", \"2013/1/29\", \"2013/1/30\",\r\n\t                        \"2013/1/31\", \"2013/2/1\", \"2013/2/4\", \"2013/2/5\", \"2013/2/6\",\r\n\t                        \"2013/2/7\", \"2013/2/8\", \"2013/2/18\", \"2013/2/19\", \"2013/2/20\",\r\n\t                        \"2013/2/21\", \"2013/2/22\", \"2013/2/25\", \"2013/2/26\", \"2013/2/27\",\r\n\t                        \"2013/2/28\", \"2013/3/1\", \"2013/3/4\", \"2013/3/5\", \"2013/3/6\",\r\n\t                        \"2013/3/7\", \"2013/3/8\", \"2013/3/11\", \"2013/3/12\", \"2013/3/13\",\r\n\t                        \"2013/3/14\", \"2013/3/15\", \"2013/3/18\", \"2013/3/19\", \"2013/3/20\",\r\n\t                        \"2013/3/21\", \"2013/3/22\", \"2013/3/25\", \"2013/3/26\", \"2013/3/27\",\r\n\t                        \"2013/3/28\", \"2013/3/29\", \"2013/4/1\", \"2013/4/2\", \"2013/4/3\",\r\n\t                        \"2013/4/8\", \"2013/4/9\", \"2013/4/10\", \"2013/4/11\", \"2013/4/12\",\r\n\t                        \"2013/4/15\", \"2013/4/16\", \"2013/4/17\", \"2013/4/18\", \"2013/4/19\",\r\n\t                        \"2013/4/22\", \"2013/4/23\", \"2013/4/24\", \"2013/4/25\", \"2013/4/26\",\r\n\t                        \"2013/5/2\", \"2013/5/3\", \"2013/5/6\", \"2013/5/7\", \"2013/5/8\",\r\n\t                        \"2013/5/9\", \"2013/5/10\", \"2013/5/13\", \"2013/5/14\", \"2013/5/15\",\r\n\t                        \"2013/5/16\", \"2013/5/17\", \"2013/5/20\", \"2013/5/21\", \"2013/5/22\",\r\n\t                        \"2013/5/23\", \"2013/5/24\", \"2013/5/27\", \"2013/5/28\", \"2013/5/29\",\r\n\t                        \"2013/5/30\", \"2013/5/31\", \"2013/6/3\", \"2013/6/4\", \"2013/6/5\",\r\n\t                        \"2013/6/6\", \"2013/6/7\", \"2013/6/13\"\r\n\t                    ]\r\n\t                }\r\n\t            ],\r\n\t            yAxis : [\r\n\t                {\r\n\t                    type : 'value',\r\n\t                    scale:true,\r\n\t                    boundaryGap: [0.01, 0.01]\r\n\t                }\r\n\t            ],\r\n\t            series : [\r\n\t                {\r\n\t                    name:'上证指数',\r\n\t                    type:'k',\r\n\t                    data:[ // 开盘，收盘，最低，最高\r\n\t                        [2320.26,2302.6,2287.3,2362.94],\r\n\t                        [2300,2291.3,2288.26,2308.38],\r\n\t                        [2295.35,2346.5,2295.35,2346.92],\r\n\t                        [2347.22,2358.98,2337.35,2363.8],\r\n\t                        [2360.75,2382.48,2347.89,2383.76],\r\n\t                        [2383.43,2385.42,2371.23,2391.82],\r\n\t                        [2377.41,2419.02,2369.57,2421.15],\r\n\t                        [2425.92,2428.15,2417.58,2440.38],\r\n\t                        [2411,2433.13,2403.3,2437.42],\r\n\t                        [2432.68,2434.48,2427.7,2441.73],\r\n\t                        [2430.69,2418.53,2394.22,2433.89],\r\n\t                        [2416.62,2432.4,2414.4,2443.03],\r\n\t                        [2441.91,2421.56,2415.43,2444.8],\r\n\t                        [2420.26,2382.91,2373.53,2427.07],\r\n\t                        [2383.49,2397.18,2370.61,2397.94],\r\n\t                        [2378.82,2325.95,2309.17,2378.82],\r\n\t                        [2322.94,2314.16,2308.76,2330.88],\r\n\t                        [2320.62,2325.82,2315.01,2338.78],\r\n\t                        [2313.74,2293.34,2289.89,2340.71],\r\n\t                        [2297.77,2313.22,2292.03,2324.63],\r\n\t                        [2322.32,2365.59,2308.92,2366.16],\r\n\t                        [2364.54,2359.51,2330.86,2369.65],\r\n\t                        [2332.08,2273.4,2259.25,2333.54],\r\n\t                        [2274.81,2326.31,2270.1,2328.14],\r\n\t                        [2333.61,2347.18,2321.6,2351.44],\r\n\t                        [2340.44,2324.29,2304.27,2352.02],\r\n\t                        [2326.42,2318.61,2314.59,2333.67],\r\n\t                        [2314.68,2310.59,2296.58,2320.96],\r\n\t                        [2309.16,2286.6,2264.83,2333.29],\r\n\t                        [2282.17,2263.97,2253.25,2286.33],\r\n\t                        [2255.77,2270.28,2253.31,2276.22],\r\n\t                        [2269.31,2278.4,2250,2312.08],\r\n\t                        [2267.29,2240.02,2239.21,2276.05],\r\n\t                        [2244.26,2257.43,2232.02,2261.31],\r\n\t                        [2257.74,2317.37,2257.42,2317.86],\r\n\t                        [2318.21,2324.24,2311.6,2330.81],\r\n\t                        [2321.4,2328.28,2314.97,2332],\r\n\t                        [2334.74,2326.72,2319.91,2344.89],\r\n\t                        [2318.58,2297.67,2281.12,2319.99],\r\n\t                        [2299.38,2301.26,2289,2323.48],\r\n\t                        [2273.55,2236.3,2232.91,2273.55],\r\n\t                        [2238.49,2236.62,2228.81,2246.87],\r\n\t                        [2229.46,2234.4,2227.31,2243.95],\r\n\t                        [2234.9,2227.74,2220.44,2253.42],\r\n\t                        [2232.69,2225.29,2217.25,2241.34],\r\n\t                        [2196.24,2211.59,2180.67,2212.59],\r\n\t                        [2215.47,2225.77,2215.47,2234.73],\r\n\t                        [2224.93,2226.13,2212.56,2233.04],\r\n\t                        [2236.98,2219.55,2217.26,2242.48],\r\n\t                        [2218.09,2206.78,2204.44,2226.26],\r\n\t                        [2199.91,2181.94,2177.39,2204.99],\r\n\t                        [2169.63,2194.85,2165.78,2196.43],\r\n\t                        [2195.03,2193.8,2178.47,2197.51],\r\n\t                        [2181.82,2197.6,2175.44,2206.03],\r\n\t                        [2201.12,2244.64,2200.58,2250.11],\r\n\t                        [2236.4,2242.17,2232.26,2245.12],\r\n\t                        [2242.62,2184.54,2182.81,2242.62],\r\n\t                        [2187.35,2218.32,2184.11,2226.12],\r\n\t                        [2213.19,2199.31,2191.85,2224.63],\r\n\t                        [2203.89,2177.91,2173.86,2210.58],\r\n\t                        [2170.78,2174.12,2161.14,2179.65],\r\n\t                        [2179.05,2205.5,2179.05,2222.81],\r\n\t                        [2212.5,2231.17,2212.5,2236.07],\r\n\t                        [2227.86,2235.57,2219.44,2240.26],\r\n\t                        [2242.39,2246.3,2235.42,2255.21],\r\n\t                        [2246.96,2232.97,2221.38,2247.86],\r\n\t                        [2228.82,2246.83,2225.81,2247.67],\r\n\t                        [2247.68,2241.92,2231.36,2250.85],\r\n\t                        [2238.9,2217.01,2205.87,2239.93],\r\n\t                        [2217.09,2224.8,2213.58,2225.19],\r\n\t                        [2221.34,2251.81,2210.77,2252.87],\r\n\t                        [2249.81,2282.87,2248.41,2288.09],\r\n\t                        [2286.33,2299.99,2281.9,2309.39],\r\n\t                        [2297.11,2305.11,2290.12,2305.3],\r\n\t                        [2303.75,2302.4,2292.43,2314.18],\r\n\t                        [2293.81,2275.67,2274.1,2304.95],\r\n\t                        [2281.45,2288.53,2270.25,2292.59],\r\n\t                        [2286.66,2293.08,2283.94,2301.7],\r\n\t                        [2293.4,2321.32,2281.47,2322.1],\r\n\t                        [2323.54,2324.02,2321.17,2334.33],\r\n\t                        [2316.25,2317.75,2310.49,2325.72],\r\n\t                        [2320.74,2300.59,2299.37,2325.53],\r\n\t                        [2300.21,2299.25,2294.11,2313.43],\r\n\t                        [2297.1,2272.42,2264.76,2297.1],\r\n\t                        [2270.71,2270.93,2260.87,2276.86],\r\n\t                        [2264.43,2242.11,2240.07,2266.69],\r\n\t                        [2242.26,2210.9,2205.07,2250.63],\r\n\t                        [2190.1,2148.35,2126.22,2190.1]\r\n\t                    ]\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t        kChart.setOption(koption);\r\n\t        $(window).resize(kChart.resize);\r\n\t\r\n\t        var pieChart = echarts.init(document.getElementById(\"echarts-pie-chart\"));\r\n\t        var pieoption = {\r\n\t            title : {\r\n\t                text: '某站点用户访问来源',\r\n\t                subtext: '纯属虚构',\r\n\t                x:'center'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'item',\r\n\t                formatter: \"{a} <br/>{b} : {c} ({d}%)\"\r\n\t            },\r\n\t            legend: {\r\n\t                orient : 'vertical',\r\n\t                x : 'left',\r\n\t                data:['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']\r\n\t            },\r\n\t            calculable : true,\r\n\t            series : [\r\n\t                {\r\n\t                    name:'访问来源',\r\n\t                    type:'pie',\r\n\t                    radius : '55%',\r\n\t                    center: ['50%', '60%'],\r\n\t                    data:[\r\n\t                        {value:335, name:'直接访问'},\r\n\t                        {value:310, name:'邮件营销'},\r\n\t                        {value:234, name:'联盟广告'},\r\n\t                        {value:135, name:'视频广告'},\r\n\t                        {value:1548, name:'搜索引擎'}\r\n\t                    ]\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t        pieChart.setOption(pieoption);\r\n\t        $(window).resize(pieChart.resize);\r\n\t\r\n\t        var radarChart = echarts.init(document.getElementById(\"echarts-radar-chart\"));\r\n\t        var radaroption = {\r\n\t            title : {\r\n\t                text: '预算 vs 开销',\r\n\t                subtext: '纯属虚构'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'axis'\r\n\t            },\r\n\t            legend: {\r\n\t                orient : 'vertical',\r\n\t                x : 'right',\r\n\t                y : 'bottom',\r\n\t                data:['预算分配','实际开销']\r\n\t            },\r\n\t            polar : [\r\n\t               {\r\n\t                   indicator : [\r\n\t                       { text: '销售', max: 6000},\r\n\t                       { text: '管理', max: 16000},\r\n\t                       { text: '信息技术', max: 30000},\r\n\t                       { text: '客服', max: 38000},\r\n\t                       { text: '研发', max: 52000},\r\n\t                       { text: '市场', max: 25000}\r\n\t                    ]\r\n\t                }\r\n\t            ],\r\n\t            calculable : true,\r\n\t            series : [\r\n\t                {\r\n\t                    name: '预算 vs 开销',\r\n\t                    type: 'radar',\r\n\t                    data : [\r\n\t                        {\r\n\t                            value : [4300, 10000, 28000, 35000, 50000, 19000],\r\n\t                            name : '预算分配'\r\n\t                        },\r\n\t                         {\r\n\t                            value : [5000, 14000, 28000, 31000, 42000, 21000],\r\n\t                            name : '实际开销'\r\n\t                        }\r\n\t                    ]\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t\r\n\t        radarChart.setOption(radaroption);\r\n\t        $(window).resize(radarChart.resize);\r\n\t\r\n\t        var mapChart = echarts.init(document.getElementById(\"echarts-map-chart\"));\r\n\t        var mapoption = {\r\n\t            title : {\r\n\t                text: 'iphone销量',\r\n\t                subtext: '纯属虚构',\r\n\t                x:'center'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'item'\r\n\t            },\r\n\t            legend: {\r\n\t                orient: 'vertical',\r\n\t                x:'left',\r\n\t                data:['iphone3','iphone4','iphone5']\r\n\t            },\r\n\t            dataRange: {\r\n\t                min: 0,\r\n\t                max: 2500,\r\n\t                x: 'left',\r\n\t                y: 'bottom',\r\n\t                text:['高','低'],           // 文本，默认为数值文本\r\n\t                calculable : true\r\n\t            },\r\n\t            toolbox: {\r\n\t                show: true,\r\n\t                orient : 'vertical',\r\n\t                x: 'right',\r\n\t                y: 'center',\r\n\t                feature : {\r\n\t                    mark : {show: true},\r\n\t                    dataView : {show: true, readOnly: false},\r\n\t                    restore : {show: true},\r\n\t                    saveAsImage : {show: true}\r\n\t                }\r\n\t            },\r\n\t            roamController: {\r\n\t                show: true,\r\n\t                x: 'right',\r\n\t                mapTypeControl: {\r\n\t                    'china': true\r\n\t                }\r\n\t            },\r\n\t            series : [\r\n\t                {\r\n\t                    name: 'iphone3',\r\n\t                    type: 'map',\r\n\t                    mapType: 'china',\r\n\t                    roam: false,\r\n\t                    itemStyle:{\r\n\t                        normal:{label:{show:true}},\r\n\t                        emphasis:{label:{show:true}}\r\n\t                    },\r\n\t                    data:[\r\n\t                        {name: '北京',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '天津',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '上海',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '重庆',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '河北',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '河南',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '云南',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '辽宁',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '黑龙江',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '湖南',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '安徽',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '山东',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '新疆',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '江苏',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '浙江',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '江西',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '湖北',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '广西',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '甘肃',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '山西',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '内蒙古',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '陕西',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '吉林',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '福建',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '贵州',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '广东',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '青海',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '西藏',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '四川',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '宁夏',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '海南',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '台湾',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '香港',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '澳门',value: Math.round(Math.random()*1000)}\r\n\t                    ]\r\n\t                },\r\n\t                {\r\n\t                    name: 'iphone4',\r\n\t                    type: 'map',\r\n\t                    mapType: 'china',\r\n\t                    itemStyle:{\r\n\t                        normal:{label:{show:true}},\r\n\t                        emphasis:{label:{show:true}}\r\n\t                    },\r\n\t                    data:[\r\n\t                        {name: '北京',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '天津',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '上海',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '重庆',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '河北',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '安徽',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '新疆',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '浙江',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '江西',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '山西',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '内蒙古',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '吉林',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '福建',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '广东',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '西藏',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '四川',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '宁夏',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '香港',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '澳门',value: Math.round(Math.random()*1000)}\r\n\t                    ]\r\n\t                },\r\n\t                {\r\n\t                    name: 'iphone5',\r\n\t                    type: 'map',\r\n\t                    mapType: 'china',\r\n\t                    itemStyle:{\r\n\t                        normal:{label:{show:true}},\r\n\t                        emphasis:{label:{show:true}}\r\n\t                    },\r\n\t                    data:[\r\n\t                        {name: '北京',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '天津',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '上海',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '广东',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '台湾',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '香港',value: Math.round(Math.random()*1000)},\r\n\t                        {name: '澳门',value: Math.round(Math.random()*1000)}\r\n\t                    ]\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t        mapChart.setOption(mapoption);\r\n\t        $(window).resize(mapChart.resize);\r\n\t\r\n\t        var gaugeChart = echarts.init(document.getElementById(\"echarts-gauge-chart\"));\r\n\t        var gaugeoption = {\r\n\t            tooltip : {\r\n\t                formatter: \"{a} <br/>{c} {b}\"\r\n\t            },\r\n\t            toolbox: {\r\n\t                show : true,\r\n\t                feature : {\r\n\t                    mark : {show: true},\r\n\t                    restore : {show: true},\r\n\t                    saveAsImage : {show: true}\r\n\t                }\r\n\t            },\r\n\t            series : [\r\n\t                {\r\n\t                    name:'速度',\r\n\t                    type:'gauge',\r\n\t                    min:0,\r\n\t                    max:220,\r\n\t                    splitNumber:11,\r\n\t                    axisLine: {            // 坐标轴线\r\n\t                        lineStyle: {       // 属性lineStyle控制线条样式\r\n\t                            width: 10\r\n\t                        }\r\n\t                    },\r\n\t                    axisTick: {            // 坐标轴小标记\r\n\t                        length :15,        // 属性length控制线长\r\n\t                        lineStyle: {       // 属性lineStyle控制线条样式\r\n\t                            color: 'auto'\r\n\t                        }\r\n\t                    },\r\n\t                    splitLine: {           // 分隔线\r\n\t                        length :20,         // 属性length控制线长\r\n\t                        lineStyle: {       // 属性lineStyle（详见lineStyle）控制线条样式\r\n\t                            color: 'auto'\r\n\t                        }\r\n\t                    },\r\n\t                    title : {\r\n\t                        textStyle: {       // 其余属性默认使用全局文本样式，详见TEXTSTYLE\r\n\t                            fontWeight: 'bolder',\r\n\t                            fontSize: 20,\r\n\t                            fontStyle: 'italic'\r\n\t                        }\r\n\t                    },\r\n\t                    detail : {\r\n\t                        textStyle: {       // 其余属性默认使用全局文本样式，详见TEXTSTYLE\r\n\t                            fontWeight: 'bolder'\r\n\t                        }\r\n\t                    },\r\n\t                    data:[{value: 40, name: 'km/h'}]\r\n\t                },\r\n\t                {\r\n\t                    name:'转速',\r\n\t                    type:'gauge',\r\n\t                    center : ['25%', '55%'],    // 默认全局居中\r\n\t                    radius : '50%',\r\n\t                    min:0,\r\n\t                    max:7,\r\n\t                    endAngle:45,\r\n\t                    splitNumber:7,\r\n\t                    axisLine: {            // 坐标轴线\r\n\t                        lineStyle: {       // 属性lineStyle控制线条样式\r\n\t                            width: 8\r\n\t                        }\r\n\t                    },\r\n\t                    axisTick: {            // 坐标轴小标记\r\n\t                        length :12,        // 属性length控制线长\r\n\t                        lineStyle: {       // 属性lineStyle控制线条样式\r\n\t                            color: 'auto'\r\n\t                        }\r\n\t                    },\r\n\t                    splitLine: {           // 分隔线\r\n\t                        length :20,         // 属性length控制线长\r\n\t                        lineStyle: {       // 属性lineStyle（详见lineStyle）控制线条样式\r\n\t                            color: 'auto'\r\n\t                        }\r\n\t                    },\r\n\t                    pointer: {\r\n\t                        width:5\r\n\t                    },\r\n\t                    title : {\r\n\t                        offsetCenter: [0, '-30%'],       // x, y，单位px\r\n\t                    },\r\n\t                    detail : {\r\n\t                        textStyle: {       // 其余属性默认使用全局文本样式，详见TEXTSTYLE\r\n\t                            fontWeight: 'bolder'\r\n\t                        }\r\n\t                    },\r\n\t                    data:[{value: 1.5, name: 'x1000 r/min'}]\r\n\t                },\r\n\t                {\r\n\t                    name:'油表',\r\n\t                    type:'gauge',\r\n\t                    center : ['75%', '50%'],    // 默认全局居中\r\n\t                    radius : '50%',\r\n\t                    min:0,\r\n\t                    max:2,\r\n\t                    startAngle:135,\r\n\t                    endAngle:45,\r\n\t                    splitNumber:2,\r\n\t                    axisLine: {            // 坐标轴线\r\n\t                        lineStyle: {       // 属性lineStyle控制线条样式\r\n\t                            color: [\r\n\t                                     [0.2, '#ff4500'],[0.8, '#48b'],[1, '#228b22']\r\n\t                                   ],\r\n\t                            width: 8\r\n\t                        }\r\n\t                    },\r\n\t                    axisTick: {            // 坐标轴小标记\r\n\t                        splitNumber:5,\r\n\t                        length :10,        // 属性length控制线长\r\n\t                        lineStyle: {       // 属性lineStyle控制线条样式\r\n\t                            color: 'auto'\r\n\t                        }\r\n\t                    },\r\n\t                    axisLabel: {\r\n\t                        formatter:function(v){\r\n\t                            switch (v + '') {\r\n\t                                case '0' : return 'E';\r\n\t                                case '1' : return 'Gas';\r\n\t                                case '2' : return 'F';\r\n\t                            }\r\n\t                        }\r\n\t                    },\r\n\t                    splitLine: {           // 分隔线\r\n\t                        length :15,         // 属性length控制线长\r\n\t                        lineStyle: {       // 属性lineStyle（详见lineStyle）控制线条样式\r\n\t                            color: 'auto'\r\n\t                        }\r\n\t                    },\r\n\t                    pointer: {\r\n\t                        width:2\r\n\t                    },\r\n\t                    title : {\r\n\t                        show: false\r\n\t                    },\r\n\t                    detail : {\r\n\t                        show: false\r\n\t                    },\r\n\t                    data:[{value: 0.5, name: 'gas'}]\r\n\t                },\r\n\t                {\r\n\t                    name:'水表',\r\n\t                    type:'gauge',\r\n\t                    center : ['75%', '50%'],    // 默认全局居中\r\n\t                    radius : '50%',\r\n\t                    min:0,\r\n\t                    max:2,\r\n\t                    startAngle:315,\r\n\t                    endAngle:225,\r\n\t                    splitNumber:2,\r\n\t                    axisLine: {            // 坐标轴线\r\n\t                        lineStyle: {       // 属性lineStyle控制线条样式\r\n\t                            color: [\r\n\t                                     [0.2, '#ff4500'],[0.8, '#48b'],[1, '#228b22']\r\n\t                                   ],\r\n\t                            width: 8\r\n\t                        }\r\n\t                    },\r\n\t                    axisTick: {            // 坐标轴小标记\r\n\t                        show: false\r\n\t                    },\r\n\t                    axisLabel: {\r\n\t                        formatter:function(v){\r\n\t                            switch (v + '') {\r\n\t                                case '0' : return 'H';\r\n\t                                case '1' : return 'Water';\r\n\t                                case '2' : return 'C';\r\n\t                            }\r\n\t                        }\r\n\t                    },\r\n\t                    splitLine: {           // 分隔线\r\n\t                        length :15,         // 属性length控制线长\r\n\t                        lineStyle: {       // 属性lineStyle（详见lineStyle）控制线条样式\r\n\t                            color: 'auto'\r\n\t                        }\r\n\t                    },\r\n\t                    pointer: {\r\n\t                        width:2\r\n\t                    },\r\n\t                    title : {\r\n\t                        show: false\r\n\t                    },\r\n\t                    detail : {\r\n\t                        show: false\r\n\t                    },\r\n\t                    data:[{value: 0.5, name: 'gas'}]\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t        gaugeChart.setOption(gaugeoption);\r\n\t        $(window).resize(gaugeChart.resize);\r\n\t\r\n\t        var funnelChart = echarts.init(document.getElementById(\"echarts-funnel-chart\"));\r\n\t        var funneloption = {\r\n\t            title : {\r\n\t                text: '漏斗图',\r\n\t                subtext: '纯属虚构'\r\n\t            },\r\n\t            tooltip : {\r\n\t                trigger: 'item',\r\n\t                formatter: \"{a} <br/>{b} : {c}%\"\r\n\t            },\r\n\t            legend: {\r\n\t                data : ['展现','点击','访问','咨询','订单']\r\n\t            },\r\n\t            calculable : true,\r\n\t            series : [\r\n\t                {\r\n\t                    name:'漏斗图',\r\n\t                    type:'funnel',\r\n\t                    width: '40%',\r\n\t                    data:[\r\n\t                        {value:60, name:'访问'},\r\n\t                        {value:40, name:'咨询'},\r\n\t                        {value:20, name:'订单'},\r\n\t                        {value:80, name:'点击'},\r\n\t                        {value:100, name:'展现'}\r\n\t                    ]\r\n\t                },\r\n\t                {\r\n\t                    name:'金字塔',\r\n\t                    type:'funnel',\r\n\t                    x : '50%',\r\n\t                    sort : 'ascending',\r\n\t                    itemStyle: {\r\n\t                        normal: {\r\n\t                            // color: 各异,\r\n\t                            label: {\r\n\t                                position: 'left'\r\n\t                            }\r\n\t                        }\r\n\t                    },\r\n\t                    data:[\r\n\t                        {value:60, name:'访问'},\r\n\t                        {value:40, name:'咨询'},\r\n\t                        {value:20, name:'订单'},\r\n\t                        {value:80, name:'点击'},\r\n\t                        {value:100, name:'展现'}\r\n\t                    ]\r\n\t                }\r\n\t            ]\r\n\t        };\r\n\t\r\n\t        funnelChart.setOption(funneloption);\r\n\t        $(window).resize(funnelChart.resize);\r\n\t\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/report/metrics.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('图表组合')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5 class=\"m-b-md\">Q1 销量</h5>\r\n                        <h2 class=\"text-navy\">\r\n                                    <i class=\"fa fa-play fa-rotate-270\"></i> 上升\r\n                                </h2>\r\n                        <small>更新时间：12天以前</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content \">\r\n                        <h5 class=\"m-b-md\">Q2 销量</h5>\r\n                        <h2 class=\"text-navy\">\r\n                                    <i class=\"fa fa-play fa-rotate-270\"></i> 上升\r\n                                </h2>\r\n                        <small>更新时间：12天以前</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5 class=\"m-b-md\">Q3 销量</h5>\r\n                        <h2 class=\"text-danger\">\r\n                                    <i class=\"fa fa-play fa-rotate-90\"></i> 下降\r\n                                </h2>\r\n                        <small>更新时间：12天以前</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5 class=\"m-b-md\">Q4 销量</h5>\r\n                        <h2 class=\"text-danger\">\r\n                                    <i class=\"fa fa-play fa-rotate-90\"></i> 下降\r\n                                </h2>\r\n                        <small>更新时间：12天以前</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>本日访问量</h5>\r\n                        <h2>198 009</h2>\r\n                        <div id=\"sparkline1\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>本周访问量</h5>\r\n                        <h2>65 000</h2>\r\n                        <div id=\"sparkline2\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>本月访问量</h5>\r\n                        <h2>680 900</h2>\r\n                        <div id=\"sparkline3\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>平均停留时间</h5>\r\n                        <h2>00:06:40</h2>\r\n                        <div id=\"sparkline4\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>使用率</h5>\r\n                        <h2>65%</h2>\r\n                        <div class=\"progress progress-mini\">\r\n                            <div style=\"width: 68%;\" class=\"progress-bar\"></div>\r\n                        </div>\r\n\r\n                        <div class=\"m-t-sm small\">4:32更新</div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>使用率</h5>\r\n                        <h2>50%</h2>\r\n                        <div class=\"progress progress-mini\">\r\n                            <div style=\"width: 78%;\" class=\"progress-bar\"></div>\r\n                        </div>\r\n\r\n                        <div class=\"m-t-sm small\">4:32更新</div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>使用率</h5>\r\n                        <h2>14%</h2>\r\n                        <div class=\"progress progress-mini\">\r\n                            <div style=\"width: 38%;\" class=\"progress-bar progress-bar-danger\"></div>\r\n                        </div>\r\n\r\n                        <div class=\"m-t-sm small\">4:32更新</div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>使用率</h5>\r\n                        <h2>20%</h2>\r\n                        <div class=\"progress progress-mini\">\r\n                            <div style=\"width: 28%;\" class=\"progress-bar progress-bar-danger\"></div>\r\n                        </div>\r\n\r\n                        <div class=\"m-t-sm small\">4:32更新</div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>百分比</h5>\r\n                        <h2>42/20</h2>\r\n                        <div class=\"text-center\">\r\n                            <div id=\"sparkline5\"></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>百分比</h5>\r\n                        <h2>100/54</h2>\r\n                        <div class=\"text-center\">\r\n                            <div id=\"sparkline6\"></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>百分比</h5>\r\n                        <h2>685/211</h2>\r\n                        <div class=\"text-center\">\r\n                            <div id=\"sparkline7\"></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>百分比</h5>\r\n                        <h2>240/32</h2>\r\n                        <div class=\"text-center\">\r\n                            <div id=\"sparkline8\"></div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>收入</h5>\r\n                        <h1 class=\"no-margins\">886,200</h1>\r\n                        <div class=\"stat-percent font-bold text-navy\">98% <i class=\"fa fa-bolt\"></i></div>\r\n                        <small>总收入</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>本月收入</h5>\r\n                        <h1 class=\"no-margins\">1 738,200</h1>\r\n                        <div class=\"stat-percent font-bold text-navy\">98% <i class=\"fa fa-bolt\"></i></div>\r\n                        <small>总收入</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>本日收入</h5>\r\n                        <h1 class=\"no-margins\">-200,100</h1>\r\n                        <div class=\"stat-percent font-bold text-danger\">12% <i class=\"fa fa-level-down\"></i></div>\r\n                        <small>总收入</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>搜索有收入</h5>\r\n                        <h1 class=\"no-margins\">54,200</h1>\r\n                        <div class=\"stat-percent font-bold text-danger\">24% <i class=\"fa fa-level-down\"></i></div>\r\n                        <small>总收入</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>预警</h5>\r\n                        <table class=\"table table-stripped small m-t-md\">\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td class=\"no-borders\">\r\n                                        <i class=\"fa fa-circle text-navy\"></i>\r\n                                    </td>\r\n                                    <td class=\"no-borders\">\r\n                                        示例 01\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-navy\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 02\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-navy\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 03\r\n                                    </td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>项目</h5>\r\n                        <table class=\"table table-stripped small m-t-md\">\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td class=\"no-borders\">\r\n                                        <i class=\"fa fa-circle text-navy\"></i>\r\n                                    </td>\r\n                                    <td class=\"no-borders\">\r\n                                        示例 01\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-navy\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 02\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-navy\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 03\r\n                                    </td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>消息</h5>\r\n                        <table class=\"table table-stripped small m-t-md\">\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td class=\"no-borders\">\r\n                                        <i class=\"fa fa-circle text-danger\"></i>\r\n                                    </td>\r\n                                    <td class=\"no-borders\">\r\n                                        示例 01\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-danger\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 02\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-danger\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 03\r\n                                    </td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox\">\r\n                    <div class=\"ibox-content\">\r\n                        <h5>通知</h5>\r\n                        <table class=\"table table-stripped small m-t-md\">\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td class=\"no-borders\">\r\n                                        <i class=\"fa fa-circle text-danger\"></i>\r\n                                    </td>\r\n                                    <td class=\"no-borders\">\r\n                                        示例 01\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-danger\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 02\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <i class=\"fa fa-circle text-danger\"></i>\r\n                                    </td>\r\n                                    <td>\r\n                                        示例 03\r\n                                    </td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: peity-js\" />\r\n    <th:block th:include=\"include :: sparkline-js\" />\r\n    <script type=\"text/javascript\">\r\n\t    $(document).ready(function () {\r\n\t        $(\"#sparkline1\").sparkline([34, 43, 43, 35, 44, 32, 44, 52], {\r\n\t            type: 'line',\r\n\t            width: '100%',\r\n\t            height: '60',\r\n\t            lineColor: '#1ab394',\r\n\t            fillColor: \"#ffffff\"\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline2\").sparkline([24, 43, 43, 55, 44, 62, 44, 72], {\r\n\t            type: 'line',\r\n\t            width: '100%',\r\n\t            height: '60',\r\n\t            lineColor: '#1ab394',\r\n\t            fillColor: \"#ffffff\"\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline3\").sparkline([74, 43, 23, 55, 54, 32, 24, 12], {\r\n\t            type: 'line',\r\n\t            width: '100%',\r\n\t            height: '60',\r\n\t            lineColor: '#ed5565',\r\n\t            fillColor: \"#ffffff\"\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline4\").sparkline([24, 43, 33, 55, 64, 72, 44, 22], {\r\n\t            type: 'line',\r\n\t            width: '100%',\r\n\t            height: '60',\r\n\t            lineColor: '#ed5565',\r\n\t            fillColor: \"#ffffff\"\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline5\").sparkline([1, 4], {\r\n\t            type: 'pie',\r\n\t            height: '140',\r\n\t            sliceColors: ['#1ab394', '#F5F5F5']\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline6\").sparkline([5, 3], {\r\n\t            type: 'pie',\r\n\t            height: '140',\r\n\t            sliceColors: ['#1ab394', '#F5F5F5']\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline7\").sparkline([2, 2], {\r\n\t            type: 'pie',\r\n\t            height: '140',\r\n\t            sliceColors: ['#ed5565', '#F5F5F5']\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline8\").sparkline([2, 3], {\r\n\t            type: 'pie',\r\n\t            height: '140',\r\n\t            sliceColors: ['#ed5565', '#F5F5F5']\r\n\t        });\r\n\t    });\r\n\t    \r\n\t    $(function() {\r\n\t        $(\"span.pie\").peity(\"pie\", {\r\n\t            fill: ['#1ab394', '#d7d7d7', '#ffffff']\r\n\t        })\r\n\t\r\n\t        $(\".line\").peity(\"line\",{\r\n\t            fill: '#1ab394',\r\n\t            stroke:'#169c81',\r\n\t        })\r\n\t\r\n\t        $(\".bar\").peity(\"bar\", {\r\n\t            fill: [\"#1ab394\", \"#d7d7d7\"]\r\n\t        })\r\n\t\r\n\t        $(\".bar_dashboard\").peity(\"bar\", {\r\n\t            fill: [\"#1ab394\", \"#d7d7d7\"],\r\n\t            width:100\r\n\t        })\r\n\t\r\n\t        var updatingChart = $(\".updating-chart\").peity(\"line\", { fill: '#1ab394',stroke:'#169c81', width: 64 })\r\n\t\r\n\t        setInterval(function() {\r\n\t            var random = Math.round(Math.random() * 10)\r\n\t            var values = updatingChart.text().split(\",\")\r\n\t            values.shift()\r\n\t            values.push(random)\r\n\t\r\n\t            updatingChart\r\n\t                .text(values.join(\",\"))\r\n\t                .change()\r\n\t        }, 1000);\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/report/peity.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('图表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInDown\">\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-5\">\r\n                <div class=\"jumbotron\">\r\n                    <h1>Peity图表</h1>\r\n                    <p>是一个内嵌数据图形可视化的图表库</p>\r\n                    <p><a href=\"http://benpickles.github.io/peity/\" target=\"_blank\" class=\"btn btn-primary btn-lg\" role=\"button\">了解 Peity</a>\r\n                    </p>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-7\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>饼状图 <small>自定义颜色</small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div>\r\n                        <table class=\"table table-bordered white-bg\">\r\n                            <thead>\r\n                                <tr>\r\n                                    <th>图表</th>\r\n                                    <th>代码</th>\r\n                                </tr>\r\n                            </thead>\r\n\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"pie\">1/5</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"pie\"&gt;1/5&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"pie\">226/360</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"pie\"&gt;226/360&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"pie\">0.52/1.561</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"pie\"&gt;0.52/1.561&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"pie\">1,4</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"pie\"&gt;1,4&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"pie\">226,134</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"pie\"&gt;226,134&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"pie\">0.52,1.041</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"pie\"&gt;0.52,1.041&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>线性图</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div>\r\n                        <table class=\"table table-bordered white-bg\">\r\n                            <thead>\r\n                                <tr>\r\n                                    <th>图表</th>\r\n                                    <th>代码</th>\r\n                                </tr>\r\n                            </thead>\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span data-diameter=\"40\" class=\"updating-chart\">5,3,9,6,5,9,7,3,5,2,5,3,9,6,5,9,7,3,5,2</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"line\"&gt;5,3,9,6,5,9,7,3,5,2&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"line\">5,3,9,6,5,9,7,3,5,2</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"line\"&gt;5,3,9,6,5,9,7,3,5,2&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"line\">5,3,2,-1,-3,-2,2,3,5,2</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"line\"&gt;5,3,2,-1,-3,-2,2,3,5,2&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"line\">0,-3,-6,-4,-5,-4,-7,-3,-5,-2</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"line\"&gt;0,-3,-6,-4,-5,-4,-7,-3,-5,-2&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"bar\">5,3,9,6,5,9,7,3,5,2</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"bar\"&gt;5,3,9,6,5,9,7,3,5,2&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span class=\"bar\">5,3,2,-1,-3,-2,2,3,5,2</span>\r\n                                    </td>\r\n                                    <td>\r\n                                        <code>&lt;span class=\"bar\"&gt;5,3,2,-1,-3,-2,2,3,5,2&lt;/span&gt;</code>\r\n                                    </td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: peity-js\" />\r\n    <script type=\"text/javascript\">\r\n\t    $(function() {\r\n\t        $(\"span.pie\").peity(\"pie\", {\r\n\t            fill: ['#1ab394', '#d7d7d7', '#ffffff']\r\n\t        })\r\n\t\r\n\t        $(\".line\").peity(\"line\",{\r\n\t            fill: '#1ab394',\r\n\t            stroke:'#169c81',\r\n\t        })\r\n\t\r\n\t        $(\".bar\").peity(\"bar\", {\r\n\t            fill: [\"#1ab394\", \"#d7d7d7\"]\r\n\t        })\r\n\t\r\n\t        $(\".bar_dashboard\").peity(\"bar\", {\r\n\t            fill: [\"#1ab394\", \"#d7d7d7\"],\r\n\t            width:100\r\n\t        })\r\n\t\r\n\t        var updatingChart = $(\".updating-chart\").peity(\"line\", { fill: '#1ab394',stroke:'#169c81', width: 64 })\r\n\t\r\n\t        setInterval(function() {\r\n\t            var random = Math.round(Math.random() * 10)\r\n\t            var values = updatingChart.text().split(\",\")\r\n\t            values.shift()\r\n\t            values.push(random)\r\n\t\r\n\t            updatingChart\r\n\t                .text(values.join(\",\"))\r\n\t                .change()\r\n\t        }, 1000);\r\n\t\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/report/sparkline.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('线状图')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInDown\">\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-5\">\r\n                <div class=\"jumbotron\">\r\n                    <h1>Sparkline</h1>\r\n                    <p>这是另一个可视化图表库</p>\r\n                    <p><a href=\"http://omnipotent.net/jquery.sparkline\" target=\"_blank\" class=\"btn btn-primary btn-lg\" role=\"button\">了解 Sparkline</a>\r\n                    </p>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-7\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>Sparkline图表 <small>自定义颜色</small></h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div>\r\n                        <table class=\"table table-bordered white-bg\">\r\n                            <thead>\r\n                                <tr>\r\n                                    <th>图表</th>\r\n                                    <th>类型</th>\r\n                                </tr>\r\n                            </thead>\r\n\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span id=\"sparkline1\"></span>\r\n                                    </td>\r\n                                    <td>\r\n                                        内联线性图\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span id=\"sparkline2\"></span>\r\n                                    </td>\r\n                                    <td>\r\n                                        柱状图\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span id=\"sparkline3\"></span>\r\n                                    </td>\r\n                                    <td>\r\n                                        饼状图\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span id=\"sparkline4\"></span>\r\n                                    </td>\r\n                                    <td>\r\n                                        长线性图\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span id=\"sparkline5\"></span>\r\n                                    </td>\r\n                                    <td>\r\n                                        三态图\r\n                                    </td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td>\r\n                                        <span id=\"sparkline6\"></span>\r\n                                    </td>\r\n                                    <td>\r\n                                        散点图\r\n                                    </td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>自定义饼状图尺寸</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content text-center h-200\">\r\n                        <span id=\"sparkline7\"></span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>自定义柱状图尺寸</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content text-center h-200\">\r\n                        <span id=\"sparkline8\"></span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>自定义线性图尺寸</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">选项1</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">选项2</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content text-center h-200\">\r\n                        <span id=\"sparkline9\"></span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: sparkline-js\" />\r\n    <script type=\"text/javascript\">\r\n\t    $(function () {\r\n\t        $(\"#sparkline1\").sparkline([34, 43, 43, 35, 44, 32, 44, 52, 25], {\r\n\t            type: 'line',\r\n\t            lineColor: '#17997f',\r\n\t            fillColor: '#1ab394',\r\n\t        });\r\n\t        $(\"#sparkline2\").sparkline([5, 6, 7, 2, 0, -4, -2, 4], {\r\n\t            type: 'bar',\r\n\t            barColor: '#1ab394',\r\n\t            negBarColor: '#c6c6c6'});\r\n\t\r\n\t        $(\"#sparkline3\").sparkline([1, 1, 2], {\r\n\t            type: 'pie',\r\n\t            sliceColors: ['#1ab394', '#b3b3b3', '#e4f0fb']});\r\n\t\r\n\t        $(\"#sparkline4\").sparkline([34, 43, 43, 35, 44, 32, 15, 22, 46, 33, 86, 54, 73, 53, 12, 53, 23, 65, 23, 63, 53, 42, 34, 56, 76, 15, 54, 23, 44], {\r\n\t            type: 'line',\r\n\t            lineColor: '#17997f',\r\n\t            fillColor: '#ffffff',\r\n\t        });\r\n\t\r\n\t        $(\"#sparkline5\").sparkline([1, 1, 0, 1, -1, -1, 1, -1, 0, 0, 1, 1], {\r\n\t            type: 'tristate',\r\n\t            posBarColor: '#1ab394',\r\n\t            negBarColor: '#bfbfbf'});\r\n\t\r\n\t\r\n\t        $(\"#sparkline6\").sparkline([4, 6, 7, 7, 4, 3, 2, 1, 4, 4, 5, 6, 3, 4, 5, 8, 7, 6, 9, 3, 2, 4, 1, 5, 6, 4, 3, 7, ], {\r\n\t            type: 'discrete',\r\n\t            lineColor: '#1ab394'});\r\n\t\r\n\t        $(\"#sparkline7\").sparkline([52, 12, 44], {\r\n\t            type: 'pie',\r\n\t            height: '150px',\r\n\t            sliceColors: ['#1ab394', '#b3b3b3', '#e4f0fb']});\r\n\t\r\n\t        $(\"#sparkline8\").sparkline([5, 6, 7, 2, 0, 4, 2, 4, 5, 7, 2, 4, 12, 14, 4, 2, 14, 12, 7], {\r\n\t            type: 'bar',\r\n\t            barWidth: 8,\r\n\t            height: '150px',\r\n\t            barColor: '#1ab394',\r\n\t            negBarColor: '#c6c6c6'});\r\n\t\r\n\t        $(\"#sparkline9\").sparkline([34, 43, 43, 35, 44, 32, 15, 22, 46, 33, 86, 54, 73, 53, 12, 53, 23, 65, 23, 63, 53, 42, 34, 56, 76, 15, 54, 23, 44], {\r\n\t            type: 'line',\r\n\t            lineWidth: 1,\r\n\t            height: '150px',\r\n\t            lineColor: '#17997f',\r\n\t            fillColor: '#ffffff',\r\n\t        });\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/asynTree.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n    <th:block th:include=\"include :: header('异步加载表格树')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12 search-collapse\">\r\n                <form id=\"formId\">\r\n                    <div class=\"select-list\">\r\n                        <ul>\r\n                            <li>\r\n                                <label>区域名称：</label>\r\n                                <input type=\"text\" name=\"areaName\"/>\r\n                            </li>\r\n                            <li>\r\n                                <a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.treeTable.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n                                <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n                            </li>\r\n                        </ul>\r\n                    </div>\r\n                </form>\r\n            </div>\r\n\r\n            <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n                <a class=\"btn btn-info\" id=\"expandAllBtn\">\r\n                    <i class=\"fa fa-exchange\"></i> 展开/折叠\r\n                </a>\r\n            </div>\r\n            <div class=\"col-sm-12 select-table table-striped\">\r\n                <table id=\"bootstrap-tree-table\"></table>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n\r\n        $(function() {\r\n            var options = {\r\n                code: \"id\",\r\n                parentCode: \"parentId\",\r\n                uniqueId: \"id\",\r\n                expandAll: false,\r\n\t\t        expandFirst: false,\r\n\t\t        expandColumn: 1,\r\n                pagination: true,                      // 开启分页\r\n                url: prefix + \"/tree/list\",            // 列表请求\r\n                dataUrl: prefix + \"/tree/listChild\",   // 子节点异步请求\r\n                onClickRow: onClickRow,\r\n                columns: [{\r\n                    field: 'selectItem',\r\n                    radio: true\r\n                },\r\n                {\r\n                    field: 'areaName',\r\n                    title: '区域名称',\r\n                    align: 'left',\r\n                },\r\n                {\r\n                    field: 'areaCode',\r\n                    title: '区域代码',\r\n                    align: 'left'\r\n                },\r\n                {\r\n                    field: 'simplePy',\r\n                    title: '首字母简拼',\r\n                    align: 'left'\r\n                },\r\n                {\r\n                    field: 'pinYin',\r\n                    title: '名称全拼',\r\n                    align: 'left'\r\n                }]\r\n            };\r\n            $.treeTable.init(options);\r\n        });\r\n        \r\n        function onClickRow(row, $element){\r\n//         \talert(\"单击行id：\" + row.id + \" name：\" + row.name);\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/button.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('点击按钮加载表格')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"ordinary-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t用户名称：<input type=\"text\" name=\"userName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"query()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        function query() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/child.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('表格父子视图')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t    <!-- 点击事件的方式打开使用 detailViewIcon: false and detailViewByClick: true\n\t\t\t         data-detail-view-icon=\"false\" \n\t\t\t         data-detail-view-by-click=\"true\" -->\n\t\t\t\t<table id=\"bootstrap-table\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n    <div th:include=\"include :: footer\"></div>\n    <script th:inline=\"javascript\">\n        var prefix = ctx + \"demo/table\";\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\n\n        $(function() {\n            var options = {\n                url: prefix + \"/list\",\n\t\t        showSearch: false,\n\t\t        showRefresh: false,\n\t\t        showToggle: false,\n\t\t        showColumns: false,\n\t\t        detailView: true,\n\t\t\t\tonExpandRow : function(index, row, $detail) {\n\t\t\t\t\tinitChildTable(index, row, $detail);\n\t\t\t\t},\n                columns: [{\n\t\t            checkbox: true\n\t\t        },\n\t\t\t\t{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '用户ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '用户编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '用户姓名'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userPhone', \n\t\t\t\t\ttitle : '用户手机'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userEmail', \n\t\t\t\t\ttitle : '用户邮箱'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t    field : 'userBalance',\n\t\t\t\t    title : '用户余额'\n\t\t\t\t},\n\t\t\t\t{\n                    field: 'status',\n                    title: '用户状态',\n                    align: 'center',\n                    formatter: function(value, row, index) {\n                    \treturn $.table.selectDictLabel(datas, value);\n                    }\n                },\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'center',\n\t\t            formatter: function(value, row, index) {\n\t\t            \tvar actions = [];\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\n\t\t\t\t\t\treturn actions.join('');\n\t\t            }\n\t\t        }]\n            };\n            $.table.init(options);\n        });\n        \n\t\tinitChildTable = function(index, row, $detail) {\n\t\t\tvar childTable = $detail.html('<table style=\"table-layout:fixed\"></table>').find('table');\n    \t    $(childTable).bootstrapTable({\n    \t        url: prefix + \"/list\",\n    \t        method: 'post',\n    \t        sidePagination: \"server\",\n    \t        contentType: \"application/x-www-form-urlencoded\",\n    \t        queryParams : {\n                    userName: '测试8'\n\t\t\t\t},\n    \t        columns: [{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '子表ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '子表编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '子表姓名'\n\t\t\t\t},\n\t\t\t\t{\n                    field: 'status',\n                    title: '子表状态',\n                    align: 'center',\n                    formatter: function(value, row, index) {\n                    \treturn $.table.selectDictLabel(datas, value);\n                    }\n                }]\n    \t    });\n\t\t};\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/cookie.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('表格保存状态')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t\t<table id=\"bootstrap-table\" data-cookie=\"true\" data-cookie-id-table=\"userTableId\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n    <div th:include=\"include :: footer\"></div>\n    <th:block th:include=\"include :: bootstrap-table-cookie-js\" />\n    <script th:inline=\"javascript\">\n        var prefix = ctx + \"demo/table\";\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\n\n        $(function() {\n            var options = {\n                url: prefix + \"/list\",\n                search: true,\n                showSearch: false,\n                showRefresh: false,\n\t\t        showToggle: false,\n                columns: [{\n                \tfield: 'state',\n\t\t            checkbox: true\n\t\t        },\n\t\t\t\t{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '用户ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '用户编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '用户姓名'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userPhone', \n\t\t\t\t\ttitle : '用户手机'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userEmail', \n\t\t\t\t\ttitle : '用户邮箱'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t    field : 'userBalance',\n\t\t\t\t    title : '用户余额'\n\t\t\t\t},\n\t\t\t\t{\n                    field: 'status',\n                    title: '用户状态',\n                    align: 'center',\n                    formatter: function(value, row, index) {\n                    \treturn $.table.selectDictLabel(datas, value);\n                    }\n                },\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'center',\n\t\t            formatter: function(value, row, index) {\n\t\t            \tvar actions = [];\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\n\t\t\t\t\t\treturn actions.join('');\n\t\t            }\n\t\t        }]\n            };\n            $.table.init(options);\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/curd.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('动态增删改查')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\n\t        <a class=\"btn btn-success\" onclick=\"insertRow()\">\n\t            <i class=\"fa fa-plus\"></i> 新增行\n\t        </a>\n\t        <a class=\"btn btn-danger multiple disabled\" onclick=\"removeRow()\">\n\t            <i class=\"fa fa-remove\"></i> 删除选择行\n\t        </a>\n\t        <a class=\"btn btn-danger\" onclick=\"removeRowByUniqueId()\">\n\t            <i class=\"fa fa-remove\"></i> 根据值删除行\n\t        </a>\n\t        <a class=\"btn btn-danger\" onclick=\"removeRowAll()\">\n\t            <i class=\"fa fa-remove\"></i> 删除所有行\n\t        </a>\n\t        <a class=\"btn btn-info\" onclick=\"updateRow()\">\n\t            <i class=\"fa fa-edit\"></i> 修改行\n\t        </a>\n\t        <a class=\"btn btn-info\" onclick=\"updateRowByUniqueId()\">\n\t            <i class=\"fa fa-edit\"></i> 根据值修改行\n\t        </a>\n\t        <a class=\"btn btn-info\" onclick=\"getSelections()\">\n\t            <i class=\"fa fa-search\"></i> 查询选择数据\n\t        </a>\n\t        <a class=\"btn btn-info\" onclick=\"getRowByUniqueId()\">\n\t            <i class=\"fa fa-search\"></i> 根据值查询行\n\t        </a>\n\t        <a class=\"btn btn-primary\" onclick=\"getData()\">\n\t            <i class=\"fa fa-search\"></i> 查询所有数据\n\t        </a>\n        </div>\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t\t<table id=\"bootstrap-table\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n    <div th:include=\"include :: footer\"></div>\n    <script th:inline=\"javascript\">\n        var prefix = ctx + \"demo/table\";\n        \n        $(function() {\n            var options = {\n                url: prefix + \"/list\",\n\t\t        showSearch: false,\n\t\t        showRefresh: false,\n\t\t        showToggle: false,\n\t\t        showColumns: false,\n\t\t        pagination: false,\n\t\t        uniqueId: \"userId\",\n\t\t        height: 400,\n                columns: [{\n\t\t            checkbox: true\n\t\t        },\n\t\t\t\t{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '用户ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '用户编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '用户姓名'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userPhone', \n\t\t\t\t\ttitle : '用户手机'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userEmail', \n\t\t\t\t\ttitle : '用户邮箱'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t    field : 'userBalance',\n\t\t\t\t    title : '用户余额'\n\t\t\t\t}]\n            };\n            $.table.init(options);\n        });\n        \n        /* 新增表格行 */\n        function insertRow(){\n        \tvar randomId = 100 + ~~(Math.random() * 100)\n        \t$(\"#\" + table.options.id).bootstrapTable('insertRow', {\n        \t\tindex: 0, // 你想插入到哪，0表示第一行\n                row: {\n                \tuserId: randomId,\n                \tuserCode: 2000000 + randomId,\n                \tuserName: '测试' + randomId,\n                \tuserPhone: '1588888888',\n                \tuserEmail: 'ry1@qq.com',\n                \tuserBalance: 10 + randomId,\n                }\n        \t})\n        }\n        \n        /* 删除指定表格行 */\n        function removeRow(){\n        \tvar ids = $.table.selectColumns(\"userId\");\n        \tif (ids.length == 0) {\n    \t\t\t$.modal.alertWarning(\"请至少选择一条记录\");\n    \t\t\treturn;\n    \t\t}\n        \t$(\"#\" + table.options.id).bootstrapTable('remove', {\n        \t    field: 'userId',\n        \t    values: ids\n        \t})\n        }\n        \n        /* 删除行ID值为1的数据 */\n        function removeRowByUniqueId(){\n        \t$(\"#\" + table.options.id).bootstrapTable('removeByUniqueId', 1)\n        }\n        \n        /* 删除所有表格行 */\n        function removeRowAll(){\n        \t$(\"#\" + table.options.id).bootstrapTable('removeAll')\n        }\n        \n        /* 修改表格行 */\n        function updateRow(){\n        \tvar randomId = 100 + ~~(Math.random() * 100)\n        \t$(\"#\" + table.options.id).bootstrapTable('updateRow', {\n        \t\tindex: 0, // 你想修改哪行，0表示第一行\n                row: {\n                \tuserId: randomId,\n                \tuserCode: 3000000 + randomId,\n                \tuserName: '测试' + randomId,\n                \tuserPhone: '1599999999',\n                \tuserEmail: 'ry2@qq.com',\n                \tuserBalance: 50 + randomId,\n                }\n        \t})\n        }\n        \n        /* 修改行ID值为1的数据 */\n        function updateRowByUniqueId(){\n        \tvar randomId = 100 + ~~(Math.random() * 100)\n        \t$(\"#\" + table.options.id).bootstrapTable('updateByUniqueId', {\n        \t\tid: 1,\n                row: {\n                \tuserId: randomId,\n                \tuserCode: 3000000 + randomId,\n                \tuserName: '测试' + randomId,\n                \tuserPhone: '1599999999',\n                \tuserEmail: 'ry2@qq.com',\n                \tuserBalance: 50 + randomId,\n                }\n        \t})\n        }\n        \n        /* 查询表格所有数据值 */\n        function getData(){\n        \tvar data = $(\"#\" + table.options.id).bootstrapTable('getData');\n            alert(JSON.stringify(data))\n        }\n        \n        /* 查询行ID值为1的数据 */\n        function getRowByUniqueId(){\n        \tvar data = $(\"#\" + table.options.id).bootstrapTable('getRowByUniqueId', 1);\n            alert(JSON.stringify(data))\n        }\n        \n        /* 查询表格选择行数据值 */\n        function getSelections(){\n        \tvar data = $(\"#\" + table.options.id).bootstrapTable('getSelections');\n        \talert(JSON.stringify(data))\n        }\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/customView.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('自定义视图分页')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t\t<table id=\"bootstrap-table\" data-page-size=\"10\" \n\t\t\t\t       data-show-custom-view=\"true\" data-custom-view=\"customViewFormatter\"\n                       data-custom-view-default-view=\"true\">\n                </table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t\n    <template id=\"profileTemplate\">\n        <div class=\"col-sm-4\">\n            <div class=\"contact-box\">\n                <a href=\"profile.html\">\n                    <div class=\"col-sm-4\">\n                        <div class=\"text-center\">\n                            <img alt=\"image\" class=\"img-circle m-t-xs img-responsive\" src=\"%IMAGE%\">\n                            <div class=\"m-t-xs font-bold\">%userName%</div>\n                        </div>\n                    </div>\n                    <div class=\"col-sm-8\">\n                        <h3><strong>%userCode%</strong></h3>\n                        <p><i class=\"fa fa-jpy\"></i> %userBalance%</p>\n                        <address>\n                        <strong>RuoYi, Inc.</strong><br>\n                        E-mail: %userEmail%<br>\n                        <abbr title=\"Phone\">Tel:</abbr> %userPhone%\n                       </address>\n                    </div>\n                    <div class=\"clearfix\"></div>\n                 </a>\n             </div>\n        </div>\n    </template>\n\n    <div th:include=\"include :: footer\"></div>\n    <th:block th:include=\"include :: bootstrap-table-custom-view-js\" />\n    <script th:inline=\"javascript\">\n        var prefix = ctx + \"demo/table\";\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\n\n        $(function() {\n            var options = {\n                url: prefix + \"/list\",\n\t\t        showSearch: false,\n\t\t        showRefresh: false,\n\t\t        showToggle: false,\n\t\t        showColumns: false,\n\t\t        showExport: true,\n                columns: [{\n\t\t            checkbox: true\n\t\t        },\n\t\t\t\t{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '用户ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '用户编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '用户姓名'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userPhone', \n\t\t\t\t\ttitle : '用户手机'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userEmail', \n\t\t\t\t\ttitle : '用户邮箱'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t    field : 'userBalance',\n\t\t\t\t    title : '用户余额'\n\t\t\t\t},\n\t\t\t\t{\n                    field: 'status',\n                    title: '用户状态',\n                    align: 'center',\n                    formatter: function(value, row, index) {\n                    \treturn $.table.selectDictLabel(datas, value);\n                    }\n                },\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'center',\n\t\t            formatter: function(value, row, index) {\n\t\t            \tvar actions = [];\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\n\t\t\t\t\t\treturn actions.join('');\n\t\t            }\n\t\t        }]\n            };\n            $.table.init(options);\n        });\n        \n        function customViewFormatter (data) {\n            var template = $('#profileTemplate').html()\n            var view = ''\n            $.each(data, function (i, row) {\n              view += template.replace('%userCode%', row.userCode)\n                .replace('%IMAGE%', \"http://demo.ruoyi.vip/img/profile.jpg\")\n                .replace('%userName%', row.userName)\n                .replace('%userEmail%', row.userEmail)\n                .replace('%userPhone%', row.userPhone)\n                .replace('%userBalance%', row.userBalance);\n            })\n\n            return `<div class=\"row mx-0\">${view}</div>`\n          }\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/data.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('加载data数据')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                data: [[${users}]],\r\n                sidePagination: \"client\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/detail.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格细节视图')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        detailView: true,\r\n\t\t        detailFormatter: detailFormatter,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function detailFormatter(index, row) {\r\n        \tvar html = [];\r\n        \t$.each(row, function(key, value) {\r\n        \t\thtml.push('<p><b>' + key + ':</b> ' + value + '</p>');\r\n        \t});\r\n        \treturn html.join('');\r\n       \t}\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/dynamicColumns.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n<th:block th:include=\"include :: header('动态列')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"table-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t要增加的列：\r\n\t\t\t\t\t\t\t\t<select name=\"field\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">默认</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"userBalance\">用户余额</option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"tableSearch()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<div th:include=\"include :: footer\"></div>\r\n\t<script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n        \tajaxColumns();\r\n        });\r\n        // 动态获取列\r\n        function ajaxColumns() {\r\n        \tvar url = prefix + \"/ajaxColumns\";\r\n        \tvar dataParam = $.common.formToJSON(\"table-form\");\r\n            $.modal.loading(\"正在查询中，请稍候...\");\r\n            $.post(url, dataParam, function(result) {\r\n                if (result.code == web_status.SUCCESS) {\r\n                \tsetColumns(result.data);\r\n                } else if (result.code == web_status.WARNING) {\r\n                    $.modal.alertWarning(result.msg)\r\n                } else {\r\n                    $.modal.alertError(result.msg);\r\n                }\r\n                $.modal.closeLoading();\r\n            });\r\n        }\r\n      \t// 设置列\r\n        function setColumns(list) {\r\n        \tvar columns = [];\r\n        \tlist.forEach(function(item) {\r\n        \t    if($.common.equals('status',item.field)){\r\n        \t    \tcolumns.push({\r\n        \t    \t\tfield : item.field, \r\n    \t\t\t\t\ttitle : item.title,\r\n                        align: 'center',\r\n                        formatter: function(value, row, index) {\r\n                        \treturn $.table.selectDictLabel(datas, value);\r\n                        }\r\n        \t    \t})\r\n        \t    } else {\r\n        \t    \tcolumns.push({\r\n        \t    \t\tfield : item.field, \r\n    \t\t\t\t\ttitle : item.title\r\n        \t    \t})\r\n        \t    }\r\n        \t});\r\n        \tcolumns.push({\r\n\t            title: '操作',\r\n\t            align: 'center',\r\n\t            formatter: function(value, row, index) {\r\n\t            \tvar actions = [];\r\n\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                    actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\treturn actions.join('');\r\n\t            }\r\n\t        });\r\n        \tif(!table.get(table.options.id)){\r\n        \t\tinitTable(columns);\r\n        \t} else {\r\n        \t\trefreshTable(columns);\r\n        \t}\r\n        }\r\n      \t// 刷新表格\r\n        function refreshTable(columns) {\r\n        \tvar options = {\r\n        \t\tcolumns: columns\r\n        \t};\r\n        \t$(\"#\" + table.options.id).bootstrapTable('refreshOptions',options);\r\n        }\r\n      \t// 初始化表格\r\n        function initTable(columns){\r\n        \tvar options = {\r\n        \t\turl: prefix + \"/list\",\r\n            \tshowSearch: false,\r\n            \tshowRefresh: false,\r\n            \tshowToggle: false,\r\n            \tshowColumns: false,\r\n            \tcolumns: columns\r\n            };\r\n            $.table.init(options);\r\n        }\r\n      \t// 搜索\r\n        function tableSearch(){\r\n        \tajaxColumns();\r\n        }\r\n      \t// 重置\r\n\t\tfunction reset(){\r\n\t\t\t$(\"#table-form\")[0].reset();\r\n\t\t\tajaxColumns();\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/editable.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格行内编辑')\" />\r\n\t<th:block th:include=\"include :: bootstrap-editable-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n             <a class=\"btn btn-info\" onclick=\"getSelections()\">\r\n\t            <i class=\"fa fa-search\"></i> 查询选择数据\r\n\t        </a>\r\n\t        <a class=\"btn btn-primary\" onclick=\"getData()\">\r\n\t            <i class=\"fa fa-search\"></i> 获取所有数据\r\n\t        </a>\r\n        </div>\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: bootstrap-table-editable-js\" />\r\n\t\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        showPageGo: true,\r\n\t\t        onEditableSave: onEditableSave,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号',\r\n\t\t\t\t\teditable: true\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名',\r\n\t\t\t\t\teditable : {\r\n\t\t\t\t\t\ttype : 'text',\r\n\t\t\t\t\t\ttitle : '名称',\r\n\t\t\t\t\t\temptytext : \"【名称】为空\",\r\n\t\t\t\t\t\tvalidate : function(value) {\r\n\t\t\t\t\t\t\tif (value.length > 30) {\r\n\t\t\t\t\t\t\t\treturn '名称不能超过30个字符';\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (value.length == 0) {\r\n\t\t\t\t\t\t\t\treturn '名称不能为空';\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    editable : {\r\n\t\t\t\t\t\ttype : 'select',\r\n\t\t\t\t\t\ttitle : '状态',\r\n\t\t\t\t\t\tsource : [{\r\n\t\t\t\t\t\t\tvalue : 0,\r\n\t\t\t\t\t\t\ttext : \"正常\"\r\n\t\t\t\t\t\t}, {\r\n\t\t\t\t\t\t\tvalue : 1,\r\n\t\t\t\t\t\t\ttext : \"停用\"\r\n\t\t\t\t\t\t}]\r\n\t\t\t\t\t}\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function onEditableSave (field, row, rowIndex, oldValue, $el) {\r\n        \talert(\"字段名：\" + field + \"，当前值：\" + row[field]  + \"，旧值：\" + oldValue);\r\n        }\r\n        \r\n        /* 查询表格所有数据值 */\r\n        function getData(){\r\n        \tvar data = $(\"#\" + table.options.id).bootstrapTable('getData');\r\n            alert(JSON.stringify(data))\r\n        }\r\n        \r\n        /* 查询表格选择行数据值 */\r\n        function getSelections(){\r\n        \tvar data = $(\"#\" + table.options.id).bootstrapTable('getSelections');\r\n        \talert(JSON.stringify(data))\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/event.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('自定义触发事件')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <p class=\"select-title\">自定义触发事件（点击某行/双击某行/单击某格/双击某格/服务器发送数据前触发/数据被加载时触发）</p>\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        onCheck: onCheck,\r\n\t\t        onUncheck: onUncheck,\r\n\t\t        onCheckAll: onCheckAll,\r\n\t\t        onUncheckAll: onUncheckAll,\r\n\t\t        onClickRow: onClickRow,\r\n\t\t        onDblClickRow: onDblClickRow,\r\n\t\t        onClickCell: onClickCell,\r\n\t\t        onDblClickCell: onDblClickCell,\r\n\t\t        responseHandler: responseHandler,\r\n\t\t        onLoadSuccess: onLoadSuccess,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function onClickRow(row, $element){\r\n        \talert(\"单击行userId：\" + row.userId + \" userName：\" + row.userName);\r\n        }\r\n        \r\n        function onDblClickRow(row, $element){\r\n        \talert(\"双击行userId：\" + row.userId + \" userName：\" + row.userName);\r\n        }\r\n        \r\n        function onClickCell(field, value, row, $element){\r\n        \talert(\"单击格name：\" + field + \" value：\" + value);\r\n        }\r\n        \r\n        function onDblClickCell(field, value, row, $element){\r\n        \talert(\"双击格name：\" + field + \" value：\" + value);\r\n        }\r\n        \r\n        function onCheck(row, $element){\r\n        \talert(\"选中行userId：\" + row.userId + \" userName：\" + row.userName);\r\n        }\r\n        \r\n        function onUncheck(row, $element){\r\n        \talert(\"取消行userId：\" + row.userId + \" userName：\" + row.userName);\r\n        }\r\n        \r\n        function onCheckAll(rowsAfter, rowsBefore){\r\n        \tvar rows = $.map(rowsAfter, function(row) {\r\n    \t        return $.common.getItemField(row, \"userId\");\r\n    \t    });\r\n        \talert(\"全选行：\" + rows);\r\n        }\r\n        \r\n        function onUncheckAll(rowsAfter, rowsBefore){\r\n        \tvar rows = $.map(rowsBefore, function(row) {\r\n    \t        return $.common.getItemField(row, \"userId\");\r\n    \t    });\r\n        \talert(\"取消行：\" + rows);\r\n        }\r\n        \r\n        function responseHandler(res){\r\n        \talert(\"请求获取数据后处理回调函数\");\r\n        }\r\n        \r\n        function onLoadSuccess(data){\r\n        \talert(\"当所有数据被加载时触发\");\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/export.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('导出')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <th:block th:include=\"include :: bootstrap-table-export-js\" />\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        showExport: true,\r\n\t\t        exportDataType: 'selected', // 导出选择数据\r\n\t\t        exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel'], // 导出的文件类型\r\n\t\t        exportOptions: {\r\n\t\t        \tfileName: '用户数据',    // 文件名称设置\r\n\t\t        \tignoreColumn: [0, 8]    // 忽略第一列和最后一列\r\n\t\t        },\r\n\t\t        clickToSelect: true,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/exportSelected.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('导出选择列')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t    <div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"export-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t用户姓名：<input type=\"text\" name=\"userName\" value=\"\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t        <i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  勾选数据导出指定列，否则为全部   \r\n\t\t        <a class=\"btn btn-warning\" onclick=\"exportSelected()\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n            </div>\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        clickToSelect: true,\r\n\t\t        rememberSelected: true,\r\n                columns: [{\r\n                \tfield: 'state',\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        // 导出数据\r\n        function exportSelected() {\r\n        \tvar userIds = $.table.selectColumns(\"userId\");\r\n        \tvar dataParam = $(\"#export-form\").serializeArray();\r\n        \tvar tipMsg = \"确定导出所有数据吗？\";\r\n        \tif($.common.isNotEmpty(userIds)){\r\n        \t\ttipMsg = \"确定导出勾选\" + userIds.length + \"条数据吗？\";\r\n        \t\tdataParam.push({ \"name\": \"userIds\", \"value\": userIds });\r\n        \t}\r\n        \t$.modal.confirm(tipMsg, function() {\r\n    \t\t\t$.post(prefix + \"/exportData\", dataParam, function(result) {\r\n                    if (result.code == web_status.SUCCESS) {\r\n                        window.location.href = ctx + \"common/download?fileName=\" + encodeURI(result.msg) + \"&delete=\" + true;\r\n                    } else {\r\n                        $.modal.alertError(result.msg);\r\n                    }\r\n                });\r\n        \t});\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/fixedColumns.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('冻结列')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t\t\t<a class=\"btn btn-success\">\r\n\t                <i class=\"fa fa-plus\"></i> 新增\r\n\t            </a>\r\n\t\t\t\t<a class=\"btn btn-primary single disabled\">\r\n\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t        </a>\r\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t        </div>\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <th:block th:include=\"include :: bootstrap-table-fixed-columns-js\" />\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        fixedColumns: true,\r\n    \t\t    fixedNumber: 3,\r\n    \t\t    fixedRightNumber: 3,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试1'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试2'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试3'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试4'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试5'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试6'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试7'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试8'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试9'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试10'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试11'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试12'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试13'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试14'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试15'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '测试16'\r\n\t\t\t\t}]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/footer.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格数据汇总')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showFooter: true,\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        footerStyle: footerStyle,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额',\r\n\t\t\t\t    footerFormatter:function (value) {\r\n\t\t\t\t    \tvar sumBalance = 0;\r\n\t\t\t\t        for (var i in value) {\r\n\t\t\t\t        \tsumBalance += parseFloat(value[i].userBalance);\r\n\t\t\t\t        }\r\n\t\t\t\t        return \"总金额：\" + sumBalance;\r\n\t\t\t\t    }\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function footerStyle(column) {\r\n        \treturn {\r\n//         \t    userBalance: {\r\n//         \t        classes: 'class'\r\n//         \t    },\r\n        \t    userBalance: {\r\n        \t        css: { color: 'red', 'font-weight': 'normal' }\r\n        \t    }\r\n        \t}[column.field]\r\n          }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/groupHeader.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('组合表头')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-bordered\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        columns : [\r\n        \t\t\t\t[{\r\n        \t\t\t\t\ttitle : '基本信息',\r\n        \t\t\t\t\talign : 'center',\r\n        \t\t\t\t\tcolspan : 6\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\ttitle : '其他信息',\r\n        \t\t\t\t\talign : 'center',\r\n        \t\t\t\t\tcolspan : 3\r\n        \t\t\t\t}\r\n        \t\t\t],\r\n        \t\t\t[{\r\n        \t\t\t\t\tcheckbox : true\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\tfield : 'userId',\r\n        \t\t\t\t\ttitle : '用户ID'\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\tfield : 'userCode',\r\n        \t\t\t\t\ttitle : '用户编号'\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\tfield : 'userName',\r\n        \t\t\t\t\ttitle : '用户姓名'\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\tfield : 'userPhone',\r\n        \t\t\t\t\ttitle : '用户手机'\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\tfield : 'userEmail',\r\n        \t\t\t\t\ttitle : '用户邮箱'\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\tfield : 'userBalance',\r\n        \t\t\t\t\ttitle : '用户余额'\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\tfield : 'status',\r\n        \t\t\t\t\ttitle : '用户状态',\r\n        \t\t\t\t\tformatter : function (value, row, index) {\r\n        \t\t\t\t\t\treturn $.table.selectDictLabel(datas, value);\r\n        \t\t\t\t\t}\r\n        \t\t\t\t}, {\r\n        \t\t\t\t\ttitle : '操作',\r\n        \t\t\t\t\talign : 'center',\r\n        \t\t\t\t\tformatter : function (value, row, index) {\r\n        \t\t\t\t\t\tvar actions = [];\r\n        \t\t\t\t\t\tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n        \t\t\t\t\t\tactions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n        \t\t\t\t\t\treturn actions.join('');\r\n        \t\t\t\t\t}\r\n        \t\t\t\t}\r\n        \t\t\t]\r\n        \t\t]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/headerStyle.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格标题格式化')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        headerStyle: headerStyle,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function headerStyle(column) {\r\n            return {\r\n                userId: {\r\n                    classes: 'uppercase'\r\n                },\r\n                userName: {\r\n                    css: { background: 'yellow' }\r\n                },\r\n                userBalance: {\r\n                    css: { color: 'red' }\r\n                }\r\n            } [column.field]\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/image.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格图片预览')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    title: '图片',\r\n\t\t\t\t    formatter: function(value, row, index) {\r\n\t\t\t\t    \t// 图片预览（注意：如存储在本地直接获取数据库路径，如有配置context-path需要使用ctx+路径）\r\n\t\t\t\t    \t// 如：/profile/upload/2019/08/08/3b7a839aced67397bac694d77611ce72.png\r\n\t\t\t\t    \tif(index % 2 == 0){\r\n\t\t\t\t    \t\treturn $.table.imageView('http://demo.ruoyi.vip/img/profile.jpg');\r\n\t\t\t\t    \t}else {\r\n\t\t\t\t    \t\treturn $.table.imageView('http://demo.ruoyi.vip/ruoyi.png');\r\n\t\t\t\t    \t}\r\n\t\t\t\t    }\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/multi.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('初始多表格')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"container-div\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12 search-collapse\">\r\n                <form id=\"form1\">\r\n                    <div class=\"select-list\">\r\n                        <ul>\r\n\t\t\t\t\t\t    <li>\r\n\t\t\t\t\t\t\t\t用户名称：<input type=\"text\" name=\"userName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search('form1', 'bootstrap-table1')\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset('form1', 'bootstrap-table1')\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n            <div class=\"btn-group-sm\" id=\"toolbar1\" role=\"group\">\r\n                <a class=\"btn btn-success\" onclick=\"options1()\">\r\n\t                <i class=\"fa fa-search\"></i> options\r\n\t            </a>\r\n\t            <a class=\"btn btn-success\" onclick=\"$.operate.add()\">\r\n\t                <i class=\"fa fa-plus\"></i> 新增\r\n\t            </a>\r\n\t            <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\">\r\n\t                <i class=\"fa fa-edit\"></i> 修改\r\n\t            </a>\r\n\t            <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\">\r\n\t                <i class=\"fa fa-remove\"></i> 删除\r\n\t            </a>\r\n            </div>\r\n\t\t\t<div class=\"col-xs-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table1\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t\r\n\t<div class=\"container-div\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12 search-collapse\">\r\n                <form id=\"form2\">\r\n                    <div class=\"select-list\">\r\n                        <ul>\r\n                            <li>\r\n\t\t\t\t\t\t\t\t用户名称：<input type=\"text\" name=\"userName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search('form2', 'bootstrap-table2')\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset('form2', 'bootstrap-table2')\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n            <div class=\"btn-group-sm\" id=\"toolbar2\" role=\"group\">\r\n                <a class=\"btn btn-success\" onclick=\"options2()\">\r\n\t                <i class=\"fa fa-search\"></i> options\r\n\t            </a>\r\n\t            <a class=\"btn btn-success\" onclick=\"$.operate.add()\">\r\n\t                <i class=\"fa fa-plus\"></i> 新增\r\n\t            </a>\r\n\t            <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\">\r\n\t                <i class=\"fa fa-edit\"></i> 修改\r\n\t            </a>\r\n\t            <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\">\r\n\t                <i class=\"fa fa-remove\"></i> 删除\r\n\t            </a>\r\n            </div>\r\n\t\t\t<div class=\"col-xs-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table2\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/operate\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n            \tid: \"bootstrap-table1\",\r\n            \tformId: \"form1\",\r\n            \ttoolbar: \"toolbar1\",\r\n                url: prefix + \"/list\",\r\n                createUrl: prefix + \"/add\",\r\n                removeUrl: prefix + \"/remove\",\r\n                updateUrl: prefix + \"/edit/{id}\",\r\n\t\t        modalName: \"用户\",\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"###\" onclick=\"$.operate.edit(\\'' + row.userId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"###\" onclick=\"$.operate.remove(\\'' + row.userId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        \r\n        $(function() {\r\n            var options = {\r\n            \tid: \"bootstrap-table2\",\r\n            \tformId: \"form2\",\r\n            \ttoolbar: \"toolbar2\",\r\n                url: prefix + \"/list\",\r\n                createUrl: prefix + \"/add\",\r\n                removeUrl: prefix + \"/remove\",\r\n                updateUrl: prefix + \"/edit/{id}\",\r\n\t\t        modalName: \"用户\",\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"###\" onclick=\"$.operate.edit(\\'' + row.userId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n\t\t            \tactions.push('<a class=\"btn btn-danger btn-xs\" href=\"###\" onclick=\"$.operate.remove(\\'' + row.userId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function options1() {\r\n        \tvar temp = \"\";\r\n        \tvar obj = table.config['bootstrap-table1'];\r\n        \tfor (var i in obj) {\r\n        \t    temp += i + \":\" + obj[i] + \"<br/>\";\r\n        \t}\r\n        \t$.modal.alert(temp);\r\n        }\r\n        \r\n        function options2() {\r\n        \tvar temp = \"\";\r\n        \tvar obj = table.config['bootstrap-table2'];\r\n        \tfor (var i in obj) {\r\n        \t    temp += i + \":\" + obj[i] + \"<br/>\";\r\n        \t}\r\n        \t$.modal.alert(temp);\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/other.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('其他操作')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n     \t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t        <a class=\"btn btn-success\" onclick=\"$.table.showColumn('userName')\">\r\n\t            <i class=\"fa fa-check\"></i> 显示姓名\r\n\t        </a>\r\n\t        <a class=\"btn btn-danger\" onclick=\"$.table.hideColumn('userName')\">\r\n\t            <i class=\"fa fa-close\"></i> 隐藏姓名\r\n\t        </a>\r\n\t        <a class=\"btn btn-info\" onclick=\"selectColumns()\">\r\n\t            <i class=\"fa fa-search\"></i> 获取选中姓名\r\n\t        </a>\r\n\t        <a class=\"btn btn-warning\" onclick=\"$.table.refresh()\">\r\n\t            <i class=\"fa fa-refresh\"></i> 刷新\r\n\t        </a>\r\n\t        <a class=\"btn btn-danger\" onclick=\"$.table.destroy()\">\r\n\t            <i class=\"fa fa-refresh\"></i> 销毁\r\n\t        </a>\r\n\t        <a class=\"btn btn-primary\" onclick=\"selectFirstColumns()\">\r\n\t            <i class=\"fa fa-search\"></i> 获取选中首列值\r\n\t        </a>\r\n        </div>\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function selectColumns() {\r\n        \tvar column = $.table.selectColumns('userName');\r\n        \talert(column);\r\n        }\r\n        \r\n        function selectFirstColumns() {\r\n        \tvar column = $.table.selectFirstColumns();\r\n        \talert(column);\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/pageGo.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('跳转至指定页')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        showPageGo: true,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/params.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('自定义查询参数')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<p class=\"select-title\">通过queryParams方法设置</p>\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"post-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t用户姓名：<input type=\"text\" name=\"userName\" value=\"测试6\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<p class=\"select-title\">通过form自动填充</p>\r\n\t\t\t\t<table id=\"bootstrap-table-form\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        queryParams: queryParams,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function queryParams(params) {\r\n            var search = $.table.queryParams(params);\r\n            search.userName = '测试1';\r\n            return search;\r\n        }\r\n        \r\n        \r\n        $(function() {\r\n            var options = {\r\n            \tid: \"bootstrap-table-form\",\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/print.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('表格打印配置')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t    <!-- data-show-print设置为true为显示工具栏上的“打印”按钮。\n\t\t\t         data-print-as-filtered-and-sorted-on-ui为true时-在用户界面上按排序和过滤条件打印表格。请注意，如果设置为true以及用于过滤和排序的显式预定义打印选项（printFilter，printSortOrder，printSortColumn），则它们将应用于已由UI控件过滤和排序的数据。对于在UI上按过滤和排序方式打印数据-请勿设置以下3个选项：printFilter，printSortOrder，printSortColumn\n\t\t\t         data-print-page-builder 接收html <table>元素作为字符串参数，返回html字符串进行打印。用于样式和添加页眉或页脚。\n\t\t\t         data-print-sort-column 设置列字段名称以对打印表进行排序\n\t\t\t         data-print-sort-order 有效值：“ asc”，“ desc”。仅当设置了printSortColumn时相关\n\t\t\t         data-print-filter 设置值以按此列过滤打印的数据。\n\t\t\t         data-print-formatter 函数（值，行，索引）-返回字符串。格式化打印表中此列的单元格值。函数行为类似于“ formatter”列选项\n\t\t\t         printIgnore 设置为true可以在打印页面中隐藏此列。 -->\n\t\t\t\t<table id=\"bootstrap-table\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n    <div th:include=\"include :: footer\"></div>\n    <th:block th:include=\"include :: bootstrap-table-print-js\" />\n    <script th:inline=\"javascript\">\n        var prefix = ctx + \"demo/table\";\n\n        $(function() {\n            var options = {\n                url: prefix + \"/list\",\n                showPrint: true,\n\t\t        showSearch: false,\n\t\t        showRefresh: false,\n\t\t        showToggle: false,\n\t\t        showColumns: false,\n\t\t        printPageBuilder: printPageBuilder,\n                columns: [{\n\t\t            checkbox: true,\n\t\t            printIgnore: true\n\t\t        },\n\t\t\t\t{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '用户ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '用户编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '用户姓名'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userPhone', \n\t\t\t\t\ttitle : '用户手机'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userEmail', \n\t\t\t\t\ttitle : '用户邮箱'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t    field : 'userBalance',\n\t\t\t\t    title : '用户余额'\n\t\t\t\t},\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'center',\n\t\t            printIgnore: true,\n\t\t            formatter: function(value, row, index) {\n\t\t            \tvar actions = [];\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\" onclick=\"remove(this)\"><i class=\"fa fa-remove\"></i>删除</a>');\n\t\t\t\t\t\treturn actions.join('');\n\t\t            }\n\t\t        }]\n            };\n            $.table.init(options);\n        });\n        \n        // 假删除操作\n        function remove(obj) {\n        \t$.modal.confirm(\"确认要删除吗？\", function() {\n        \t    $(obj).parents(\"tr\").remove();\n        \t    $.modal.msgSuccess('已删除!');\n        \t});\n        }\n        \n        // 自定义打印页面模板\n        function printPageBuilder(table) {\n        \treturn `\n        \t<html>\n        \t  <head>\n        \t  <style type=\"text/css\" media=\"print\">\n        \t  @page {\n        \t    size: auto;\n        \t    margin: 25px 0 25px 0;\n        \t  }\n        \t  </style>\n        \t  <style type=\"text/css\" media=\"all\">\n        \t  table {\n        \t    border-collapse: collapse;\n        \t    font-size: 12px;\n        \t  }\n        \t  table, th, td {\n        \t    border: 1px solid grey;\n        \t  }\n        \t  th, td {\n        \t    text-align: center;\n        \t    vertical-align: middle;\n        \t  }\n        \t  p {\n        \t    font-weight: bold;\n        \t    margin-left:20px;\n        \t  }\n        \t  table {\n        \t    width:94%;\n        \t    margin-left:3%;\n        \t    margin-right:3%;\n        \t  }\n        \t  div.bs-table-print {\n        \t    text-align:center;\n        \t  }\n        \t  </style>\n        \t  </head>\n        \t  <title>Print Table</title>\n        \t  <body>\n        \t  <div class=\"bs-table-print\">${table}</div>\n        \t  </body>\n        \t</html>`\n        }\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/refresh.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格自动刷新')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <!-- data-auto-refresh设置true为启用自动刷新插件 \r\n\t\t\t         data-auto-refresh-interval为每次自动刷新发生的时间（以秒为单位）默认60。\r\n\t\t\t\t     data-auto-refresh-silent设置为true可以自动无提示刷新。默认： true\r\n\t\t\t\t     data-auto-refresh-status 设置true为启用自动刷新。这是表加载时自动刷新的状态。单击按钮切换此属性。这只是自动刷新的默认状态，因为用户始终可以通过单击按钮来更改它。 默认： true  -->\r\n\t\t\t\t<table id=\"bootstrap-table\" data-auto-refresh=\"true\" data-auto-refresh-interval=\"30\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <th:block th:include=\"include :: bootstrap-table-auto-refresh-js\" />\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\" onclick=\"remove(this)\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        // 假删除操作\r\n        function remove(obj) {\r\n        \t$.modal.confirm(\"确认要删除吗？\", function() {\r\n        \t    $(obj).parents(\"tr\").remove();\r\n        \t    $.modal.msgSuccess('已删除!');\r\n        \t});\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/remember.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('翻页记住选择')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n     \t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t        <a class=\"btn btn-success\" onclick=\"checkItem()\">\r\n\t            <i class=\"fa fa-check\"></i> 选中项\r\n\t        </a>\r\n        </div>\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        rememberSelected: true,\r\n                columns: [{\r\n                \tfield: 'state',\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        // 选中数据\r\n        function checkItem(){\r\n        \t// var arrays = $.table.selectColumns(\"userId\");\r\n        \tvar arrays = $.table.selectColumns(\"userCode\");\r\n        \talert(arrays);\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/reorderColumns.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格列拖拽操作')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t        <a class=\"btn btn-success\" onclick=\"orderColumns()\">\r\n\t            <i class=\"fa fa-refresh\"></i> 恢复顺序\r\n\t        </a>\r\n        </div>\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-bordered\">\r\n\t\t\t    <p class=\"select-title\">按住表格列拖拽</p>\r\n\t\t\t\t<table id=\"bootstrap-table\"\r\n\t\t\t\t data-reorderable-columns=\"true\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <script th:src=\"@{/js/jquery-ui-1.10.4.min.js}\"></script>\r\n    <th:block th:include=\"include :: bootstrap-table-reorder-columns-js\" />\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        function orderColumns() {\r\n            $('#bootstrap-table').bootstrapTable('orderColumns', {\r\n            \tuserId: 0,\r\n            \tuserCode: 1,\r\n            \tuserName: 2,\r\n            \tuserPhone: 3,\r\n            \tuserEmail: 4,\r\n            \tuserBalance: 5,\r\n            \tstatus: 6\r\n            })\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/reorderRows.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('表格行拖拽操作')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\n            <a class=\"btn btn-primary\" onclick=\"getData()\">\n                <i class=\"fa fa-search\"></i> 查询所有数据\n            </a>\n        </div>\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t    <p class=\"select-title\">按住表格行拖拽</p>\n\t\t\t\t<table id=\"bootstrap-table\"\n\t\t\t\t data-use-row-attr-func=\"true\"\n\t\t\t\t data-reorderable-rows=\"true\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n    <div th:include=\"include :: footer\"></div>\n    <th:block th:include=\"include :: bootstrap-table-reorder-rows-js\" />\n    <script th:inline=\"javascript\">\n        var prefix = ctx + \"demo/table\";\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\n\n        $(function() {\n            var options = {\n                url: prefix + \"/list\",\n\t\t        showSearch: false,\n\t\t        showRefresh: false,\n\t\t        showToggle: false,\n\t\t        showColumns: false,\n\t\t        onReorderRow: function (data, newRow, oldRow, el) {\n\t\t\t        // 当拖拽结束后，data为整个表格的数据\n\t\t            console.table(data)\n\t\t            // 当sidePagination: \"server\"时，拖拽行后顺序错乱，需要重新调用加载数据方法\n\t\t            $(\"#\" + table.options.id).bootstrapTable('load', {\n\t\t\t            total: el._xhr.responseJSON.total,\n\t\t\t            rows: data\n\t\t\t        });\n\t\t            return false;\n\t\t        },\n                columns: [{\n\t\t            checkbox: true\n\t\t        },\n\t\t\t\t{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '用户ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '用户编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '用户姓名'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userPhone', \n\t\t\t\t\ttitle : '用户手机'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userEmail', \n\t\t\t\t\ttitle : '用户邮箱'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t    field : 'userBalance',\n\t\t\t\t    title : '用户余额'\n\t\t\t\t},\n\t\t\t\t{\n                    field: 'status',\n                    title: '用户状态',\n                    align: 'center',\n                    formatter: function(value, row, index) {\n                    \treturn $.table.selectDictLabel(datas, value);\n                    }\n                }]\n            };\n            $.table.init(options);\n        });\n        \n        /* 查询表格所有数据值 */\n        function getData(){\n            var data = $(\"#\" + table.options.id).bootstrapTable('getData');\n            alert(JSON.stringify(data.map( item => { return item.userId })))\n        }\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/resizable.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格列宽拖动')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 select-table table-bordered\">\r\n\t\t\t\t<table id=\"bootstrap-table\" data-resizable=\"true\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n    <div th:include=\"include :: footer\"></div>\r\n    <th:block th:include=\"include :: bootstrap-table-resizable-js\" />\r\n    \r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"demo/table\";\r\n        var datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userId', \r\n\t\t\t\t\ttitle : '用户ID'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userCode', \r\n\t\t\t\t\ttitle : '用户编号'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userName', \r\n\t\t\t\t\ttitle : '用户姓名',\r\n\t\t\t\t\tcellStyle: function (value, row, index) {\r\n                        return { css: { \"min-width\": \"100px\", \"white-space\": \"nowrap\", \"text-overflow\": \"ellipsis\", \"overflow\": \"hidden\", \"max-width\": \"200px\" } }\r\n                    },\r\n                    formatter: function(value, row, index) {\r\n                        if (index == 0) {\r\n                            value = value + \"，测试用户姓名，这是一条长文本，可以通过拖拽自适应内容显示。。。。\";\r\n                        }\r\n                        return $.table.tooltip(value, 30, \"open\");\r\n                    }\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userPhone', \r\n\t\t\t\t\ttitle : '用户手机'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'userEmail', \r\n\t\t\t\t\ttitle : '用户邮箱'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t    field : 'userBalance',\r\n\t\t\t\t    title : '用户余额'\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n                    field: 'status',\r\n                    title: '用户状态',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \treturn $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs\" href=\"javascript:;\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs\" href=\"javascript:;\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/search.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表格搜索')\" />\r\n\t<th:block th:include=\"include :: bootstrap-select-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t    <p class=\"select-title\">普通条件查询</p>\r\n\t\t\t\t<form id=\"ordinary-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t商户编号：<input type=\"text\" name=\"userId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t终端编号：<input type=\"text\" name=\"termId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t处理状态：<select name=\"status\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"0\">初始</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"1\">处理中</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"2\">交易成功</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"3\">交易失败</option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t    <p class=\"select-title\">时间条件查询</p>\r\n\t\t\t\t<form id=\"time-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t商户编号：<input type=\"text\" name=\"userId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t终端编号：<input type=\"text\" name=\"termId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-time\">\r\n\t\t\t\t\t\t\t\t<label>创建时间： </label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[beginTime]\"/>\r\n\t\t\t\t\t\t\t\t<span>-</span>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[endTime]\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset('time-form')\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t    <p class=\"select-title\">多级联动下拉查询</p>\r\n\t\t\t\t<form id=\"cxselect-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul id=\"element\">\r\n\t\t\t\t\t\t    <li>\r\n\t\t\t\t\t\t\t\t商户编号：<input type=\"text\" name=\"userId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t充值类型：<select class=\"type\"></select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t充值路由：<select class=\"router\"></select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset('cxselect-form')\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t    <p class=\"select-title\">下拉多选条件查询</p>\r\n\t\t\t\t<form id=\"select-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t商户编号：<input type=\"text\" name=\"userId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t终端编号：<input type=\"text\" name=\"termId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-selectpicker\">\r\n\t\t\t\t\t\t\t\t<label>操作类型： </label><select class=\"selectpicker\" data-none-selected-text=\"请选择\" multiple>\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"0\">初始</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"1\">处理中</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"2\">交易成功</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"3\">交易失败</option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset('select-form')\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t    <p class=\"select-title\">复杂条件查询</p>\r\n\t\t\t\t<form id=\"complex-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">商户编号：</label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" name=\"userId\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">订单号：</label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" name=\"orderNo\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">日期：</label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" placeholder=\"日期\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-selectpicker\">\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">状态：</label>\r\n\t\t\t\t\t\t\t\t<select class=\"selectpicker\" data-none-selected-text=\"请选择\" multiple>\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"0\">初始</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"1\">处理中</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"2\">交易成功</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"3\">交易失败</option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">供货商通道：</label>\r\n\t\t\t\t\t\t\t\t<select>\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"0\">腾讯</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"1\">天猫</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"2\">京东</option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">来源：</label>\r\n\t\t\t\t\t\t\t\t<select>\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"0\">手机</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"1\">电脑</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"2\">第三方</option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">运营商：</label>\r\n\t\t\t\t\t\t\t\t<select>\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"0\">移动</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"1\">电信</option>\r\n\t\t\t\t\t\t\t\t\t<option value=\"2\">联通</option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-time\">\r\n\t\t\t\t\t\t\t\t<label style=\"width: 80px\">回调时间：</label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" placeholder=\"开始时间\"/>\r\n\t\t\t\t\t\t\t\t<span>-</span>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" placeholder=\"结束时间\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm m50\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset('complex-form')\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: bootstrap-select-js\" />\r\n\t<th:block th:include=\"include :: jquery-cxselect-js\" />\r\n\r\n\t<script th:inline=\"javascript\">\r\n\t    // 直接返回获取\r\n   \t\tvar data = [{\"v\":\"taobao\",\"n\":\"淘宝\",\"s\":[{\"v\":\"tm\",\"n\":\"天猫\"},{\"v\":\"jhs\",\"n\":\"聚划算\"}]},{\"v\":\"jd\",\"n\":\"京东\",\"s\":[{\"v\":\"jdcs\",\"n\":\"京东超市\"},{\"v\":\"jdsx\",\"n\":\"京东生鲜\"}]}];\r\n    \t$('#element').cxSelect({\r\n    \t  selects: ['type', 'router'],\r\n    \t  jsonValue: 'v',\r\n    \t  data: data\r\n    \t});\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/subdata.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n    <th:block th:include=\"include :: header('主子表提交')\" />\r\n    <th:block th:include=\"include :: datetimepicker-css\" />\r\n    <style type=\"text/css\">\r\n        table label.error{position: inherit;}select + label.error{z-index:1;right:40px;}\r\n    </style>\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"main-content\">\r\n        <form id=\"form-add\" class=\"form-horizontal\">\r\n            <h4 class=\"form-header h4\">客户信息</h4>\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">客户名称：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"name\" placeholder=\"请输入客户名称\" class=\"form-control\" type=\"text\" maxlength=\"30\" required>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">用户性别：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <select name=\"sex\" class=\"form-control\" th:with=\"type=${@dict.getType('sys_user_sex')}\">\r\n\t\t\t\t                <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t            </select>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">手机号码：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input id=\"phonenumber\" name=\"phonenumber\" placeholder=\"请输入手机号码\" class=\"form-control isPhone\" type=\"text\" maxlength=\"11\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">生日：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group date\">\r\n\t\t                        <input name=\"birthday\" class=\"form-control\" placeholder=\"yyyy-MM-dd\" type=\"text\">\r\n\t\t                        <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n\t\t                    </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-xs-2 control-label\">备注：</label>\r\n                        <div class=\"col-xs-10\">\r\n                            <textarea name=\"remark\" maxlength=\"500\" class=\"form-control\" rows=\"3\"></textarea>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <h4 class=\"form-header h4\">商品数据</h4>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <button type=\"button\" class=\"btn btn-white btn-sm\" onclick=\"addRow()\"><i class=\"fa fa-plus\"> 增加</i></button>\r\n                    <button type=\"button\" class=\"btn btn-white btn-sm\" onclick=\"sub.delRow()\"><i class=\"fa fa-minus\"> 删除</i></button>\r\n                    <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t\t\t</div>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n      \r\n    <div class=\"row\">\r\n        <div class=\"col-sm-offset-5 col-sm-10\">\r\n            <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submitHandler()\"><i class=\"fa fa-check\"></i>保 存</button>&nbsp;\r\n            <button type=\"button\" class=\"btn btn-sm btn-danger\" onclick=\"closeItem()\"><i class=\"fa fa-reply-all\"></i>关 闭 </button>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: datetimepicker-js\" />\r\n    <script th:src=\"@{/js/jquery.tmpl.js}\"></script>\r\n\t<script th:inline=\"javascript\">\r\n\t    $(function() {\r\n\t    \t// 初始化数据, 可以由后台传过来\r\n\t    \tvar data = [\r\n\t    \t{\r\n\t    \t\tid: \"100\",\r\n\t    \t\tname: \"商品名称\",\r\n            \tweight: \"100\",\r\n            \tprice: \"12.5\",\r\n            \tdate: \"2021-02-01\",\r\n            \ttype: \"1\",\r\n\t    \t},\r\n\t    \t{\r\n\t    \t\tid: \"101\",\r\n\t    \t\tname: \"商品名称2\",\r\n            \tweight: \"50\",\r\n            \tprice: \"10.8\",\r\n            \tdate: \"2021-02-01\",\r\n            \ttype: \"0\",\r\n\t    \t}];\r\n\t\t    var options = {\r\n\t\t    \tdata: data,\r\n                pagination: false,\r\n\t\t        showSearch: false,\r\n                showRefresh: false,\r\n                showToggle: false,\r\n                showColumns: false,\r\n                sidePagination: \"client\",\r\n\t\t        columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t        \tfield: 'index',\r\n\t\t        \talign: 'center',\r\n\t\t        \ttitle: \"序号\",\r\n                    formatter: function (value, row, index) {\r\n                    \tvar columnIndex = $.common.sprintf(\"<input type='hidden' name='index' value='%s'>\", $.table.serialNumber(index));\r\n                    \tvar columnId = $.common.sprintf(\"<input type='hidden' name='goods[%s].id' value='%s'>\", index, row.id);\r\n                    \treturn columnIndex + $.table.serialNumber(index) + columnId;\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            field: 'name',\r\n\t\t            align: 'center',\r\n\t\t            title: '商品名称',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar html = $.common.sprintf(\"<input class='form-control goodsName' type='text' name='goods[%s].name' value='%s'>\", index, value);\r\n\t\t        \t\treturn html;\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'weight',\r\n\t\t            align: 'center',\r\n\t\t            title: '商品重量',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar html = $.common.sprintf(\"<input class='form-control goodsWeight' type='text' name='goods[%s].weight' value='%s'>\", index, value);\r\n\t\t        \t\treturn html;\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'date',\r\n\t\t            align: 'center',\r\n\t\t            title: '商品日期',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar html = $.common.sprintf(\"<input class='form-control' type='text' name='goods[%s].date' value='%s' placeholder='yyyy-MM-dd'>\", index, value);\r\n\t\t        \t\treturn html;\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'price',\r\n\t\t            align: 'center',\r\n\t\t            title: '商品价格',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar html = $.common.sprintf(\"<input class='form-control' type='text' name='goods[%s].price' value='%s'>\", index, value);\r\n\t\t        \t\treturn html;\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'type',\r\n\t\t            align: 'center',\r\n\t\t            title: '商品种类',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t        \t\tvar data = [{ index: index, type: value }];\r\n\t\t                return $(\"#goodsTypeTpl\").tmpl(data).html();\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n                    title: '操作',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                    \tvar value = $.common.isNotEmpty(row.index) ? row.index : $.table.serialNumber(index);\r\n                        return '<a class=\"btn btn-danger btn-xs\" href=\"javascript:void(0)\" onclick=\"sub.delRowByIndex(\\'' + value + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>';\r\n                    }\r\n                }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t    \r\n        $.validator.addMethod(\"goodsName\", function(value, element) {\r\n            return !this.optional(element);\r\n        }, \"商品名称必填。\");\r\n        \r\n        $.validator.addMethod(\"goodsWeight\", function(value, element) {\r\n            return !this.optional(element) && (value <= 100 && value >= 0);\r\n        }, \"商品重量长度区间0-100。\");\r\n        \r\n        /* 主子表-提交 */\r\n        function submitHandler(index, layero){\r\n            if ($.validate.form()) {\r\n                var data = $(\"#form-add\").serializeArray();\r\n                alert(JSON.stringify(data))\r\n                $.operate.saveModal(\"/demo/operate/customer/add\", data);\r\n            }\r\n        }\r\n\t    \r\n        $(\"input[name='birthday']\").datetimepicker({\r\n            format: \"yyyy-mm-dd\",\r\n            minView: \"month\",\r\n            autoclose: true\r\n        });\r\n        \r\n        function addRow() {\r\n        \tvar count = $(\"#\" + table.options.id).bootstrapTable('getData').length;\r\n        \tvar row = {\r\n                index: $.table.serialNumber(count),\r\n            \tname: \"\",\r\n            \tweight: \"\",\r\n            \tprice: \"\",\r\n            \tdate: \"\",\r\n            \ttype: \"\",\r\n            }\r\n        \tsub.addRow(row);\r\n        }\r\n        \r\n        $(\"#bootstrap-table\").on(\"post-body.bs.table\", function (e, args) {\r\n        \t$(\"input[name$='date']\").datetimepicker({\r\n\t            format: \"yyyy-mm-dd\",\r\n\t            minView: \"month\",\r\n\t            autoclose: true,\r\n\t            pickerPosition:'top-right'\r\n\t        });\r\n    \t});\r\n    </script>\r\n</body>\r\n</html>\r\n\r\n<!-- 商品类型 -->\r\n<script id=\"goodsTypeTpl\" type=\"text/x-jquery-tmpl\">\r\n<div>\r\n<select class='form-control' name='goods[${index}].type'>\r\n    <option value=\"\">所有</option>\r\n    <option value=\"0\" {{if type===\"0\"}}selected{{/if}}>寒性</option>\r\n    <option value=\"1\" {{if type===\"1\"}}selected{{/if}}>热性</option>\r\n</select>\r\n</div>\r\n</script>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/textSearch.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('全文搜索')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t\t<table id=\"bootstrap-table\" data-page-size=\"10\" data-search-align=\"left\"\n\t\t\t\t       data-show-custom-view=\"true\" data-custom-view=\"customViewFormatter\"\n                       data-custom-view-default-view=\"true\">\n                </table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t\n    <template id=\"textSearchTemplate\">\n        <div class=\"col-sm-12\">\n            <p style=\"margin-top:10px;line-height:1.5;\">\n             <span style=\"color:blue;font-size:medium\">%title%</span><br>\n             <span style=\"color:#000000;font-size:medium\">%content%</span><br>\n             <span style=\"color:#008000;font-size:medium\">\n                                        档号：<a href=\"javascript:void(0)\" onclick=\"handleView('%tableId%', '%archiveNo%')\">%archiveNo%</a>\n               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%docNo%\n              </span>\n            </p>\n        </div>\n    </template>\n\n    <div th:include=\"include :: footer\"></div>\n    <th:block th:include=\"include :: bootstrap-table-custom-view-js\" />\n    <script th:inline=\"javascript\">\n        var prefix = ctx + \"demo/table\";\n\n        $(function() {\n            var options = {\n                url: prefix + \"/text/list\",\n                search: true,\n\t\t        showSearch: false,\n\t\t        showRefresh: false,\n\t\t        showToggle: false,\n\t\t        showColumns: false,\n\t\t        showExport: true,\n                columns: [{\n\t\t            checkbox: true\n\t\t        },\n\t\t        {\n\t\t\t\t\tfield : 'tableId', \n\t\t\t\t\ttitle : '编号',\n\t\t\t\t\tvisible: false\n\t\t\t\t},\n\t\t        {\n\t\t\t\t\tfield : 'archiveNo', \n\t\t\t\t\ttitle : '档号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'docNo', \n\t\t\t\t\ttitle : '文件编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'title', \n\t\t\t\t\ttitle : '标题',\n\t\t\t\t\tformatter: function(value, row, index) {\n                        return $.table.tooltip(value, 20, \"open\");\n                    }\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'content', \n\t\t\t\t\ttitle : '内容',\n\t\t\t\t\tformatter: function(value, row, index) {\n                        return $.table.tooltip(value, 30, \"open\");\n                    }\n\t\t\t\t}]\n            };\n            $.table.init(options);\n        });\n        \n        function customViewFormatter (data) {\n            var template = $('#textSearchTemplate').html()\n            var view = ''\n\t        if(data.length > 0) {\n\t            $.each(data, function (i, row) {\n\t                view += template.replace('%tableId%', row.tableId)\n\t                .replaceAll('%archiveNo%', row.archiveNo)\n\t                .replace('%title%', row.title)\n\t                .replace('%docNo%', row.docNo)\n\t                .replace('%content%', truncateString(row.content, 500))\n\t            })\n\t            return `<div class=\"row mx-0\">${view}</div>`;\n            } else {\n                return `<div class=\"row mx-0\"><div class=\"col-sm-12\"><p style=\"margin-top:10px;line-height:1.5;\"><span style=\"font-size:medium\">没有找到记录。请检查过滤条件。</span></p></div></div>`\n            }\n          }\n        \n        function handleView(tableId, archiveNo) {\n        \talert(\"tableId：\" + tableId + \"，archiveNo：\" + archiveNo);\n        }\n        \n        function truncateString(str, maxLength) {\n       \t    if (str.length > maxLength) {\n       \t        return str.slice(0, maxLength) + '...';\n       \t    }\n       \t    return str;\n       \t}\n        \n        $(document).ready(function() {\n            $('.search-input').css('width', '320px');\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/demo/table/virtualScroll.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('表格虚拟滚动')\" />\n</head>\n<body class=\"gray-bg\">\n     <div class=\"container-div\">\n        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\n\t        <a class=\"btn btn-success\" onclick=\"loadRows()\">\n\t            <i class=\"fa fa-plus\"></i> 加载10000行数据\n\t        </a>\n\t        <a class=\"btn btn-info\" onclick=\"appendRows()\">\n\t            <i class=\"fa fa-edit\"></i> 追加10000行数据\n\t        </a>\n\t        &nbsp;&nbsp;<span id=\"total\" class=\"badge badge-success\"></span>\n        </div>\n        <div class=\"row\">\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\n\t\t\t\t<table id=\"bootstrap-table\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n    <div th:include=\"include :: footer\"></div>\n    <script>\n        var total = 0\n\n        $(function() {\n\t\t    var options = {\n\t    \t\tdata: getData(20),\n\t    \t\theight: 400,\n\t\t        sidePagination: \"client\",\n\t\t        pagination: false,\n\t\t        showSearch: false,\n\t\t        virtualScroll: true,\n                columns: [{\n\t\t\t\t\tfield : 'userId', \n\t\t\t\t\ttitle : '用户ID'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userCode', \n\t\t\t\t\ttitle : '用户编号'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userName', \n\t\t\t\t\ttitle : '用户姓名'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userPhone', \n\t\t\t\t\ttitle : '用户手机'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield : 'userEmail', \n\t\t\t\t\ttitle : '用户邮箱'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t    field : 'userBalance',\n\t\t\t\t    title : '用户余额'\n\t\t\t\t}]\n\t\t    };\n\t\t    $.table.init(options);\n\t\t});\n\n        function getData(number, isAppend) {\n            if (!isAppend) {\n                total = 0\n            }\n            var data = []\n            for (var i = total; i < total + number; i++) {\n                var randomId = 100 + ~~ (Math.random() * 100);\n                data.push({\n                    userId: i + 1,\n                    userCode: 2000000 + randomId,\n                    userName: '测试' + randomId,\n                    userPhone: '1588888888',\n                    userEmail: 'ry1@qq.com',\n                    userBalance: 10 + randomId,\n                })\n            }\n            if (isAppend) {\n                total += number\n            } else {\n                total = number\n            }\n            $('#total').text(total);\n            return data;\n        }\n\n        function loadRows() {\n            $('#bootstrap-table').bootstrapTable('load', getData(10000))\n        }\n\n        function appendRows() {\n            $('#bootstrap-table').bootstrapTable('append', getData(10000, true))\n        }\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/error/404.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>RuoYi - 404</title>\r\n    <link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"middle-box text-center animated fadeInDown\">\r\n        <h1>404</h1>\r\n        <h3 class=\"font-bold\">找不到网页！</h3>\r\n        <div class=\"error-desc\">\r\n                                对不起，您正在寻找的页面不存在。尝试检查URL的错误，然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容。\r\n            <a href=\"javascript:index()\" class=\"btn btn-primary m-t\">主页</a>\r\n        </div>\r\n    </div>\r\n    <script th:inline=\"javascript\">\r\n      var ctx = [[@{/}]];\r\n      function index() {\r\n    \t  window.top.location = ctx + \"index\";\r\n      }\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/error/500.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>RuoYi - 500</title>\r\n\t<link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"middle-box text-center animated fadeInDown\">\r\n        <h1>500</h1>\r\n        <h3 class=\"font-bold\">内部服务器错误！</h3>\r\n\r\n        <div class=\"error-desc\">\r\n                                服务器遇到意外事件，不允许完成请求。我们抱歉。您可以返回主页面。\r\n            <a href=\"javascript:index()\" class=\"btn btn-primary m-t\">主页</a>\r\n        </div>\r\n    </div>\r\n    <script th:inline=\"javascript\">\r\n      var ctx = [[@{/}]];\r\n      function index() {\r\n    \t  window.top.location = ctx + \"index\";\r\n      }\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/error/service.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>RuoYi - 500</title>\n\t<link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\n</head>\n<body class=\"gray-bg\">\n    <div class=\"middle-box text-center animated fadeInDown\">\n        <h3 class=\"font-bold\">操作异常！</h3>\n\n        <div class=\"error-desc\">\n            [[${errorMessage}]]\n        </div>\n    </div>\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/error/unauth.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>RuoYi - 403</title>\r\n\t<link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"middle-box text-center animated fadeInDown\">\r\n        <h1>403</h1>\r\n        <h3 class=\"font-bold\">您没有访问权限！</h3>\r\n\r\n        <div class=\"error-desc\">\r\n                                对不起，您没有访问权限，请不要进行非法操作！您可以返回主页面\r\n            <a href=\"javascript:index()\" class=\"btn btn-outline btn-primary btn-xs\">返回主页</a>\r\n        </div>\r\n    </div>\r\n    <script th:inline=\"javascript\">\r\n      var ctx = [[@{/}]];\r\n      function index() {\r\n    \t  window.top.location = ctx + \"index\";\r\n      }\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/include.html",
    "content": "<!-- 通用CSS -->\r\n<head th:fragment=header(title)>\r\n\t<meta charset=\"utf-8\">\r\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n\t<meta name=\"keywords\" content=\"\">\r\n\t<meta name=\"description\" content=\"\">\r\n\t<meta th:content=\"${session.csrf_token}\" name=\"csrf-token\"/>\r\n\t<title th:text=\"${title}\"></title>\r\n\t<link th:href=\"@{/css/bootstrap.min.css?v=3.4.1}\" rel=\"stylesheet\"/>\r\n\t<link th:href=\"@{/css/font-awesome.min.css?v=4.7.0}\" rel=\"stylesheet\"/>\r\n\t<!-- bootstrap-table 表格插件样式 -->\r\n\t<link th:href=\"@{/ajax/libs/bootstrap-table/bootstrap-table.min.css?v=1.24.1}\" rel=\"stylesheet\"/>\r\n\t<link th:href=\"@{/css/animate.min.css?v=20210831}\" rel=\"stylesheet\"/>\r\n\t<link th:href=\"@{/css/style.min.css?v=20250731}\" rel=\"stylesheet\"/>\r\n\t<link th:href=\"@{/ruoyi/css/ry-ui.css?v=4.8.2}\" rel=\"stylesheet\"/>\r\n</head>\r\n\r\n<!-- 通用JS -->\r\n<div th:fragment=\"footer\">\r\n    <script th:inline=\"javascript\"> var ctx = [[@{/}]]; var lockscreen = [[${session.lockscreen}]]; if(lockscreen){window.top.location=ctx+\"lockscreen\";} </script>\r\n    <a id=\"scroll-up\" href=\"javascript:;\" class=\"btn btn-sm display\"><i class=\"fa fa-angle-double-up\"></i></a>\r\n\t<script th:src=\"@{/js/jquery.min.js?v=3.7.1}\"></script>\r\n\t<script th:src=\"@{/js/bootstrap.min.js?v=3.4.1}\"></script>\r\n\t<!-- bootstrap-table 表格插件 -->\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/bootstrap-table.min.js?v=1.24.1}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/locale/bootstrap-table-zh-CN.min.js?v=1.24.1}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/mobile/bootstrap-table-mobile.js?v=1.24.1}\"></script>\r\n\t<!-- jquery-validate 表单验证插件 -->\r\n\t<script th:src=\"@{/ajax/libs/validate/jquery.validate.min.js?v=1.21.0}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/validate/jquery.validate.extend.js?v=1.21.0}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/validate/messages_zh.js?v=1.21.0}\"></script>\r\n\t<!-- bootstrap-table 表格树插件 -->\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/tree/bootstrap-table-tree.min.js?v=1.24.1}\"></script>\r\n\t<!-- 遮罩层 -->\r\n\t<script th:src=\"@{/ajax/libs/blockUI/jquery.blockUI.js?v=2.70.0}\"></script>\r\n    <script th:src=\"@{/ajax/libs/iCheck/icheck.min.js?v=1.0.3}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/layer/layer.min.js?v=3.7.0}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/layui/layui.min.js?v=2.8.18}\"></script>\r\n\t<script th:src=\"@{/ruoyi/js/common.js?v=4.8.2}\"></script>\r\n\t<script th:src=\"@{/ruoyi/js/ry-ui.js?v=4.8.2}\"></script>\r\n</div>\r\n\r\n<!-- ztree树插件 -->\r\n<div th:fragment=\"ztree-css\">\r\n    <link th:href=\"@{/ajax/libs/jquery-ztree/3.5/css/metro/zTreeStyle.css}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"ztree-js\">\r\n    <script th:src=\"@{/ajax/libs/jquery-ztree/3.5/js/jquery.ztree.all-3.5.js}\"></script>\r\n</div>\r\n\r\n<!-- select2下拉框插件 -->\r\n<div th:fragment=\"select2-css\">\r\n    <link th:href=\"@{/ajax/libs/select2/select2.min.css?v=4.0.13}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/ajax/libs/select2/select2-bootstrap.min.css?v=4.0.13}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"select2-js\">\r\n    <script th:src=\"@{/ajax/libs/select2/select2.min.js?v=4.0.13}\"></script>\r\n</div>\r\n\r\n<!-- bootstrap-select下拉框插件 -->\r\n<div th:fragment=\"bootstrap-select-css\">\r\n    <link th:href=\"@{/ajax/libs/bootstrap-select/bootstrap-select.min.css?v=1.13.18}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"bootstrap-select-js\">\r\n    <script th:src=\"@{/ajax/libs/bootstrap-select/bootstrap-select.min.js?v=1.13.18}\"></script>\r\n</div>\r\n\r\n<!-- datetimepicker日期和时间插件 -->\r\n<div th:fragment=\"datetimepicker-css\">\r\n    <link th:href=\"@{/ajax/libs/datapicker/bootstrap-datetimepicker.min.css?v=2.4.4}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"datetimepicker-js\">\r\n    <script th:src=\"@{/ajax/libs/datapicker/bootstrap-datetimepicker.min.js?v=2.4.4}\"></script>\r\n</div>\r\n\r\n<!-- ui布局插件 -->\r\n<div th:fragment=\"layout-latest-css\">\r\n    <link th:href=\"@{/ajax/libs/jquery-layout/jquery.layout-latest.css?v=1.4.4}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"layout-latest-js\">\r\n    <script th:src=\"@{/ajax/libs/jquery-layout/jquery.layout-latest.js?v=1.4.4}\"></script>\r\n</div>\r\n\r\n<!-- summernote富文本编辑器插件 -->\r\n<div th:fragment=\"summernote-css\">\r\n    <link th:href=\"@{/ajax/libs/summernote/summernote.css?v=0.8.18}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"summernote-js\">\r\n    <script th:src=\"@{/ajax/libs/summernote/summernote.min.js?v=0.8.18}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/summernote/summernote-zh-CN.js?v=0.8.18}\"></script>\r\n</div>\r\n\r\n<!-- cropper图像裁剪插件 -->\r\n<div th:fragment=\"cropper-css\">\r\n    <link th:href=\"@{/ajax/libs/cropper/cropper.min.css?v=1.5.12}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"cropper-js\">\r\n    <script th:src=\"@{/ajax/libs/cropper/cropper.min.js?v=1.5.12}\"></script>\r\n</div>\r\n\r\n<!-- jasny功能扩展插件 -->\r\n<div th:fragment=\"jasny-bootstrap-css\">\r\n    <link th:href=\"@{/ajax/libs/jasny/jasny-bootstrap.min.css?v=3.1.3}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"jasny-bootstrap-js\">\r\n    <script th:src=\"@{/ajax/libs/jasny/jasny-bootstrap.min.js?v=3.1.3}\"></script>\r\n</div>\r\n\r\n<!-- fileinput文件上传插件 -->\r\n<div th:fragment=\"bootstrap-fileinput-css\">\r\n    <link th:href=\"@{/ajax/libs/bootstrap-fileinput/fileinput.min.css?v=5.5.4}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"bootstrap-fileinput-js\">\r\n    <script th:src=\"@{/ajax/libs/bootstrap-fileinput/fileinput.min.js?v=5.5.4}\"></script>\r\n</div>\r\n\r\n<!-- duallistbox双列表框插件 -->\r\n<div th:fragment=\"bootstrap-duallistbox-css\">\r\n    <link th:href=\"@{/ajax/libs/duallistbox/bootstrap-duallistbox.min.css?v=3.0.9}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"bootstrap-duallistbox-js\">\r\n    <script th:src=\"@{/ajax/libs/duallistbox/bootstrap-duallistbox.min.js?v=3.0.9}\"></script>\r\n</div>\r\n\r\n<!-- suggest搜索自动补全 -->\r\n<div th:fragment=\"bootstrap-suggest-js\">\r\n    <script th:src=\"@{/ajax/libs/suggest/bootstrap-suggest.min.js?v=0.1.29}\"></script>\r\n</div>\r\n\r\n<!-- typeahead搜索自动补全 -->\r\n<div th:fragment=\"bootstrap-typeahead-js\">\r\n    <script th:src=\"@{/ajax/libs/typeahead/bootstrap-typeahead.min.js?v=4.0.2}\"></script>\r\n</div>\r\n\r\n<!-- 多级联动下拉 -->\r\n<div th:fragment=\"jquery-cxselect-js\">\r\n    <script th:src=\"@{/ajax/libs/cxselect/jquery.cxselect.min.js?v=1.4.2}\"></script>\r\n</div>\r\n\r\n<!-- jsonview格式化和语法高亮JSON格式数据查看插件 -->\r\n<div th:fragment=\"jsonview-css\">\r\n    <link th:href=\"@{/ajax/libs/jsonview/jquery.jsonview.css?v=1.2.0}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"jsonview-js\">\r\n    <script th:src=\"@{/ajax/libs/jsonview/jquery.jsonview.js?v=1.2.0}\"></script>\r\n</div>\r\n\r\n<!-- jquery.smartwizard表单向导插件 -->\r\n<div th:fragment=\"jquery-smartwizard-css\">\r\n    <link th:href=\"@{/ajax/libs/smartwizard/smart_wizard_all.min.css?v=5.1.1}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"jquery-smartwizard-js\">\r\n    <script th:src=\"@{/ajax/libs/smartwizard/jquery.smartWizard.min.js?v=5.1.1}\"></script>\r\n</div>\r\n\r\n<!-- ECharts百度统计图表插件 -->\r\n<div th:fragment=\"echarts-js\">\r\n    <script th:src=\"@{/ajax/libs/report/echarts/echarts-all.min.js?v=4.2.1}\"></script>\r\n</div>\r\n\r\n<!-- peity图表组合插件 -->\r\n<div th:fragment=\"peity-js\">\r\n    <script th:src=\"@{/ajax/libs/report/peity/jquery.peity.min.js?v=2.0.3}\"></script>\r\n</div>\r\n\r\n<!-- sparkline线状图插件 -->\r\n<div th:fragment=\"sparkline-js\">\r\n    <script th:src=\"@{/ajax/libs/report/sparkline/jquery.sparkline.min.js?v=2.1.2}\"></script>\r\n</div>\r\n\r\n<!-- 表格行拖拽插件 -->\r\n<div th:fragment=\"bootstrap-table-reorder-rows-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/reorder-rows/bootstrap-table-reorder-rows.js?v=1.24.1}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/reorder-rows/jquery.tablednd.js?v=1.0.3}\"></script>\r\n</div>\r\n\r\n<!-- 表格列拖拽插件 -->\r\n<div th:fragment=\"bootstrap-table-reorder-columns-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/reorder-columns/jquery.dragtable.js?v=5.3.5}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/reorder-columns/bootstrap-table-reorder-columns.js?v=1.24.1}\"></script>\r\n</div>\r\n\r\n<!-- 表格列宽拖动插件 -->\r\n<div th:fragment=\"bootstrap-table-resizable-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/resizable/jquery.resizableColumns.min.js?v=0.1.0}\"></script>\r\n    <script th:src=\"@{/ajax/libs/bootstrap-table/extensions/resizable/bootstrap-table-resizable.js?v=1.24.1}\"></script>\r\n</div>\r\n\r\n<!-- 表格行内编辑插件 -->\r\n<div th:fragment=\"bootstrap-editable-css\">\r\n    <link th:href=\"@{/ajax/libs/bootstrap-table/extensions/editable/bootstrap-editable.css?v=1.5.1}\" rel=\"stylesheet\"/>\r\n</div>\r\n<div th:fragment=\"bootstrap-table-editable-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/editable/bootstrap-editable.min.js?v=1.5.1}\"></script>\r\n    <script th:src=\"@{/ajax/libs/bootstrap-table/extensions/editable/bootstrap-table-editable.js?v=1.24.1}\"></script>\r\n</div>\r\n\r\n<!-- 表格导出插件 -->\r\n<div th:fragment=\"bootstrap-table-export-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/export/bootstrap-table-export.js?v=1.24.1}\"></script>\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/export/tableExport.min.js?v=1.10.24}\"></script>\r\n</div>\r\n\r\n<!-- 表格冻结列插件 -->\r\n<div th:fragment=\"bootstrap-table-fixed-columns-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/columns/bootstrap-table-fixed-columns.js?v=1.24.1}\"></script>\r\n</div>\r\n\r\n<!-- 表格自动刷新插件 -->\r\n<div th:fragment=\"bootstrap-table-auto-refresh-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/auto-refresh/bootstrap-table-auto-refresh.js?v=1.24.1}\"></script>\r\n</div>\r\n\r\n<!-- 表格打印插件 -->\r\n<div th:fragment=\"bootstrap-table-print-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/print/bootstrap-table-print.js?v=1.24.1}\"></script>\r\n</div>\r\n\r\n<!-- 表格视图分页插件 -->\r\n<div th:fragment=\"bootstrap-table-custom-view-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/custom-view/bootstrap-table-custom-view.js?v=1.24.1}\"></script>\r\n</div>\r\n\r\n<!-- 表格保存状态插件 -->\r\n<div th:fragment=\"bootstrap-table-cookie-js\">\r\n\t<script th:src=\"@{/ajax/libs/bootstrap-table/extensions/cookie/bootstrap-table-cookie.js?v=1.24.1}\"></script>\r\n</div>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/index-topnav.html",
    "content": "<!DOCTYPE html>\r\n<html  lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <meta name=\"renderer\" content=\"webkit\">\r\n    <title>若依系统首页</title>\r\n    <!-- 避免IE使用兼容模式 -->\r\n \t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n    <link th:href=\"@{favicon.ico}\" rel=\"shortcut icon\"/>\r\n    <link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/jquery.contextMenu.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/skins.css?v=20200902}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/ruoyi/css/ry-ui.css?v=4.8.2}\" rel=\"stylesheet\"/>\r\n    <style type=\"text/css\">.fixed-sidebar .nav:not(.navbar-toolbar)>li.active{border-left:0px!important;}#noticeItems li a{transition:background .15s;border-radius:2px}#noticeItems li a:hover{background:#f7f9fb;text-decoration:none}#noticeItems li a:active{background:#eef2f7}#noticeItems li a:focus{background:transparent;outline:0}#noticeList .mark-all-read{font-size:12px;color:#5b9bd5;text-decoration:none;padding:2px 8px;border-radius:3px;transition:background 0.15s}#noticeList .mark-all-read:hover{background:#eef5fc;color:#2b7cc1}#noticeList .mark-all-read:active{background:#eef5fc;color:#2b7cc1}#noticeList .mark-all-read:focus{outline:none;background:transparent}\r\n</style>\r\n<body class=\"fixed-sidebar full-height-layout gray-bg\" th:classappend=\"${isMobile} ? 'canvas-menu'\" style=\"overflow: hidden\">\r\n<div id=\"wrapper\">\r\n\r\n    <!--左侧导航开始-->\r\n    <nav class=\"navbar-default navbar-static-side\" role=\"navigation\">\r\n        <div class=\"nav-close\">\r\n            <i class=\"fa fa-times-circle\"></i>\r\n        </div>\r\n        <a th:href=\"@{/index}\">\r\n            <li class=\"logo hidden-xs\">\r\n                <span class=\"logo-lg\">RuoYi</span>\r\n            </li>\r\n         </a>\r\n        <div class=\"sidebar-collapse tab-content\" id=\"side-menu\">\r\n\t\t\t<div class=\"user-panel\">\r\n\t\t\t\t<a class=\"menuItem noactive\" title=\"个人中心\" th:href=\"@{/system/user/profile}\">\r\n\t\t\t\t\t<div class=\"hide\" th:text=\"个人中心\"></div>\r\n\t\t\t\t\t<div class=\"pull-left image\">\r\n\t\t\t\t\t\t<img th:src=\"(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}\" th:onerror=\"this.src='img/profile.jpg'\" class=\"img-circle\" alt=\"User Image\">\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</a>\r\n\t\t\t\t<div class=\"pull-left info\">\r\n\t\t\t\t  <p>[[${user.loginName}]]</p>\r\n\t\t\t\t  <a href=\"javascript:;\"><i class=\"fa fa-circle text-success\"></i> 在线</a>\r\n\t\t\t\t  <a th:href=\"@{logout}\" style=\"padding-left:5px;\"><i class=\"fa fa-sign-out text-danger\"></i> 注销</a>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t\r\n            <!-- 左侧菜单 -->\r\n\t\t\t<th:block th:each=\"menu : ${menus}\">\r\n\t\t\t<div class=\"tab-pane fade height-full\" th:id=\"|menu_${menu.menuId}|\">\r\n\t\t\t  <ul class=\"nav\">\r\n                <li th:each=\"cmenu : ${menu.children}\">\r\n\t\t\t      <a class=\"menu-content\" th:if=\"${#lists.isEmpty(cmenu.children)}\" th:href=\"@{${cmenu.url}}\" th:classappend=\"${#strings.isEmpty(cmenu.target)} ? |menuItem| : ${cmenu.target}\" th:data-refresh=\"${cmenu.isRefresh == '0'}\">\r\n\t\t\t        <i th:class=\"${cmenu.icon} + ' fa-fw'\"></i> <span class=\"nav-label\">[[${cmenu.menuName}]]</span>\r\n\t\t\t      </a>\r\n\t\t\t      <a class=\"menu-content\" th:if=\"${not #lists.isEmpty(cmenu.children)}\" href=\"javascript:;\">\r\n\t\t\t        <i th:class=\"${cmenu.icon} + ' fa-fw'\"></i>\r\n\t\t\t        <span class=\"nav-label\">[[${cmenu.menuName}]]</span>\r\n\t\t\t        <span class=\"fa arrow\"></span>\r\n                  </a>\r\n\t\t\t\t  <ul th:if=\"${not #lists.isEmpty(cmenu.children)}\" class=\"nav nav-second-level collapse\">\r\n\t\t\t\t    <li th:each=\"emenu : ${cmenu.children}\">\r\n\t\t\t\t      <a th:if=\"${#lists.isEmpty(emenu.children)}\" th:href=\"@{${emenu.url}}\" th:class=\"${#strings.isEmpty(emenu.target)} ? |menuItem| : ${emenu.target}\" th:data-refresh=\"${emenu.isRefresh == '0'}\">\r\n\t\t\t\t        <i th:class=\"${emenu.icon} + ' fa-fw'\"></i> \r\n\t\t\t\t        [[${emenu.menuName}]]\r\n\t\t\t\t      </a>\r\n\t\t\t\t      <a th:if=\"${not #lists.isEmpty(emenu.children)}\" href=\"javascript:;\">\r\n\t\t\t\t        <i th:class=\"${emenu.icon} + ' fa-fw'\"></i> \r\n\t\t\t\t        [[${emenu.menuName}]]\r\n\t\t\t\t        <span class=\"fa arrow\"></span>\r\n\t\t\t\t      </a>\r\n\t\t\t\t      <ul th:if=\"${not #lists.isEmpty(emenu.children)}\" class=\"nav nav-third-level collapse\">\r\n\t\t\t\t        <li th:each=\"fmenu : ${emenu.children}\"><a th:if=\"${#lists.isEmpty(fmenu.children)}\" th:class=\"${#strings.isEmpty(fmenu.target)} ? |menuItem| : ${fmenu.target}\" th:href=\"@{${fmenu.url}}\" th:data-refresh=\"${fmenu.isRefresh == '0'}\">[[${fmenu.menuName}]]</a></li>\r\n\t\t\t\t      </ul>\r\n\t\t\t\t    </li>\r\n\t\t\t\t  </ul>\r\n                </li>\r\n\t\t\t  </ul>\r\n\t\t\t</div>\r\n\t\t\t</th:block>\r\n\t\t\t\r\n\t\t\t<!-- 首页菜单 -->\r\n\t\t\t<div class=\"tab-pane fade height-full\" id=\"index\">\r\n\t\t\t  <ul class=\"nav\">\r\n\t\t\t    <li>\r\n\t\t\t      <a class=\"menuItem\" th:href=\"@{/system/main}\">\r\n\t\t\t      <i class=\"fa fa-home\"></i> <span class=\"nav-label\">首页</span></a>\r\n\t\t\t    </li>\r\n\t\t\t  </ul>\r\n\t\t\t</div>\r\n\t\t\t\r\n            <!-- 实例演示菜单 -->\r\n\t\t\t<div class=\"tab-pane fade height-full\" id=\"demo\" th:if=\"${demoEnabled}\">\r\n\t\t\t  <ul class=\"nav\">\r\n\t\t\t    <li>\r\n\t\t\t      <a href=\"javascript:;\"><i class=\"fa fa-edit\"></i> <span class=\"nav-label\">表单</span><span class=\"fa arrow\"></span></a>\r\n\t\t\t      <ul class=\"nav nav-second-level collapse\">\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/button}\">按钮</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/grid}\">栅格</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/select}\">下拉框</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/timeline}\">时间轴</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/progress_bars}\">进度条</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/basic}\">基本表单</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/cards}\">卡片列表</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/jasny}\">功能扩展</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/sortable}\">拖动排序</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/invoice}\">单据打印</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/labels_tips}\">标签 & 提示</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/tabs_panels}\">选项卡 & 面板</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/validate}\">表单校验</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/wizard}\">表单向导</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/upload}\">文件上传</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/datetime}\">日期和时间</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/summernote}\">富文本编辑器</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/duallistbox}\">左右互选组件</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/autocomplete}\">搜索自动补全</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/cxselect}\">多级联动下拉</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/localrefresh}\">Ajax局部刷新</a></li>\r\n\t\t\t      </ul>\r\n\t\t\t    </li>\r\n\t\t\t    <li>\r\n\t\t\t      <a href=\"javascript:;\"><i class=\"fa fa-table\"></i> <span class=\"nav-label\">表格</span><span class=\"fa arrow\"></span></a>\r\n\t\t\t      <ul class=\"nav nav-second-level collapse\">\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/search}\">查询条件</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/footer}\">数据汇总</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/groupHeader}\">组合表头</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/export}\">表格导出</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/textSearch}\">全文索引</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/exportSelected}\">导出选择列</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/remember}\">翻页记住选择</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/cookie}\">表格保存状态</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/pageGo}\">跳转至指定页</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/params}\">自定义查询参数</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/multi}\">初始多表格</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/button}\">点击按钮加载表格</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/data}\">直接加载表格数据</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/fixedColumns}\">表格冻结列</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/event}\">自定义触发事件</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/headerStyle}\">表格标题格式化</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/detail}\">表格细节视图</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/child}\">表格父子视图</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/image}\">表格图片预览</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/curd}\">动态增删改查</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/reorderRows}\">表格行拖拽操作</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/reorderColumns}\">表格列拖拽操作</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/resizable}\">表格列宽拖动</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/editable}\">表格行内编辑</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/subdata}\">主子表提交</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/refresh}\">表格自动刷新</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/print}\">表格打印配置</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/dynamicColumns}\">表格动态列</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/virtualScroll}\">表格虚拟滚动</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/customView}\">自定义视图分页</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/asynTree}\">异步加载表格树</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/other}\">表格其他操作</a></li>\r\n\t\t\t      </ul>\r\n\t\t\t    </li>\r\n\t\t\t    <li>\r\n\t\t\t      <a href=\"javascript:;\"><i class=\"fa fa-flask\"></i> <span class=\"nav-label\">弹框</span><span class=\"fa arrow\"></span></a>\r\n\t\t\t      <ul class=\"nav nav-second-level collapse\">\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/modal/dialog}\">模态窗口</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/modal/layer}\">弹层组件</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/modal/table}\">弹层表格</a></li>\r\n\t\t\t      </ul>\r\n\t\t\t    </li>\r\n\t\t\t    <li>\r\n\t\t\t      <a href=\"javascript:;\"><i class=\"fa fa-wpforms\"></i> <span class=\"nav-label\">操作</span><span class=\"fa arrow\"></span></a>\r\n\t\t\t      <ul class=\"nav nav-second-level collapse\">\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/operate/table}\">表格</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/operate/other}\">其他</a></li>\r\n\t\t\t      </ul>\r\n\t\t\t    </li>\r\n\t\t\t    <li>\r\n\t\t\t      <a href=\"javascript:;\"><i class=\"fa fa-bar-chart-o\"></i> <span class=\"nav-label\">报表</span><span class=\"fa arrow\"></span></a>\r\n\t\t\t      <ul class=\"nav nav-second-level collapse\">\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/echarts}\">百度ECharts</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/peity}\">peity</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/sparkline}\">sparkline</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/metrics}\">图表组合</a></li>\r\n\t\t\t      </ul>\r\n\t\t\t    </li>\r\n\t\t\t    <li>\r\n\t\t\t      <a href=\"javascript:;\"><i class=\"fa fa-book\"></i> <span class=\"nav-label\">图标</span><span class=\"fa arrow\"></span></a>\r\n\t\t\t      <ul class=\"nav nav-second-level collapse\">\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/icon/fontawesome}\">Font Awesome</a></li>\r\n\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/icon/glyphicons}\">Glyphicons</a></li>\r\n\t\t\t      </ul>\r\n\t\t\t    </li>\r\n\t\t\t    <li>\r\n\t\t\t      <a href=\"javascript:;\"><i class=\"fa fa-navicon\"></i> <span class=\"nav-label\">四层菜单</span><span class=\"fa arrow\"></span></a>\r\n\t\t\t      <ul class=\"nav nav-second-level collapse\">\r\n\t\t\t\t\t<li>\r\n\t\t\t\t\t\t<a href=\"javascript:;\" id=\"damian\">三级菜单1<span class=\"fa arrow\"></span></a>\r\n\t\t\t\t\t\t<ul class=\"nav nav-third-level collapse\">\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a href=\"javascript:;\">四级菜单1</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a href=\"javascript:;\">四级菜单2</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</li>\r\n\t\t\t\t\t<li><a href=\"javascript:;\">三级菜单2</a></li>\r\n\t\t\t      </ul>\r\n\t\t\t    </li>\r\n\t\t\t  </ul>\r\n\t\t\t</div>\r\n        </div>\r\n    </nav>\r\n    <!--左侧导航结束-->\r\n\r\n    <!--右侧部分开始-->\r\n    <div id=\"page-wrapper\" class=\"gray-bg dashbard-1\">\r\n        <div class=\"row border-bottom\">\r\n            <nav class=\"navbar navbar-static-top\" role=\"navigation\" style=\"margin-bottom: 0\">\r\n                <div class=\"navbar-header\">\r\n                    <a class=\"navbar-minimalize minimalize-styl-2\" style=\"color:#FFF;\" href=\"javascript:;\" title=\"收起菜单\">\r\n                    \t<i class=\"fa fa-bars\"></i>\r\n                    </a>\r\n                </div>\r\n                <!-- 顶部栏 -->\r\n                <div id=\"navMenu\">\r\n                  <ul class=\"nav navbar-toolbar nav-tabs navbar-left hidden-xs\">\r\n                    \r\n                    <!-- 顶部菜单列表 -->\r\n\t                <th:block th:each=\"menu : ${menus}\">\r\n               \t    <li role=\"presentation\" th:id=\"|tab_${menu.menuId}|\">\r\n               \t        <a th:if=\"${#lists.isEmpty(menu.children)}\" data-toggle=\"tab\" th:class=\"@{${!#strings.isEmpty(menu.target) && menu.target == 'menuBlank'} ? 'menuBlank' : 'menuItem noactive'}\" th:href=\"@{${menu.url}}\">\r\n                            <i th:class=\"${menu.icon}\"></i> <span>[[${menu.menuName}]]</span>\r\n                        </a>\t\r\n                        <a th:if=\"${not #lists.isEmpty(menu.children)}\" data-toggle=\"tab\" th:class=\"@{${!#strings.isEmpty(menu.target) && menu.target == 'menuBlank'} ? 'menuBlank'}\" th:href=\"@{${!#strings.isEmpty(menu.target) && menu.target == 'menuBlank'} ? @{${menu.url}} : |#menu_${menu.menuId}|}\">\r\n                            <i th:class=\"${menu.icon}\"></i> <span>[[${menu.menuName}]]</span>\r\n                        </a>\r\n                    </li>\r\n\t                </th:block>\r\n\t                \r\n\t                <li role=\"presentation\" id=\"tab_index\">\r\n                      <a data-toggle=\"tab\" href=\"#index\">\r\n                        <i class=\"fa fa-area-chart\"></i> <span>统计报表</span>\r\n                      </a>\r\n                    </li>\r\n                    \r\n                    <li role=\"presentation\" id=\"tab_demo\" th:if=\"${demoEnabled}\">\r\n                      <a data-toggle=\"tab\" href=\"#demo\">\r\n                        <i class=\"fa fa-desktop\"></i> <span>实例演示</span>\r\n                      </a>\r\n                    </li>\r\n\t\t\t\t  </ul>\r\n\t\t\t\t</div>\r\n                <!-- 右侧栏 -->\r\n                <ul class=\"nav navbar-top-links navbar-right welcome-message\">\r\n                    <li><a data-toggle=\"tooltip\" data-trigger=\"hover\" data-placement=\"bottom\" title=\"开发文档\" href=\"http://doc.ruoyi.vip/ruoyi\" target=\"_blank\"><i class=\"fa fa-question-circle\"></i> 文档</a></li>\r\n                    <li><a data-toggle=\"tooltip\" data-trigger=\"hover\" data-placement=\"bottom\" title=\"锁定屏幕\" href=\"javascript:;\" id=\"lockScreen\"><i class=\"fa fa-lock\"></i> 锁屏</a></li>\r\n\t                <li><a data-toggle=\"tooltip\" data-trigger=\"hover\" data-placement=\"bottom\" title=\"全屏显示\" href=\"javascript:;\" id=\"fullScreen\"><i class=\"fa fa-arrows-alt\"></i> 全屏</a></li>\r\n                    <li class=\"dropdown\" id=\"noticeDropdown\">\r\n                        <a href=\"javascript:void(0)\" class=\"dropdown-toggle\" style=\"position:relative;\" data-hover=\"dropdown\">\r\n                            <i class=\"fa fa-bell-o\"></i> 消息\r\n                            <span id=\"noticeBadge\" style=\"display:none;position:absolute;top:8px;right:-4px;background:#e74c3c;color:#fff;border-radius:50%;width:16px;height:16px;font-size:10px;line-height:16px;text-align:center;font-style:normal;\"></span>\r\n                        </a>\r\n                        <ul class=\"dropdown-menu\" id=\"noticeList\" style=\"width:320px;padding:0;left:auto;right:0;\">\r\n                            <li style=\"padding:10px 16px;background:#f7f9fb;border-bottom:1px solid #eee;display:flex;align-items:center;justify-content:space-between;\">\r\n                                <span style=\"font-size:13px;font-weight:600;color:#333;\">通知公告</span>\r\n                                <a href=\"javascript:void(0)\" onclick=\"markAllRead()\" class=\"mark-all-read\">全部已读</a>\r\n                            </li>\r\n                            <li id=\"noticeItems\"><div style=\"padding:20px;text-align:center;color:#aaa;font-size:12px;\"><i class=\"fa fa-spinner fa-spin\"></i> 加载中...</div></li>\r\n                        </ul>\r\n                    </li>\r\n                    <li class=\"dropdown user-menu\">\r\n\t\t\t\t\t\t<a href=\"javascript:void(0)\" class=\"dropdown-toggle\" data-hover=\"dropdown\">\r\n\t\t\t\t\t\t\t<img th:src=\"(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}\" th:onerror=\"this.src='img/profile.jpg'\" class=\"user-image\">\r\n\t\t\t\t\t\t\t<span class=\"hidden-xs\">[[${#strings.defaultString(user.userName, '-')}]]</span>\r\n\t\t\t\t\t\t</a>\r\n\t\t\t\t\t\t<ul class=\"dropdown-menu\">\r\n\t\t\t\t\t\t\t<li class=\"mt5\">\r\n\t\t\t\t\t\t\t\t<a th:href=\"@{/system/user/profile}\" class=\"menuItem noactive\">\r\n\t\t\t\t\t\t\t\t<i class=\"fa fa-user\"></i> 个人中心</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a onclick=\"resetPwd()\">\r\n\t\t\t\t\t\t\t\t<i class=\"fa fa-key\"></i> 修改密码</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a onclick=\"switchSkin()\">\r\n\t\t\t\t\t\t\t\t<i class=\"fa fa-dashboard\"></i> 切换主题</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a onclick=\"toggleMenu()\">\r\n\t\t\t\t\t\t\t\t<i class=\"fa fa-toggle-off\"></i> 左侧菜单</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"divider\"></li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a th:href=\"@{logout}\">\r\n\t\t\t\t\t\t\t\t<i class=\"fa fa-sign-out\"></i> 退出登录</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</li>\r\n                </ul>\r\n            </nav>\r\n        </div>\r\n        <div class=\"row content-tabs\" th:classappend=\"${#bools.isFalse(tagsView)} ? |hide|\">\r\n            <button class=\"roll-nav roll-left tabLeft\">\r\n                <i class=\"fa fa-backward\"></i>\r\n            </button>\r\n            <nav class=\"page-tabs menuTabs\">\r\n                <div class=\"page-tabs-content\">\r\n                    <a href=\"javascript:;\" class=\"menuTab\" th:data-id=\"@{/system/main}\">首页</a>\r\n                </div>\r\n            </nav>\r\n            <button class=\"roll-nav roll-right tabRight\">\r\n                <i class=\"fa fa-forward\"></i>\r\n            </button>\r\n            <a href=\"javascript:void(0);\" class=\"roll-nav roll-right tabReload\"><i class=\"fa fa-refresh\"></i> 刷新</a>\r\n        </div>\r\n\r\n        <a id=\"ax_close_max\" class=\"ax_close_max\" href=\"javascript:;\" title=\"关闭全屏\"> <i class=\"fa fa-times-circle-o\"></i> </a>\r\n\r\n        <div class=\"row mainContent\" id=\"content-main\" th:classappend=\"${mainClass}\">\r\n            <iframe class=\"RuoYi_iframe\" name=\"iframe0\" width=\"100%\" height=\"100%\" th:data-id=\"@{/system/main}\"\r\n                frameborder=\"0\" seamless></iframe>\r\n        </div>\r\n        \r\n        <div th:if=\"${footer}\" class=\"footer\">\r\n            <div class=\"pull-right\">© [[${copyrightYear}]] RuoYi Copyright </div>\r\n        </div>\r\n    </div>\r\n    <!--右侧部分结束-->\r\n</div>\r\n<!-- 全局js -->\r\n<script th:src=\"@{/js/jquery.min.js}\"></script>\r\n<script th:src=\"@{/js/bootstrap.min.js}\"></script>\r\n<script th:src=\"@{/js/plugins/metisMenu/jquery.metisMenu.js}\"></script>\r\n<script th:src=\"@{/js/plugins/slimscroll/jquery.slimscroll.min.js}\"></script>\r\n<script th:src=\"@{/js/jquery.contextMenu.min.js}\"></script>\r\n<script th:src=\"@{/ajax/libs/blockUI/jquery.blockUI.js}\"></script>\r\n<script th:src=\"@{/ajax/libs/layer/layer.min.js}\"></script>\r\n<script th:src=\"@{/ruoyi/js/ry-ui.js?v=4.8.2}\"></script>\r\n<script th:src=\"@{/ruoyi/js/common.js?v=4.8.2}\"></script>\r\n<script th:src=\"@{/ruoyi/index.js?v=20201208}\"></script>\r\n<script th:src=\"@{/ajax/libs/fullscreen/jquery.fullscreen.js}\"></script>\r\n<script th:src=\"@{/js/resize-tabs.js}\"></script>\r\n<script th:inline=\"javascript\">\r\nwindow.history.forward(1);\r\nvar ctx = [[@{/}]]; \r\nvar lockscreen = [[${session.lockscreen}]]; \r\nif(lockscreen){window.top.location=ctx+\"lockscreen\";}\r\n// 皮肤缓存\r\nvar skin = storage.get(\"skin\");\r\n// history（表示去掉地址的#）否则地址以\"#\"形式展示\r\nvar mode = \"history\";\r\n// 历史访问路径缓存\r\nvar historyPath = storage.get(\"historyPath\");\r\n// 是否页签与菜单联动\r\nvar isLinkage = true;\r\n// 是否页签切换滚动到顶部\r\nvar isScrollToTop = true;\r\n\r\n// 本地主题优先，未设置取系统配置\r\nif($.common.isNotEmpty(skin)){\r\n\t$(\"body\").addClass(skin.split('|')[0]);\r\n\t$(\"body\").addClass(skin.split('|')[1]);\r\n} else {\r\n\t$(\"body\").addClass([[${sideTheme}]]);\r\n\t$(\"body\").addClass([[${skinName}]]);\r\n}\r\n\r\n/* 用户管理-重置密码 */\r\nfunction resetPwd() {\r\n    var url = ctx + 'system/user/profile/resetPwd';\r\n    $.modal.open(\"重置密码\", url, '770', '380');\r\n}\r\n/* 切换主题 */\r\nfunction switchSkin() {\r\n    layer.open({\r\n\t\ttype : 2,\r\n\t\tshadeClose : true,\r\n\t\ttitle : \"切换主题\",\r\n\t\tarea : [\"530px\", \"386px\"],\r\n\t\tcontent : [ctx + \"system/switchSkin\", 'no']\r\n\t})\r\n}\r\n\r\n/* 切换菜单 */\r\nfunction toggleMenu() {\r\n\t$.modal.confirm(\"确认要切换成左侧菜单吗？\", function() {\r\n\t\t$.get(ctx + 'system/menuStyle/default', function(result) {\r\n            window.location.reload();\r\n\t    });\r\n\t})\r\n}\r\n\r\n/** 刷新时访问路径页签 */\r\nfunction applyPath(url) {\r\n\tvar $dataObj = $('a[href$=\"' + decodeURI(url) + '\"]');\r\n\t$dataObj.click();\r\n\tif (!$dataObj.hasClass(\"noactive\")) {\r\n\t    $dataObj.parent(\"li\").addClass(\"selected\").parents(\"li\").addClass(\"active\").end().parents(\"ul\").addClass(\"in\");\r\n\t}\r\n\t// 顶部菜单同步处理\r\n    var tabStr = $dataObj.parents(\".tab-pane\").attr(\"id\");\r\n    if ($.common.isNotEmpty(tabStr)) {\r\n        var sepIndex = tabStr.lastIndexOf('_');\r\n        var menuId = tabStr.substring(sepIndex + 1, tabStr.length);\r\n        $(\"#tab_\" + menuId + \" a\").click();\r\n    }\r\n}\r\n\r\n//默认激活页签（首页）\r\nfunction tabActive() {\r\n    var $mainTab = $('.menuTab[data-id=\"' + ctx + 'system/main\"]');\r\n    $mainTab.addClass('active');\r\n    // 懒加载：首次激活首页时才设置 src 并显示\r\n    var $mainIframe = $('.mainContent .RuoYi_iframe[data-id=\"' + ctx + 'system/main\"]');\r\n    if ($mainIframe.length) {\r\n        openToCurrentTab($mainIframe[0]);\r\n    }\r\n}\r\n\r\n$(function() {\r\n\tvar lockPath = storage.get('lockPath');\r\n\tif($.common.equals(\"history\", mode) && window.performance.navigation.type == 1) {\r\n\t\tvar url = storage.get('publicPath');\r\n\t    if ($.common.isNotEmpty(url)) {\r\n\t    \tapplyPath(url);\r\n\t    } else {\r\n\t        tabActive();\r\n\t    \t$(\".navbar-toolbar li a\").eq(0).click();\r\n\t    }\r\n\t} else if($.common.isNotEmpty(lockPath)) {\r\n\t    applyPath(lockPath);\r\n\t    storage.remove('lockPath');\r\n\t} else {\r\n\t\tvar hash = location.hash;\r\n\t    if ($.common.isNotEmpty(hash)) {\r\n\t        var url = hash.substring(1, hash.length);\r\n\t        applyPath(url);\r\n\t    } else {\r\n\t    \tif($.common.equals(\"history\", mode)) {\r\n\t    \t\tstorage.set('publicPath', \"\");\r\n\t    \t}\r\n\t        tabActive();\r\n\t    \t$(\".navbar-toolbar li a\").eq(0).click();\r\n\t    }\r\n\t}\r\n\t\r\n\t/* 初始密码提示 */\r\n\tif([[${isDefaultModifyPwd}]]) {\r\n\t\tlayer.confirm(\"您的密码还是初始密码，请修改密码！\", {\r\n\t\t\ticon: 0,\r\n\t\t\ttitle: \"安全提示\",\r\n\t\t\tbtn: ['确认'\t, '取消'],\r\n\t\t\toffset: ['30%']\r\n\t\t}, function (index) {\r\n\t\t\tresetPwd();\r\n\t\t\tlayer.close(index);\r\n\t\t});\r\n\t}\r\n\t\r\n\t/* 过期密码提示 */\r\n\tif(![[${isDefaultModifyPwd}]] && [[${isPasswordExpired}]]) {\r\n\t\tlayer.confirm(\"您的密码已过期，请尽快修改密码！\", {\r\n\t\t\ticon: 0,\r\n\t\t\ttitle: \"安全提示\",\r\n\t\t\tbtn: ['确认'\t, '取消'],\r\n\t\t\toffset: ['30%']\r\n\t\t}, function (index) {\r\n\t\t\tresetPwd();\r\n\t\t\tlayer.close(index);\r\n\t\t});\r\n\t}\r\n\t\r\n\t$(\"[data-toggle='tooltip']\").tooltip();\r\n\t/* 页面加载时拉取公告 */\r\n\tloadNoticeTop();\r\n});\r\n\r\n/* 加载顶部公告列表 */\r\nfunction loadNoticeTop() {\r\n\t$.ajax({\r\n\t\turl: ctx + \"system/notice/listTop\",\r\n\t\ttype: \"get\",\r\n\t\tdataType: \"json\",\r\n\t\tsuccess: function(res) {\r\n\t\t\tif (res.code !== 0 || !res.data || res.data.length === 0) {\r\n\t\t\t\t$(\"#noticeItems\").html('<div style=\"padding:24px;text-align:center;color:#bbb;font-size:12px;\"><i class=\\\"fa fa-inbox\\\"></i><br>暂无公告</div>');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tvar list = res.data;\r\n\t\t\tvar unread = (res.unreadCount !== undefined && res.unreadCount !== null) ? res.unreadCount : list.length;\r\n\t\t\tif (unread > 0) {\r\n\t\t\t\t$(\"#noticeBadge\").text(unread).show();\r\n\t\t\t} else {\r\n\t\t\t\t$(\"#noticeBadge\").hide();\r\n\t\t\t}\r\n\t\t\tvar html = '';\r\n\t\t\tfor (var i = 0; i < list.length; i++) {\r\n\t\t\t\tvar n = list[i];\r\n\t\t\t\tvar typeClass = n.noticeType === '1' ? 'warning' : 'success';\r\n\t\t\t\tvar typeLabel = n.noticeType === '1' ? '通知' : '公告';\r\n\t\t\t\tvar isRead = n.isRead === true || n.isRead === 'true' || n.read === true || n.read === 'true';\r\n\t\t\t\tvar aColor     = isRead ? '#999' : '#333';\r\n\t\t\t\tvar titleColor = isRead ? 'color:#999;' : '';\r\n\t\t\t\tvar readAttr   = isRead ? ' data-read=\"1\"' : '';\r\n\t\t\t\tvar badgeHtml  = isRead\r\n\t\t\t\t\t? '<span style=\"flex-shrink:0;display:inline-block;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:600;background:#e9ecef;color:#aaa;\">' + typeLabel + '</span>'\r\n\t\t\t\t\t: '<span class=\"badge badge-' + typeClass + '\" style=\"flex-shrink:0;\">' + typeLabel + '</span>';\r\n\t\t\t\thtml += '<li id=\"notice-item-' + n.noticeId + '\"' + readAttr + ' style=\"border-bottom:1px solid #f5f5f5;\">';\r\n\t\t\t\thtml += '<a href=\"javascript:void(0)\" onclick=\"previewNotice(' + n.noticeId + ')\" style=\"display:flex;align-items:center;padding:10px 16px;gap:10px;text-decoration:none;color:' + aColor + ';\">';\r\n\t\t\t\thtml += badgeHtml;\r\n\t\t\t\thtml += '<span style=\"flex:1;font-size:12px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;' + titleColor + '\" title=\"' + (n.noticeTitle||'') + '\">' + (n.noticeTitle||'') + '</span>';\r\n\t\t\t\thtml += '<span style=\"font-size:11px;color:#bbb;flex-shrink:0;\">' + (n.createTime ? n.createTime.substring(0,10) : '') + '</span>';\r\n\t\t\t\thtml += '</a></li>';\r\n\t\t\t}\r\n\t\t\t$(\"#noticeItems\").html(html);\r\n\t\t},\r\n\t\terror: function() {\r\n\t\t\t$(\"#noticeItems\").html('<div style=\"padding:20px;text-align:center;color:#e74c3c;font-size:12px;\">加载失败</div>');\r\n\t\t}\r\n\t});\r\n}\r\n\r\n/* 预览公告 */\r\nfunction previewNotice(noticeId) {\r\n\tvar url = ctx + \"system/notice/view/\" + noticeId;\r\n\t// 先立即更新样式并标记已读\r\n\tvar $item = $(\"#notice-item-\" + noticeId);\r\n\t$item.attr(\"data-read\", \"1\");\r\n\t$item.find(\"a\").css(\"color\", \"#999\");\r\n\t$item.find(\"span\").css(\"color\", \"#999\");\r\n\tvar $badge = $item.find(\".badge\");\r\n\tif ($badge.length) {\r\n\t\t$badge.replaceWith('<span style=\"flex-shrink:0;display:inline-block;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:600;background:#e9ecef;color:#aaa;\">' + $badge.text() + '</span>');\r\n\t}\r\n\t// 用 data-read 属性计数未读\r\n\tvar unread = $(\"#noticeItems li:not([data-read])\").length;\r\n\tif (unread > 0) {\r\n\t\t$(\"#noticeBadge\").text(unread).show();\r\n\t} else {\r\n\t\t$(\"#noticeBadge\").hide();\r\n\t}\r\n\t// 异步通知后端记录已读（fire and forget）\r\n\t$.post(ctx + \"system/notice/markRead\", { noticeId: noticeId });\r\n\tvar _layerIdx;\r\n\t_layerIdx = top.layer.open({\r\n\t\ttype: 2,\r\n\t\toffset: 'r',\r\n\t\tanim: 'slideLeft',\r\n\t\tmove: false,\r\n\t\ttitle: false,\r\n\t\tcloseBtn: 0,\r\n\t\tshade: [0.25, '#1a202c'],\r\n\t\tshadeClose: true,\r\n\t\tarea: ['600px', '100%'],\r\n\t\tcontent: url,\r\n\t\tsuccess: function(layero) {\r\n\t\t\t// 去掉 layer 默认 padding，让内容完全填满\r\n\t\t\tlayero.css({ 'border-radius': '0', 'border': 'none' });\r\n\t\t\tlayero.find('.layui-layer-content').css({ 'border-radius': '0' });\r\n\t\t\t// 悬浮关闭按钮，紧贴面板左边缘外侧\r\n\t\t\tvar $btn = $('<button id=\"noticeCloseBtn\" style=\"position:fixed;top:20px;right:608px;width:34px;height:34px;border-radius:50%;background:#fff;border:1px solid #e2e8f0;box-shadow:0 2px 10px rgba(0,0,0,0.12);cursor:pointer;font-size:13px;color:#718096;line-height:1;z-index:19891017;transition:all 0.18s;\"><i class=\"fa fa-times\"></i></button>');\r\n\t\t\t$btn.hover(\r\n\t\t\t\tfunction(){ $(this).css({'background':'#f7fafc','color':'#2d3748','border-color':'#cbd5e0'}); },\r\n\t\t\t\tfunction(){ $(this).css({'background':'#fff','color':'#718096','border-color':'#e2e8f0'}); }\r\n\t\t\t);\r\n\t\t\t$btn.on('click', function(){ top.layer.close(_layerIdx); });\r\n\t\t\t$('body', top.document).append($btn);\r\n\t\t},\r\n\t\tend: function() {\r\n\t\t\t$('body', top.document).find('#noticeCloseBtn').remove();\r\n\t\t}\r\n\t});\r\n}\r\n\r\nfunction markAllRead() {\r\n\tvar ids = [];\r\n\t$(\"#noticeItems li\").each(function() {\r\n\t\tvar id = $(this).attr(\"id\").replace(\"notice-item-\", \"\");\r\n\t\tif (id) ids.push(id);\r\n\t\t$(this).attr(\"data-read\", \"1\");\r\n\t\t$(this).find(\"a\").css(\"color\", \"#999\");\r\n\t\t$(this).find(\"span\").css(\"color\", \"#999\");\r\n\t\tvar $b = $(this).find(\".badge\");\r\n\t\t$b.replaceWith('<span style=\"flex-shrink:0;display:inline-block;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:600;background:#e9ecef;color:#aaa;\">' + $b.text() + '</span>');\r\n\t});\r\n\t$(\"#noticeBadge\").hide();\r\n\tif (ids.length > 0) {\r\n\t\t$.post(ctx + \"system/notice/markReadAll\", { ids: ids.join(\",\") });\r\n\t}\r\n}\r\n</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html  lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"renderer\" content=\"webkit\">\n    <title>若依系统首页</title>\n    <!-- 避免IE使用兼容模式 -->\n \t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link th:href=\"@{favicon.ico}\" rel=\"shortcut icon\"/>\n    <link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/jquery.contextMenu.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/skins.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/ruoyi/css/ry-ui.css?v=4.8.2}\" rel=\"stylesheet\"/>\n    <style type=\"text/css\">#noticeItems li a{transition:background .15s;border-radius:2px}#noticeItems li a:hover{background:#f7f9fb;text-decoration:none}#noticeItems li a:active{background:#eef2f7}#noticeItems li a:focus{background:transparent;outline:0}#noticeList .mark-all-read{font-size:12px;color:#5b9bd5;text-decoration:none;padding:2px 8px;border-radius:3px;transition:background 0.15s}#noticeList .mark-all-read:hover{background:#eef5fc;color:#2b7cc1}#noticeList .mark-all-read:active{background:#eef5fc;color:#2b7cc1}#noticeList .mark-all-read:focus{outline:none;background:transparent}\n</style>\n</head>\n<body class=\"fixed-sidebar full-height-layout gray-bg\" th:classappend=\"${isMobile} ? 'canvas-menu'\" style=\"overflow: hidden\">\n<div id=\"wrapper\">\n\n    <!--左侧导航开始-->\n    <nav class=\"navbar-default navbar-static-side\" role=\"navigation\">\n        <div class=\"nav-close\">\n            <i class=\"fa fa-times-circle\"></i>\n        </div>\n        <a th:href=\"@{/index}\">\n            <li class=\"logo hidden-xs\">\n                <span class=\"logo-lg\">RuoYi</span>\n            </li>\n         </a>\n        <div class=\"sidebar-collapse\">\n            <ul class=\"nav\" id=\"side-menu\">\n            \t<li>\n            \t\t<div class=\"user-panel\">\n            \t\t\t<a class=\"menuItem noactive\" title=\"个人中心\" th:href=\"@{/system/user/profile}\">\n            \t\t\t\t<div class=\"hide\" th:text=\"个人中心\"></div>\n\t\t\t\t\t        <div class=\"pull-left image\">\n\t\t                    \t<img th:src=\"(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}\" th:onerror=\"this.src='img/profile.jpg'\" class=\"img-circle\" alt=\"User Image\">\n\t\t\t\t\t        </div>\n\t\t\t\t        </a>\n\t\t\t\t        <div class=\"pull-left info\">\n\t\t\t\t          <p>[[${user.loginName}]]</p>\n\t\t\t\t          <a href=\"javascript:;\"><i class=\"fa fa-circle text-success\"></i> 在线</a>\n\t\t\t\t          <a th:href=\"@{logout}\" style=\"padding-left:5px;\"><i class=\"fa fa-sign-out text-danger\"></i> 注销</a>\n\t\t\t\t        </div>\n\t\t\t\t    </div>\n            \t</li>\n                <li>\n                    <a class=\"menuItem\" th:href=\"@{/system/main}\"><i class=\"fa fa-home\"></i> <span class=\"nav-label\">首页</span> </a>\n                </li>\n                <li th:each=\"menu : ${menus}\">\n                \t<a th:class=\"@{${!#strings.isEmpty(menu.url) && menu.url != '#'} ? ${menu.target}}\" th:href=\"@{${#strings.isEmpty(menu.url)} ? |#| : ${menu.url}}\" th:data-refresh=\"${menu.isRefresh == '0'}\">\n                \t\t<i class=\"fa fa-bar-chart-o\" th:class=\"${menu.icon}\"></i>\n                    \t<span class=\"nav-label\" th:text=\"${menu.menuName}\">一级菜单</span>\n                    \t<span th:class=\"${#strings.isEmpty(menu.url) || menu.url == '#'} ? |fa arrow|\"></span>\n                \t</a>\n                    <ul class=\"nav nav-second-level collapse\">\n\t\t\t\t\t\t<li th:each=\"cmenu : ${menu.children}\">\n\t\t\t\t\t\t\t<a th:if=\"${#lists.isEmpty(cmenu.children)}\" th:class=\"${#strings.isEmpty(cmenu.target)} ? |menuItem| : ${cmenu.target}\" th:utext=\"${cmenu.menuName}\" th:href=\"@{${cmenu.url}}\" th:data-refresh=\"${cmenu.isRefresh == '0'}\">二级菜单</a>\n\t\t\t\t\t\t\t<a th:if=\"${not #lists.isEmpty(cmenu.children)}\" href=\"javascript:;\">[[${cmenu.menuName}]]<span class=\"fa arrow\"></span></a>\n\t\t\t\t\t\t\t<ul th:if=\"${not #lists.isEmpty(cmenu.children)}\" class=\"nav nav-third-level\">\n\t\t\t\t\t\t\t\t<li th:each=\"emenu : ${cmenu.children}\">\n\t\t\t\t\t\t\t\t    <a th:if=\"${#lists.isEmpty(emenu.children)}\" th:class=\"${#strings.isEmpty(emenu.target)} ? |menuItem| : ${emenu.target}\" th:text=\"${emenu.menuName}\" th:href=\"@{${emenu.url}}\" th:data-refresh=\"${emenu.isRefresh == '0'}\">三级菜单</a>\n\t\t\t\t\t\t\t\t    <a th:if=\"${not #lists.isEmpty(emenu.children)}\" href=\"javascript:;\">[[${emenu.menuName}]]<span class=\"fa arrow\"></span></a>\n\t\t\t\t\t\t\t\t    <ul th:if=\"${not #lists.isEmpty(emenu.children)}\" class=\"nav nav-four-level\">\n\t\t\t\t\t\t\t\t      \t<li th:each=\"fmenu : ${emenu.children}\"><a th:if=\"${#lists.isEmpty(fmenu.children)}\" th:class=\"${#strings.isEmpty(fmenu.target)} ? |menuItem| : ${fmenu.target}\" th:text=\"${fmenu.menuName}\" th:href=\"@{${fmenu.url}}\" th:data-refresh=\"${fmenu.isRefresh == '0'}\">四级菜单</a></li>\n\t\t\t\t\t\t\t\t    </ul>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n                </li>\n                <li th:if=\"${demoEnabled}\">\n                    <a href=\"javascript:;\"><i class=\"fa fa-desktop\"></i><span class=\"nav-label\">实例演示</span><span class=\"fa arrow\"></span></a>\n                    <ul class=\"nav nav-second-level collapse\">\n                        <li> <a>表单<span class=\"fa arrow\"></span></a>\n                            <ul class=\"nav nav-third-level\">\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/button}\">按钮</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/grid}\">栅格</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/select}\">下拉框</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/timeline}\">时间轴</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/progress_bars}\">进度条</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/basic}\">基本表单</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/cards}\">卡片列表</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/jasny}\">功能扩展</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/sortable}\">拖动排序</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/invoice}\">单据打印</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/labels_tips}\">标签 & 提示</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/tabs_panels}\">选项卡 & 面板</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/validate}\">表单校验</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/wizard}\">表单向导</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/upload}\">文件上传</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/datetime}\">日期和时间</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/summernote}\">富文本编辑器</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/duallistbox}\">左右互选组件</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/autocomplete}\">搜索自动补全</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/cxselect}\">多级联动下拉</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/form/localrefresh}\">Ajax局部刷新</a></li>\n\t\t\t\t\t\t\t</ul>\n                        </li>\n                        <li> <a>表格<span class=\"fa arrow\"></span></a>\n                            <ul class=\"nav nav-third-level\">\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/search}\">查询条件</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/footer}\">数据汇总</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/groupHeader}\">组合表头</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/export}\">表格导出</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/textSearch}\">全文索引</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/exportSelected}\">导出选择列</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/remember}\">翻页记住选择</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/cookie}\">表格保存状态</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/pageGo}\">跳转至指定页</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/params}\">自定义查询参数</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/multi}\">初始多表格</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/button}\">点击按钮加载表格</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/data}\">直接加载表格数据</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/fixedColumns}\">表格冻结列</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/event}\">自定义触发事件</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/headerStyle}\">表格标题格式化</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/detail}\">表格细节视图</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/child}\">表格父子视图</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/image}\">表格图片预览</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/curd}\">动态增删改查</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/reorderRows}\">表格行拖拽操作</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/reorderColumns}\">表格列拖拽操作</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/resizable}\">表格列宽拖动</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/editable}\">表格行内编辑</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/subdata}\">主子表提交</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/refresh}\">表格自动刷新</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/print}\">表格打印配置</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/dynamicColumns}\">表格动态列</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/virtualScroll}\">表格虚拟滚动</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/customView}\">自定义视图分页</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/asynTree}\">异步加载表格树</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/table/other}\">表格其他操作</a></li>\n\t\t\t\t\t\t\t</ul>\n                        </li>\n                        <li> <a>弹框<span class=\"fa arrow\"></span></a>\n                            <ul class=\"nav nav-third-level\">\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/modal/dialog}\">模态窗口</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/modal/layer}\">弹层组件</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/modal/table}\">弹层表格</a></li>\n\t\t\t\t\t\t\t</ul>\n                        </li>\n                        <li> <a>操作<span class=\"fa arrow\"></span></a>\n                            <ul class=\"nav nav-third-level\">\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/operate/table}\">表格</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/operate/other}\">其他</a></li>\n\t\t\t\t\t\t\t</ul>\n                        </li>\n                        <li> <a>报表<span class=\"fa arrow\"></span></a>\n                            <ul class=\"nav nav-third-level\">\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/echarts}\">百度ECharts</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/peity}\">peity</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/sparkline}\">sparkline</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/report/metrics}\">图表组合</a></li>\n\t\t\t\t\t\t\t</ul>\n                        </li>\n                        <li> <a>图标<span class=\"fa arrow\"></span></a>\n                            <ul class=\"nav nav-third-level\">\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/icon/fontawesome}\">Font Awesome</a></li>\n\t\t\t\t\t\t\t\t<li><a class=\"menuItem\" th:href=\"@{/demo/icon/glyphicons}\">Glyphicons</a></li>\n\t\t\t\t\t\t\t</ul>\n                        </li>\n                        <li>\n\t                        <a href=\"javascript:;\"><i class=\"fa fa-sitemap\"></i>四层菜单<span class=\"fa arrow\"></span></a>\n\t                        <ul class=\"nav nav-third-level collapse\">\n\t                            <li>\n\t                                <a href=\"javascript:;\" id=\"damian\">三级菜单1<span class=\"fa arrow\"></span></a>\n\t                                <ul class=\"nav nav-third-level\">\n\t                                    <li>\n\t                                        <a href=\"javascript:;\">四级菜单1</a>\n\t                                    </li>\n\t                                    <li>\n\t                                        <a href=\"javascript:;\">四级菜单2</a>\n\t                                    </li>\n\t                                </ul>\n\t                            </li>\n\t                            <li><a href=\"javascript:;\">三级菜单2</a></li>\n\t                        </ul>\n\t                    </li>\n                    </ul>\n                </li>\n            </ul>\n        </div>\n    </nav>\n    <!--左侧导航结束-->\n\n    <!--右侧部分开始-->\n    <div id=\"page-wrapper\" class=\"gray-bg dashbard-1\">\n        <div class=\"row border-bottom\">\n            <nav class=\"navbar navbar-static-top\" role=\"navigation\" style=\"margin-bottom: 0\">\n                <div class=\"navbar-header\">\n                    <a class=\"navbar-minimalize minimalize-styl-2\" style=\"color:#FFF;\" href=\"javascript:;\" title=\"收起菜单\">\n                    \t<i class=\"fa fa-bars\"></i>\n                    </a>\n                </div>\n                <ul class=\"nav navbar-top-links navbar-right welcome-message\">\n                    <li><a data-toggle=\"tooltip\" data-trigger=\"hover\" data-placement=\"bottom\" title=\"开发文档\" href=\"http://doc.ruoyi.vip/ruoyi\" target=\"_blank\"><i class=\"fa fa-question-circle\"></i> 文档</a></li>\n                    <li><a data-toggle=\"tooltip\" data-trigger=\"hover\" data-placement=\"bottom\" title=\"锁定屏幕\" href=\"javascript:;\" id=\"lockScreen\"><i class=\"fa fa-lock\"></i> 锁屏</a></li>\n\t                <li><a data-toggle=\"tooltip\" data-trigger=\"hover\" data-placement=\"bottom\" title=\"全屏显示\" href=\"javascript:;\" id=\"fullScreen\"><i class=\"fa fa-arrows-alt\"></i> 全屏</a></li>\n                    <li class=\"dropdown\" id=\"noticeDropdown\">\n                        <a href=\"javascript:void(0)\" class=\"dropdown-toggle\" style=\"position:relative;\" data-hover=\"dropdown\">\n                            <i class=\"fa fa-bell-o\"></i> 消息\n                            <span id=\"noticeBadge\" style=\"display:none;position:absolute;top:8px;right:-4px;background:#e74c3c;color:#fff;border-radius:50%;width:16px;height:16px;font-size:10px;line-height:16px;text-align:center;font-style:normal;\"></span>\n                        </a>\n                        <ul class=\"dropdown-menu\" id=\"noticeList\" style=\"width:320px;padding:0;left:auto;right:0;\">\n                            <li style=\"padding:10px 16px;background:#f7f9fb;border-bottom:1px solid #eee;display:flex;align-items:center;justify-content:space-between;\">\n                                <span style=\"font-size:13px;font-weight:600;color:#333;\">通知公告</span>\n                                <a href=\"javascript:void(0)\" onclick=\"markAllRead()\" class=\"mark-all-read\">全部已读</a>\n                            </li>\n                            <li id=\"noticeItems\"><div style=\"padding:20px;text-align:center;color:#aaa;font-size:12px;\"><i class=\"fa fa-spinner fa-spin\"></i> 加载中...</div></li>\n                        </ul>\n                    </li>\n                    <li class=\"dropdown user-menu\">\n\t\t\t\t\t\t<a href=\"javascript:void(0)\" class=\"dropdown-toggle\" data-hover=\"dropdown\">\n\t\t\t\t\t\t\t<img th:src=\"(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}\" th:onerror=\"this.src='img/profile.jpg'\" class=\"user-image\">\n\t\t\t\t\t\t\t<span class=\"hidden-xs\">[[${#strings.defaultString(user.userName, '-')}]]</span>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<ul class=\"dropdown-menu\">\n\t\t\t\t\t\t\t<li class=\"mt5\">\n\t\t\t\t\t\t\t\t<a th:href=\"@{/system/user/profile}\" class=\"menuItem noactive\">\n\t\t\t\t\t\t\t\t<i class=\"fa fa-user\"></i> 个人中心</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a onclick=\"resetPwd()\">\n\t\t\t\t\t\t\t\t<i class=\"fa fa-key\"></i> 修改密码</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a onclick=\"switchSkin()\">\n\t\t\t\t\t\t\t\t<i class=\"fa fa-dashboard\"></i> 切换主题</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a onclick=\"toggleMenu()\">\n\t\t\t\t\t\t\t\t<i class=\"fa fa-toggle-off\"></i> 横向菜单</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li class=\"divider\"></li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a th:href=\"@{logout}\">\n\t\t\t\t\t\t\t\t<i class=\"fa fa-sign-out\"></i> 退出登录</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</li>\n                </ul>\n            </nav>\n        </div>\n        <div class=\"row content-tabs\" th:classappend=\"${#bools.isFalse(tagsView)} ? |hide|\">\n            <button class=\"roll-nav roll-left tabLeft\">\n                <i class=\"fa fa-backward\"></i>\n            </button>\n            <nav class=\"page-tabs menuTabs\">\n                <div class=\"page-tabs-content\">\n                    <a href=\"javascript:;\" class=\"menuTab\" th:data-id=\"@{/system/main}\">首页</a>\n                </div>\n            </nav>\n            <button class=\"roll-nav roll-right tabRight\">\n                <i class=\"fa fa-forward\"></i>\n            </button>\n            <a href=\"javascript:void(0);\" class=\"roll-nav roll-right tabReload\"><i class=\"fa fa-refresh\"></i> 刷新</a>\n        </div>\n\n        <a id=\"ax_close_max\" class=\"ax_close_max\" href=\"javascript:;\" title=\"关闭全屏\"> <i class=\"fa fa-times-circle-o\"></i> </a>\n\n        <div class=\"row mainContent\" id=\"content-main\" th:classappend=\"${mainClass}\">\n            <iframe class=\"RuoYi_iframe\" name=\"iframe0\" width=\"100%\" height=\"100%\" th:data-id=\"@{/system/main}\"\n                frameborder=\"0\" seamless></iframe>\n        </div>\n\n        <div th:if=\"${footer}\" class=\"footer\">\n            <div class=\"pull-right\">© [[${copyrightYear}]] RuoYi Copyright </div>\n        </div>\n    </div>\n    <!--右侧部分结束-->\n</div>\n<!-- 全局js -->\n<script th:src=\"@{/js/jquery.min.js}\"></script>\n<script th:src=\"@{/js/bootstrap.min.js}\"></script>\n<script th:src=\"@{/js/plugins/metisMenu/jquery.metisMenu.js}\"></script>\n<script th:src=\"@{/js/plugins/slimscroll/jquery.slimscroll.min.js}\"></script>\n<script th:src=\"@{/js/jquery.contextMenu.min.js}\"></script>\n<script th:src=\"@{/ajax/libs/blockUI/jquery.blockUI.js}\"></script>\n<script th:src=\"@{/ajax/libs/layer/layer.min.js}\"></script>\n<script th:src=\"@{/ruoyi/js/ry-ui.js?v=4.8.2}\"></script>\n<script th:src=\"@{/ruoyi/js/common.js?v=4.8.2}\"></script>\n<script th:src=\"@{/ruoyi/index.js?v=20201208}\"></script>\n<script th:src=\"@{/ajax/libs/fullscreen/jquery.fullscreen.js}\"></script>\n<script th:inline=\"javascript\">\nwindow.history.forward(1);\nvar ctx = [[@{/}]]; \nvar lockscreen = [[${session.lockscreen}]]; \nif(lockscreen){window.top.location=ctx+\"lockscreen\";}\n// 皮肤缓存\nvar skin = storage.get(\"skin\");\n// history（表示去掉地址的#）否则地址以\"#\"形式展示\nvar mode = \"history\";\n// 历史访问路径缓存\nvar historyPath = storage.get(\"historyPath\");\n// 是否页签与菜单联动\nvar isLinkage = true;\n// 是否页签切换滚动到顶部\nvar isScrollToTop = true;\n\n// 本地主题优先，未设置取系统配置\nif($.common.isNotEmpty(skin)){\n\t$(\"body\").addClass(skin.split('|')[0]);\n\t$(\"body\").addClass(skin.split('|')[1]);\n} else {\n\t$(\"body\").addClass([[${sideTheme}]]);\n\t$(\"body\").addClass([[${skinName}]]);\n}\n\n/* 用户管理-重置密码 */\nfunction resetPwd() {\n    var url = ctx + 'system/user/profile/resetPwd';\n    $.modal.open(\"重置密码\", url, '770', '380');\n}\n\n/* 切换主题 */\nfunction switchSkin() {\n    layer.open({\n\t\ttype : 2,\n\t\tshadeClose : true,\n\t\ttitle : \"切换主题\",\n\t\tarea : [\"530px\", \"386px\"],\n\t\tcontent : [ctx + \"system/switchSkin\", 'no']\n\t})\n}\n\n/* 切换菜单 */\nfunction toggleMenu() {\n\t$.modal.confirm(\"确认要切换成横向菜单吗？\", function() {\n\t\t$.get(ctx + 'system/menuStyle/topnav', function(result) {\n            window.location.reload();\n\t    });\n\t})\n}\n\n/** 刷新时访问路径页签 */\nfunction applyPath(url) {\n\t$('a[href$=\"' + decodeURI(url) + '\"]').click();\n\tif (!$('a[href$=\"' + url + '\"]').hasClass(\"noactive\")) {\n\t    $('a[href$=\"' + url + '\"]').parent(\"li\").addClass(\"selected\").parents(\"li\").addClass(\"active\").end().parents(\"ul\").addClass(\"in\");\n\t}\n}\n\n// 默认激活页签（首页）\nfunction tabActive() {\n    var $mainTab = $('.menuTab[data-id=\"' + ctx + 'system/main\"]');\n    $mainTab.addClass('active');\n    // 懒加载：首次激活首页时才设置 src 并显示\n    var $mainIframe = $('.mainContent .RuoYi_iframe[data-id=\"' + ctx + 'system/main\"]');\n    if ($mainIframe.length) {\n        openToCurrentTab($mainIframe[0]);\n    }\n}\n\n$(function() {\n\tvar lockPath = storage.get('lockPath');\n\tif($.common.equals(\"history\", mode) && window.performance.navigation.type == 1) {\n\t\tvar url = storage.get('publicPath');\n\t    if ($.common.isNotEmpty(url)) {\n\t    \tapplyPath(url);\n\t    } else {\n\t        tabActive();\n\t    }\n\t} else if($.common.isNotEmpty(lockPath)) {\n\t    applyPath(lockPath);\n\t    storage.remove('lockPath');\n\t} else {\n\t\tvar hash = location.hash;\n\t    if ($.common.isNotEmpty(hash)) {\n\t        var url = hash.substring(1, hash.length);\n\t        applyPath(url);\n\t    } else {\n\t    \tif($.common.equals(\"history\", mode)) {\n\t    \t\tstorage.set('publicPath', \"\");\n\t    \t}\n\t        tabActive();\n\t    }\n\t}\n\t\n\t/* 初始密码提示 */\n\tif([[${isDefaultModifyPwd}]]) {\n\t\tlayer.confirm(\"您的密码还是初始密码，请修改密码！\", {\n\t\t\ticon: 0,\n\t\t\ttitle: \"安全提示\",\n\t\t\tbtn: ['确认'\t, '取消'],\n\t\t\toffset: ['30%']\n\t\t}, function (index) {\n\t\t\tresetPwd();\n\t\t\tlayer.close(index);\n\t\t});\n\t}\n\t\n\t/* 过期密码提示 */\n\tif(![[${isDefaultModifyPwd}]] && [[${isPasswordExpired}]]) {\n\t\tlayer.confirm(\"您的密码已过期，请尽快修改密码！\", {\n\t\t\ticon: 0,\n\t\t\ttitle: \"安全提示\",\n\t\t\tbtn: ['确认'\t, '取消'],\n\t\t\toffset: ['30%']\n\t\t}, function (index) {\n\t\t\tresetPwd();\n\t\t\tlayer.close(index);\n\t\t});\n\t}\n\t$(\"[data-toggle='tooltip']\").tooltip();\n\t/* 页面加载时拉取公告 */\n\tloadNoticeTop();\n});\n\n/* 加载顶部公告列表 */\nfunction loadNoticeTop() {\n\t$.ajax({\n\t\turl: ctx + \"system/notice/listTop\",\n\t\ttype: \"get\",\n\t\tdataType: \"json\",\n\t\tsuccess: function(res) {\n\t\t\tif (res.code !== 0 || !res.data || res.data.length === 0) {\n\t\t\t\t$(\"#noticeItems\").html('<div style=\"padding:24px;text-align:center;color:#bbb;font-size:12px;\"><i class=\\\"fa fa-inbox\\\"></i><br>暂无公告</div>');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar list = res.data;\n\t\t\tvar unread = (res.unreadCount !== undefined && res.unreadCount !== null) ? res.unreadCount : list.length;\n\t\t\tif (unread > 0) {\n\t\t\t\t$(\"#noticeBadge\").text(unread).show();\n\t\t\t} else {\n\t\t\t\t$(\"#noticeBadge\").hide();\n\t\t\t}\n\t\t\tvar html = '';\n\t\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\t\tvar n = list[i];\n\t\t\t\tvar typeClass = n.noticeType === '1' ? 'warning' : 'success';\n\t\t\t\tvar typeLabel = n.noticeType === '1' ? '通知' : '公告';\n\t\t\t\tvar isRead = n.isRead === true || n.isRead === 'true' || n.read === true || n.read === 'true';\n\t\t\t\tvar aColor     = isRead ? '#999' : '#333';\n\t\t\t\tvar titleColor = isRead ? 'color:#999;' : '';\n\t\t\t\tvar readAttr   = isRead ? ' data-read=\"1\"' : '';\n\t\t\t\tvar badgeHtml  = isRead\n\t\t\t\t\t? '<span style=\"flex-shrink:0;display:inline-block;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:600;background:#e9ecef;color:#aaa;\">' + typeLabel + '</span>'\n\t\t\t\t\t: '<span class=\"badge badge-' + typeClass + '\" style=\"flex-shrink:0;\">' + typeLabel + '</span>';\n\t\t\t\thtml += '<li id=\"notice-item-' + n.noticeId + '\"' + readAttr + ' style=\"border-bottom:1px solid #f5f5f5;\">';\n\t\t\t\thtml += '<a href=\"javascript:void(0)\" onclick=\"previewNotice(' + n.noticeId + ')\" style=\"display:flex;align-items:center;padding:10px 16px;gap:10px;text-decoration:none;color:' + aColor + ';\">';\n\t\t\t\thtml += badgeHtml;\n\t\t\t\thtml += '<span style=\"flex:1;font-size:12px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;' + titleColor + '\" title=\"' + (n.noticeTitle||'') + '\">' + (n.noticeTitle||'') + '</span>';\n\t\t\t\thtml += '<span style=\"font-size:11px;color:#bbb;flex-shrink:0;\">' + (n.createTime ? n.createTime.substring(0,10) : '') + '</span>';\n\t\t\t\thtml += '</a></li>';\n\t\t\t}\n\t\t\t$(\"#noticeItems\").html(html);\n\t\t},\n\t\terror: function() {\n\t\t\t$(\"#noticeItems\").html('<div style=\"padding:20px;text-align:center;color:#e74c3c;font-size:12px;\">加载失败</div>');\n\t\t}\n\t});\n}\n\n/* 预览公告 */\nfunction previewNotice(noticeId) {\n\tvar url = ctx + \"system/notice/view/\" + noticeId;\n\t// 先立即更新样式并标记已读\n\tvar $item = $(\"#notice-item-\" + noticeId);\n\t$item.attr(\"data-read\", \"1\");\n\t$item.find(\"a\").css(\"color\", \"#999\");\n\t$item.find(\"span\").css(\"color\", \"#999\");\n\tvar $badge = $item.find(\".badge\");\n\tif ($badge.length) {\n\t\t$badge.replaceWith('<span style=\"flex-shrink:0;display:inline-block;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:600;background:#e9ecef;color:#aaa;\">' + $badge.text() + '</span>');\n\t}\n\t// 用 data-read 属性计数未读\n\tvar unread = $(\"#noticeItems li:not([data-read])\").length;\n\tif (unread > 0) {\n\t\t$(\"#noticeBadge\").text(unread).show();\n\t} else {\n\t\t$(\"#noticeBadge\").hide();\n\t}\n\t// 异步通知后端记录已读（fire and forget）\n\t$.post(ctx + \"system/notice/markRead\", { noticeId: noticeId });\n\tvar _layerIdx;\n\t_layerIdx = top.layer.open({\n\t\ttype: 2,\n\t\toffset: 'r',\n\t\tanim: 'slideLeft',\n\t\tmove: false,\n\t\ttitle: false,\n\t\tcloseBtn: 0,\n\t\tshade: [0.25, '#1a202c'],\n\t\tshadeClose: true,\n\t\tarea: ['600px', '100%'],\n\t\tcontent: url,\n\t\tsuccess: function(layero) {\n\t\t\t// 去掉 layer 默认 padding，让内容完全填满\n\t\t\tlayero.css({ 'border-radius': '0', 'border': 'none' });\n\t\t\tlayero.find('.layui-layer-content').css({ 'border-radius': '0' });\n\t\t\t// 悬浮关闭按钮，紧贴面板左边缘外侧\n\t\t\tvar $btn = $('<button id=\"noticeCloseBtn\" style=\"position:fixed;top:20px;right:608px;width:34px;height:34px;border-radius:50%;background:#fff;border:1px solid #e2e8f0;box-shadow:0 2px 10px rgba(0,0,0,0.12);cursor:pointer;font-size:13px;color:#718096;line-height:1;z-index:19891017;transition:all 0.18s;\"><i class=\"fa fa-times\"></i></button>');\n\t\t\t$btn.hover(\n\t\t\t\tfunction(){ $(this).css({'background':'#f7fafc','color':'#2d3748','border-color':'#cbd5e0'}); },\n\t\t\t\tfunction(){ $(this).css({'background':'#fff','color':'#718096','border-color':'#e2e8f0'}); }\n\t\t\t);\n\t\t\t$btn.on('click', function(){ top.layer.close(_layerIdx); });\n\t\t\t$('body', top.document).append($btn);\n\t\t},\n\t\tend: function() {\n\t\t\t$('body', top.document).find('#noticeCloseBtn').remove();\n\t\t}\n\t});\n}\n\nfunction markAllRead() {\n\tvar ids = [];\n\t$(\"#noticeItems li\").each(function() {\n\t\tvar id = $(this).attr(\"id\").replace(\"notice-item-\", \"\");\n\t\tif (id) ids.push(id);\n\t\t$(this).attr(\"data-read\", \"1\");\n\t\t$(this).find(\"a\").css(\"color\", \"#999\");\n\t\t$(this).find(\"span\").css(\"color\", \"#999\");\n\t\tvar $b = $(this).find(\".badge\");\n\t\t$b.replaceWith('<span style=\"flex-shrink:0;display:inline-block;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:600;background:#e9ecef;color:#aaa;\">' + $b.text() + '</span>');\n\t});\n\t$(\"#noticeBadge\").hide();\n\tif (ids.length > 0) {\n\t\t$.post(ctx + \"system/notice/markReadAll\", { ids: ids.join(\",\") });\n\t}\n}\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/lock.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <meta th:content=\"${session.csrf_token}\" name=\"csrf-token\"/>\r\n    <!--360浏览器优先以webkit内核解析-->\r\n    <title>锁定屏幕</title>\r\n    <link th:href=\"@{favicon.ico}\" rel=\"shortcut icon\"/>\r\n    <link href=\"../static/css/bootstrap.min.css\" th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/font-awesome.min.css\" th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\r\n\t<style>.lockscreen{background:#d2d6de;height:auto;}.lockscreen .lockscreen-name{text-align:center;font-weight:600;margin-top:50px;margin-bottom:30px;}.lockscreen-wrapper{max-width:400px;margin:10% auto;z-index:800;position:relative;}.lockscreen .lockscreen-name{text-align:center;font-weight:600;margin-top:50px;margin-bottom:30px;}.lockscreen-item{border-radius:4px;padding:0;background:#fff;position:relative;margin:10px auto 30px auto;width:290px}.lockscreen-image{border-radius:50%;position:absolute;left:-10px;top:-25px;background:#fff;padding:5px;z-index:10}.lockscreen-image>img{border-radius:50%;width:70px;height:70px}.lockscreen-credentials{margin-left:70px}.lockscreen-credentials .form-control{border:0}.lockscreen-credentials .btn{background-color:#fff;border:0;padding:0 10px}.lockscreen-footer{margin-top:150px}.lockscreen-time{width:100%;color:#fff;font-size:60px;display:inline-block;text-align:center;font-family:'Open Sans',sans-serif;font-weight:300;}</style>\r\n</head>\r\n<body class=\"lockscreen\">\r\n<div class=\"lockscreen-wrapper\">\r\n    <div class=\"lockscreen-time\"></div>\r\n    <div class=\"lockscreen-name\">[[ ${user.loginName} ]] / [[${#strings.defaultString(user.userName, '-')}]]</div>\r\n\r\n    <div class=\"lockscreen-item\">\r\n        <div class=\"lockscreen-image\">\r\n            <img th:src=\"(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}\" th:onerror=\"this.src='img/profile.jpg'\" class=\"img-circle\" alt=\"User Image\">\r\n        </div>\r\n        <form class=\"lockscreen-credentials\" method=\"post\" action=\"#\" onsubmit=\"return false;\">\r\n            <div class=\"input-group\">\r\n                <input type=\"password\" name=\"password\" autocomplete=\"off\" class=\"form-control\" placeholder=\"密码\">\r\n                <div class=\"input-group-btn\">\r\n                    <button type=\"button\" class=\"btn\" onclick=\"unlock()\"><i class=\"fa fa-arrow-right text-muted\"></i></button>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n    \r\n    <div class=\"help-block text-center\" style=\"margin-top: 50px;\">系统锁屏,请输入密码登录!</div>\r\n    <div class=\"text-center\">\r\n        <a th:href=\"@{logout}\">退出重新登录</a>\r\n    </div>\r\n</div>\r\n<script src=\"../static/js/jquery.min.js\" th:src=\"@{/js/jquery.min.js}\"></script>\r\n<script src=\"../static/js/bootstrap.min.js\" th:src=\"@{/js/bootstrap.min.js}\"></script>\r\n<script src=\"../static/js/three.min.js\" th:src=\"@{/js/three.min.js}\"></script>\r\n<script src=\"../static/ajax/libs/layer/layer.min.js\" th:src=\"@{/ajax/libs/layer/layer.min.js}\"></script>\r\n<script src=\"../static/ruoyi/js/ry-ui.js\" th:src=\"@{/ruoyi/js/ry-ui.js?v=4.8.2}\"></script>\r\n</body>\r\n<script th:inline=\"javascript\">\r\n    var ctx = [[@{/}]];\r\n    Date.prototype.format = function(fmt) {\r\n\t  var o = {\r\n\t    \"M+\" : this.getMonth()+1,                 //月份\r\n\t    \"d+\" : this.getDate(),                    //日\r\n\t    \"h+\" : this.getHours(),                   //小时\r\n\t    \"m+\" : this.getMinutes(),                 //分\r\n\t    \"s+\" : this.getSeconds(),                 //秒\r\n\t    \"q+\" : Math.floor((this.getMonth()+3)/3), //季度\r\n\t    \"S\"  : this.getMilliseconds()             //毫秒\r\n\t  };\r\n\r\n\t  if (/(y+)/.test(fmt)) {\r\n          fmt = fmt.replace(RegExp.$1, (this.getFullYear() + \"\").substr(4 - RegExp.$1.length));\r\n\t  }\r\n\r\n\t  for (var k in o) {\r\n\t\t  if (new RegExp(\"(\" + k + \")\").test(fmt)) {\r\n\t\t      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((\"00\" + o[k]).substr((\"\" + o[k]).length)));\r\n\t\t  }\r\n      }\r\n\t  return fmt;\r\n\t}\r\n    \r\n    $(function() {\r\n        $('.lockscreen-time').text((new Date()).format('hh:mm:ss'));\r\n        setInterval(function() {\r\n            $('.lockscreen-time').text((new Date()).format('hh:mm:ss'));\r\n        }, 500);\r\n        init();\r\n        animate();\r\n    });\r\n\r\n    $(document).keydown(function(event) {\r\n   \t    if (event.keyCode == 13) {\r\n   \t    \tunlock();\r\n   \t    }\r\n   \t});\r\n     \r\n    function unlock() {\r\n        var username = $(\"input[name='username']\").val();\r\n        var password = $(\"input[name='password']\").val();\r\n        if ($.common.isEmpty(password)) {\r\n        \t$.modal.msg(\"请输入密码\");\r\n            return;\r\n        }\r\n        \r\n        var index = \"\";\r\n        var config = {\r\n            url: ctx + \"unlockscreen\",\r\n            type: \"post\",\r\n            dataType: \"json\",\r\n            data: { password: password },\r\n            beforeSend: function(xhr) {\r\n            \tvar csrftoken = $('meta[name=csrf-token]').attr('content');\r\n                xhr.setRequestHeader(\"X-CSRF-Token\", csrftoken);\r\n            \tindex = layer.load(2, {shade: false});\r\n            },\r\n            success: function(result) {\r\n                if (result.code == web_status.SUCCESS) {\r\n                    location.href = ctx + 'index';\r\n                } else {\r\n                    $.modal.msg(result.msg);\r\n                    $(\"input[name='password']\").val(\"\");\r\n                }\r\n                layer.close(index);\r\n            }\r\n        };\r\n        $.ajax(config);\r\n    };\r\n\r\n    var container;\r\n    var camera, scene, projector, renderer;\r\n    var PI2 = Math.PI * 2;\r\n\r\n    var programFill = function(context) {\r\n        context.beginPath();\r\n        context.arc(0, 0, 1, 0, PI2, true);\r\n        context.closePath();\r\n        context.fill();\r\n    };\r\n\r\n    var programStroke = function(context) {\r\n        context.lineWidth = 0.05;\r\n        context.beginPath();\r\n        context.arc(0, 0, 1, 0, PI2, true);\r\n        context.closePath();\r\n        context.stroke();\r\n    };\r\n\r\n    var mouse = { x: 0, y: 0 }, INTERSECTED;\r\n    function init() {\r\n    \tcontainer = document.createElement('div');\r\n    \tcontainer.id = 'bgc';\r\n    \tcontainer.style.position = 'absolute';\r\n    \tcontainer.style.zIndex = '0';\r\n    \tcontainer.style.top = '0px';\r\n    \t$(\".lockscreen-wrapper\").before(container);\r\n\r\n        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);\r\n        camera.position.set(0, 300, 500);\r\n        scene = new THREE.Scene();\r\n\r\n        for (var i = 0; i < 100; i++) {\r\n            var particle = new THREE.Particle(new THREE.ParticleCanvasMaterial({ color: Math.random() * 0x808080 + 0x808080, program: programStroke }));\r\n            particle.position.x = Math.random() * 800 - 400;\r\n            particle.position.y = Math.random() * 800 - 400;\r\n            particle.position.z = Math.random() * 800 - 400;\r\n            particle.scale.x = particle.scale.y = Math.random() * 10 + 10;\r\n            scene.add(particle);\r\n        }\r\n        projector = new THREE.Projector();\r\n        renderer = new THREE.CanvasRenderer();\r\n        renderer.setSize(window.innerWidth, window.innerHeight - 10);\r\n        container.appendChild(renderer.domElement);\r\n        document.addEventListener('mousemove', onDocumentMouseMove, false);\r\n        window.addEventListener('resize', onWindowResize, false);\r\n    };\r\n\r\n    function onWindowResize() {\r\n        camera.aspect = window.innerWidth / window.innerHeight;\r\n        camera.updateProjectionMatrix();\r\n        renderer.setSize(window.innerWidth, window.innerHeight - 10);\r\n    };\r\n\r\n    function onDocumentMouseMove(event) {\r\n        event.preventDefault();\r\n        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;\r\n        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;\r\n    };\r\n\r\n    function animate() {\r\n        requestAnimationFrame(animate);\r\n        render();\r\n    };\r\n\r\n    var radius = 600;\r\n    var theta = 0;\r\n\r\n    function render() {\r\n    \ttheta += 0.2;\r\n    \tcamera.position.x = radius * Math.sin(theta * Math.PI / 360);\r\n    \tcamera.position.y = radius * Math.sin(theta * Math.PI / 360);\r\n    \tcamera.position.z = radius * Math.cos(theta * Math.PI / 360);\r\n    \tcamera.lookAt(scene.position);\r\n    \tcamera.updateMatrixWorld();\r\n\r\n    \tvar vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);\r\n    \tprojector.unprojectVector(vector, camera);\r\n\r\n    \tvar ray = new THREE.Ray(camera.position, vector.subSelf(camera.position).normalize());\r\n    \tvar intersects = ray.intersectObjects(scene.children);\r\n\r\n        if (intersects.length > 0) {\r\n            if (INTERSECTED != intersects[0].object) {\r\n                if (INTERSECTED) INTERSECTED.material.program = programStroke;\r\n                INTERSECTED = intersects[0].object;\r\n                INTERSECTED.material.program = programFill;\r\n            }\r\n        } else {\r\n            if (INTERSECTED) INTERSECTED.material.program = programStroke;\r\n            INTERSECTED = null;\r\n        }\r\n        renderer.render(scene, camera);\r\n    }\r\n</script>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">\r\n    <title>登录若依系统</title>\r\n    <meta name=\"description\" content=\"若依后台管理框架\">\r\n    <link href=\"../static/css/bootstrap.min.css\" th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/font-awesome.min.css\" th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/style.min.css\" th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/login.min.css\" th:href=\"@{/css/login.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/ruoyi/css/ry-ui.css\" th:href=\"@{/ruoyi/css/ry-ui.css?v=4.8.2}\" rel=\"stylesheet\"/>\r\n    <!-- 360浏览器急速模式 -->\r\n    <meta name=\"renderer\" content=\"webkit\">\r\n    <!-- 避免IE使用兼容模式 -->\r\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n    <link rel=\"shortcut icon\" href=\"../static/favicon.ico\" th:href=\"@{favicon.ico}\"/>\r\n    <style type=\"text/css\">label.error { position:inherit;  }</style>\r\n    <script>\r\n        if(window.top!==window.self){alert('未登录或登录超时。请重新登录');window.top.location=window.location};\r\n    </script>\r\n</head>\r\n<body class=\"signin\">\r\n    <div class=\"signinpanel\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-7\">\r\n                <div class=\"signin-info\">\r\n                    <div class=\"logopanel m-b\">\r\n                        <h1><img alt=\"[ 若依 ]\" src=\"../static/ruoyi.png\" th:src=\"@{/ruoyi.png}\"></h1>\r\n                    </div>\r\n                    <div class=\"m-b\"></div>\r\n                    <h4>欢迎使用 <strong>若依 后台管理系统</strong></h4>\r\n                    <ul class=\"m-b\">\r\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> SpringBoot</li>\r\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Mybatis</li>\r\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Shiro</li>\r\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Thymeleaf</li>\r\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Bootstrap</li>\r\n                    </ul>\r\n                    <strong th:if=\"${isAllowRegister}\">还没有账号？ <a th:href=\"@{/register}\">立即注册&raquo;</a></strong>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-5\">\r\n                <form id=\"signupForm\" autocomplete=\"off\">\r\n                    <h4 class=\"no-margins\">登录：</h4>\r\n                    <p class=\"m-t-md\">你若不离不弃，我必生死相依</p>\r\n                    <input type=\"text\"     name=\"username\" class=\"form-control uname\"     placeholder=\"用户名\" value=\"admin\"    />\r\n                    <input type=\"password\" name=\"password\" class=\"form-control pword\"     placeholder=\"密码\"   value=\"admin123\" />\r\n\t\t\t\t\t<div class=\"row m-t\" th:if=\"${captchaEnabled==true}\">\r\n\t\t\t\t\t\t<div class=\"col-xs-6\">\r\n\t\t\t\t\t\t    <input type=\"text\" name=\"validateCode\" class=\"form-control code\" placeholder=\"验证码\" maxlength=\"5\" />\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t<div class=\"col-xs-6\">\r\n\t\t\t\t\t\t\t<a href=\"javascript:void(0);\" title=\"点击更换验证码\">\r\n\t\t\t\t\t\t\t\t<img th:src=\"@{/captcha/captchaImage(type=${captchaType})}\" class=\"imgcode\" width=\"85%\"/>\r\n\t\t\t\t\t\t\t</a>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n                    <div class=\"checkbox-custom\" th:if=\"${isRemembered}\" th:classappend=\"${captchaEnabled==false} ? 'm-t'\">\r\n\t\t\t\t        <input type=\"checkbox\" id=\"rememberme\" name=\"rememberme\"> <label for=\"rememberme\">记住我</label>\r\n\t\t\t\t    </div>\r\n                    <button class=\"btn btn-success btn-block\" id=\"btnSubmit\" data-loading=\"正在验证登录，请稍候...\">登录</button>\r\n                </form>\r\n            </div>\r\n        </div>\r\n        <div class=\"signup-footer\">\r\n            <div class=\"pull-left\">\r\n                Copyright © 2018-2026 ruoyi.vip All Rights Reserved. <br>\r\n            </div>\r\n        </div>\r\n    </div>\r\n<script th:inline=\"javascript\"> var ctx = [[@{/}]]; var captchaType = [[${captchaType}]]; var captchaEnabled = [[${captchaEnabled}]];</script>\r\n<!--[if lte IE 8]><script>window.location.href=ctx+'html/ie.html';</script><![endif]-->\r\n<!-- 全局js -->\r\n<script src=\"../static/js/jquery.min.js\" th:src=\"@{/js/jquery.min.js}\"></script>\r\n<script src=\"../static/ajax/libs/validate/jquery.validate.min.js\" th:src=\"@{/ajax/libs/validate/jquery.validate.min.js}\"></script>\r\n<script src=\"../static/ajax/libs/layer/layer.min.js\" th:src=\"@{/ajax/libs/layer/layer.min.js}\"></script>\r\n<script src=\"../static/ajax/libs/blockUI/jquery.blockUI.js\" th:src=\"@{/ajax/libs/blockUI/jquery.blockUI.js}\"></script>\r\n<script src=\"../static/ruoyi/js/ry-ui.js\" th:src=\"@{/ruoyi/js/ry-ui.js?v=4.8.2}\"></script>\r\n<script src=\"../static/ruoyi/login.js\" th:src=\"@{/ruoyi/login.js}\"></script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/main.html",
    "content": "<!DOCTYPE html>\r\n<html  lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <!--360浏览器优先以webkit内核解析-->\r\n    <title>若依介绍</title>\r\n    <link rel=\"shortcut icon\" href=\"favicon.ico\">\r\n    <link href=\"../static/css/bootstrap.min.css\" th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/font-awesome.min.css\" th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/style.min.css\" th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\r\n</head>\r\n\r\n<body class=\"gray-bg\">\r\n    <div class=\"row border-bottom white-bg dashboard-header\">\r\n        <div class=\"col-sm-3\">\r\n            <h2>Hello,Guest</h2>\r\n            <small>移动设备访问请扫描以下二维码：</small>\r\n            <br>\r\n            <br>\r\n            <img th:src=\"@{/img/qr_code.png}\" width=\"100%\" style=\"max-width:264px;\">\r\n            <br>\r\n        </div>\r\n        <div class=\"col-sm-5\">\r\n            <h2>若依后台管理框架</h2>\r\n            <p>一直想做一款后台管理系统，看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统。，她可以用于所有的Web应用程序，如<b>网站管理后台</b>，<b>网站会员中心</b>，<b>CMS</b>，<b>CRM</b>，<b>OA</b>等等，当然，您也可以对她进行深度定制，以做出更强系统。所有前端后台代码封装过后十分精简易上手，出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。</p>\r\n            <p>\r\n                <b>当前版本：</b><span>v[[${version}]]</span>\r\n            </p>\r\n            <p>\r\n                <span class=\"label label-warning\">&yen;免费开源</span>\r\n            </p>\r\n            <br>\r\n            <p>\r\n                <a class=\"btn btn-success btn-outline\" href=\"https://gitee.com/y_project/RuoYi\" target=\"_blank\">\r\n                    <i class=\"fa fa-cloud\"> </i> 访问码云\r\n                </a>\r\n                <a class=\"btn btn-white btn-bitbucket\" href=\"http://ruoyi.vip\" target=\"_blank\">\r\n                    <i class=\"fa fa-home\"></i> 访问主页\r\n                </a>\r\n            </p>\r\n        </div>\r\n        <div class=\"col-sm-4\">\r\n            <h4>技术选型：</h4>\r\n            <ol>\r\n                <li>核心框架：Spring Boot。</li>\r\n                <li>安全框架：Apache Shiro。</li>\r\n                <li>模板引擎：Thymeleaf。</li>\r\n                <li>持久层框架：MyBatis。</li>\r\n                <li>定时任务：Quartz。</li>\r\n                <li>数据库连接池：Druid。</li>\r\n                <li>工具类：Fastjson。</li>\r\n                <li>更多……</li>\r\n            </ol>\r\n        </div>\r\n\r\n    </div>\r\n    <div class=\"wrapper wrapper-content\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-4\">\r\n\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>联系信息</h5>\r\n\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <p><i class=\"fa fa-send-o\"></i> 官网：<a href=\"http://www.ruoyi.vip\" target=\"_blank\">http://www.ruoyi.vip</a>\r\n                        </p>\r\n                        <p><i class=\"fa fa-qq\"></i> QQ群：<s>满1389287</s> <s>满1679294</s> <s>满1529866</s> <s>满1772718</s> <s>满1366522</s> <s>满1382251</s> <s>满1145125</s> <s>满86752435</s> <s>满134072510</s> <s>满210336300</s> <s>满339522636</s> <s>满130035985</s> <s>满143151071</s> <s>满158781320</s> <s>满201531282</s> <s>满101526938</s> <s>满264355400</s> <s>满298522656</s> <s>满139845794</s>  <s>满185760789</s> <s>满175104288</s> <s>满174942938</s> <s>满287843737</s> <s>满232896766</s> <s>满180208928</s> <s>满140284548</s> <a href=\"http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=z9z9jkkkinfAElKZk2FXqlN4XIXlXsMi&authKey=Sm9XMTV%2FFyANBrv9rVpMfMNcX4v1lVah3795O9VclQwU4DNzQcT5BLXTmTBouIkM&noverify=0&group_code=177203794\" target=\"_blank\">177203794</a>\r\n                        </p>\r\n                        <p><i class=\"fa fa-weixin\"></i> 微信：<a href=\"javascript:;\">/ *若依</a>\r\n                        </p>\r\n                        <p><i class=\"fa fa-credit-card\"></i> 支付宝：<a href=\"javascript:;\" class=\"支付宝信息\">/ *若依</a>\r\n                        </p>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>更新日志</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content no-padding\">\r\n                        <div class=\"panel-body\">\r\n                            <div class=\"panel-group\" id=\"version\">\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v482\">v4.8.2</a><code class=\"pull-right\">2025.12.13</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v482\" class=\"panel-collapse collapse in\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>使用yauaa代替bitwalker</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户归属部门新增清除按钮</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户头像更换后移除旧头像文件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持Excel导出对象的多个子列表</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap版本到3.4.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.9.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本1.2.27</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级tomcat到最新版本9.0.112</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级commons.io到最新版本2.21.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复用户归属部门无法修改为空问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复菜单栏收起后下级菜单无法滚动问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复异步树表查询条件无法带入分页问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复comboReadDict属性下多个sheet出现的报错</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化密码策略提示优先顺序</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化日志记录参数拼装提升效率</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导入文件检查标题行不能为空</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化定时任务包名白名单匹配方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化Excel统计行数值的单元格样式显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化数据权限控制逻辑，放开permission限制</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v481\">v4.8.1</a><code class=\"pull-right\">2025.05.20</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v481\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>新增CSRF防护功能</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel导入导出支持多图片</li>\r\n\t\t\t\t\t\t\t\t\t        <li>菜单管理支持批量保存排序</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户分配角色页禁用不允许分配</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化Tab页签跟随主题样式效果</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化浅色主题下菜单右边框同步主题色</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化空指针异常时日志无法记录错误信息问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（自定义radio/checkbox的name值）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.8.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级tomcat到最新版本9.0.105</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级commons.io到最新版本2.19.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-table到最新版本1.24.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-fileinput到最新版本5.5.4</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户更新方法移除login_name更新字段</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复定时任务参数值带括号时异常问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>进入新增页面前方法校验数据权限</li>\r\n\t\t\t\t\t\t\t\t\t        <li>进入授权角色&重置密码页校验数据权限</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化Excel匹配数值型.0结尾</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化HttpUtils加入请求类型传参</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化管理员登录不设置权限permissions属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化successCallback方法对于非特定表格类型无响应问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导出Excel日期格式双击离开后与设定的格式不一致问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v480\">v4.8.0</a><code class=\"pull-right\">2024.12.26</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v480\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>支持自定义显示Excel属性列</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表格默认转义HTML字符串</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增列宽拖动长内容自适应显示示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持wrapText是否允许内容换行</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成新增配置是否允许文件覆盖到本地</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.6.5</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级tomcat到最新版本9.0.96</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级logback到最新版本1.2.13</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级commons.io到最新版本2.16.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-framework到最新版本5.3.39</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级jquery.validate到最新版本v1.21.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导入带标题文件关闭清理</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成创建表屏蔽违规的字符</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复主子表数据显示问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复记住我请求头过大的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复角色禁用权限不失效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复类匿名注解访问失效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复导出子列表对象只能在最后的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复多选下拉框open导致页签空白问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化身份证脱敏正则</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化查询时间范围日期格式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化异步树表格折叠同步子状态</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化时间控件清除按钮样式问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化表格图片预览动态路径显示问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化select2下拉框必填背景色无法清空问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v479\">v4.7.9</a><code class=\"pull-right\">2024.06.06</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v479\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>通知公告新增详细显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增数据脱敏过滤注解</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格示例（虚拟滚动）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格示例（全文检索）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格示例（保存状态）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成支持表单布局选项</li>\r\n\t\t\t\t\t\t\t\t\t        <li>限制用户操作数据权限范围</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户密码新增非法字符验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>默认加载layer扩展皮肤</li>\r\n\t\t\t\t\t\t\t\t\t        <li>未修改初始密码弹框提醒</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务白名单配置范围缩小</li>\r\n\t\t\t\t\t\t\t\t\t        <li>操作日志列表重置回第一页</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务日志默认按时间排序</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解ColumnType类型新增文本</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解新增属性comboReadDict</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增Anonymous匿名访问不鉴权注解</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.6.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本1.2.23</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级commons.io到最新版本2.13.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-framework到安全版本</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-table到最新版本1.22.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复重置日期时出现的异常问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复页签关闭后存在的跳转问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复tooltip单击复制文本不生效的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>更新缓存管理键名排序方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>更新HttpUtils中的User-Agent</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化自定义XSS注解匹配方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化登录注册页面验证码验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化数据权限自定义匹配方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化高频率定时任务不执行问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化树表格align属性在标题生效</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化代码生成主子表关联查询方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导入Excel时设置dictType属性重复查缓存问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v478\">v4.7.8</a><code class=\"pull-right\">2023.11.23</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v478\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>用户列表新增抽屉效果详细信息</li>\r\n\t\t\t\t\t\t\t\t\t        <li>操作日志列表新增IP地址查询</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务新增页去除状态选项</li>\r\n\t\t\t\t\t\t\t\t\t        <li>系统管理角色列表显示数据权限</li>\r\n\t\t\t\t\t\t\t\t\t        <li>通用排序属性orderBy参数限制长度</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增isScrollToTop页签切换滚动到顶部</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel自定义数据处理器增加单元格/工作簿对象</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（数据值为空时显示的内容undefinedText）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.4.7</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版本1.13.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本1.2.20</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级pagehelper到最新版1.4.7</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-boot到最新版本2.5.15</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级jquery到最新版v3.7.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layer到最新版本v3.7.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layui到最新版本v2.8.18</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级x-editable到最新版本1.5.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复自定义字典样式不生效的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复弹窗按钮启用禁用方法无效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复横向菜单关闭最后一个页签状态问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复Excel导入数据临时文件无法删除问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复表格行内编辑启用翻页记住选择无效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复Excels导入时无法获取到dictType字典值问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化重置密码鼠标按下显示密码</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化参数键值文本框改为文本域</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化表格重置默认返回到第一页</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化菜单管理类型为按钮状态可选</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化数字金额大写转换精度丢失问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化树表查询无数据时清除分页信息</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化通用detail详细信息弹窗不显示按钮</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v477\">v4.7.7</a><code class=\"pull-right\">2023.04.14</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v477\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>操作日志新增消耗时间属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>日志管理使用索引提升查询性能</li>\r\n\t\t\t\t\t\t\t\t\t        <li>日志注解支持排除指定的请求参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增监控页面图标显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增支持登录IP黑名单限制</li>\r\n\t\t\t\t\t\t\t\t\t        <li>更新fontawesome图标示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>屏蔽定时任务bean违规的字符</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持自定义隐藏属性列过滤子对象</li>\r\n\t\t\t\t\t\t\t\t\t        <li>连接池Druid支持新的配置connectTimeout和socketTimeout</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级jquery到最新版v3.6.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layui到最新版本2.7.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级jasny-bootstrap到最新版4.0.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.4.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本1.2.16</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复异步表格树子项排序问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复冻结列不支持IE浏览器的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复主子表使用suggest插件无法新增问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复菜单栏快速点击导致展开折叠样式问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复用户多角色数据权限可能出现权限抬升的情况</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复异步加载表格树重置列表父节点展开异常问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复页签属性refresh为undefined时页面被刷新问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>移除apache/commons-fileupload依赖</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化前端属性提醒说明</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化用户导入更新时需获取用户编号问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化主子表根据序号删除方法加入表格ID参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导出Excel时设置dictType属性重复查缓存问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化在线用户服务缓存改为从Bean容器获取不使用自动装配</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化表格示例行拖拽后列表底部总记录条数变成了undefined问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v476\">v4.7.6</a><code class=\"pull-right\">2022.12.16</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v476\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务违规的字符</li>\r\n\t\t\t\t\t\t\t\t\t        <li>忽略不必要的属性数据返回</li>\r\n\t\t\t\t\t\t\t\t\t        <li>导入更新用户数据前校验数据权限</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改参数键名时移除前缓存配置</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改用户登录账号进行重复验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>兼容Excel下拉框内容过多无法显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.4.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级kaptcha到最新版2.3.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本1.2.15</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版本1.10.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级pagehelper到最新版1.4.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-fileinput到最新版本5.5.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复sheet超出最大行数异常问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复关闭父页签后提交无法跳转的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复操作日志类型多选导出不生效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复导出包含空子列表数据异常的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化树形表格层级显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化SQL关键字检查防止注入</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化用户管理重置时取消部门选择</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化代码生成同步后字典值NULL问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导出对象的子列表为空会出现[]问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化select2搜索下拉后校验必填样式问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v475\">v4.7.5</a><code class=\"pull-right\">2022.09.05</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v475\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel支持导出对象的子列表方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>数据逻辑删除不进行唯一验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化多角色数据权限匹配规则</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增主子表提交校验示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持自定义隐藏Excel属性列</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持backgroundColor属性设置背景颜色</li>\r\n\t\t\t\t\t\t\t\t\t        <li>菜单配置刷新时Tab页签切换时刷新</li>\r\n\t\t\t\t\t\t\t\t\t        <li>增加对AjaxResult消息结果类型的判断</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增示例（进度条）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增内容编码/解码方便插件集成使用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级jquery到最新版3.6.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layui到最新版本2.7.5</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版本1.9.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本1.2.11</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级pagehelper到最新版1.4.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.2.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复树表onLoadSuccess不生效的问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复用户分配角色大于默认页数丢失问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务支持执行父类方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>自动设置切换多个树表格实例配置</li>\r\n\t\t\t\t\t\t\t\t\t        <li>页签创建标题优先data-title属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化任务过期不执行调度</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化横向菜单下激活菜单样式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化按钮打开窗口后按回车反复弹出</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化excel/scale属性导出单元格数值类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化druid开启wall过滤器出现的异常问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化多个相同角色数据导致权限SQL重复问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v474\">v4.7.4</a><code class=\"pull-right\">2022.06.01</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v474\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>用户头像上传图片格式限制</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持color属性设置字体颜色</li>\r\n\t\t\t\t\t\t\t\t\t        <li>设置分页参数默认值</li>\r\n\t\t\t\t\t\t\t\t\t        <li>主子表操作列新增单个删除</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务检查Bean包名是否为白名单配置</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-boot到最新版本2.5.14</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版本1.9.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.1.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.83 安全修复版本</li>\r\n\t\t\t\t\t\t\t\t\t        <li>文件上传兼容Weblogic环境</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增清理分页的线程变量方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增获取不带后缀文件名称方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户缓存信息添加部门ancestors祖级列表</li>\r\n\t\t\t\t\t\t\t\t\t        <li>自定义ShiroFilterFactoryBean防止中文请求被拦截</li>\r\n\t\t\t\t\t\t\t\t\t        <li>字典类型必须以字母开头，且只能为（小写字母，数字，下滑线）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化IP地址获取到多个的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化表格冻结列阴影效果显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化菜单侧边栏滚动条尺寸及颜色</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化显示顺序orderNum类型为整型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化接口使用泛型使其看到响应属性字段</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导出数据LocalDateTime类型无数据问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复导入Excel时字典字段类型为Long转义为空问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导出excel单元格验证,包含变更为开头.防止正常内容被替换</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复URL类型回退键被禁止问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复表格客户端分页序号显示错误问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复代码生成拖拽多次出现的排序不正确问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复表格打印组件不识别多层对象属性值问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复操作日志查询类型条件为0时会查到所有数据</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复Excel注解prompt/combo同时使用不生效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复初始化多表格处理回调函数时获取的表格配置不一致问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v473\">v4.7.3</a><code class=\"pull-right\">2022.03.01</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v473\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>表格树支持分页/异步加载</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成预览支持复制内容</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务默认保存到内存中执行</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成同步保留必填/类型选项</li>\r\n\t\t\t\t\t\t\t\t\t        <li>页面若未匹配到字典标签则返回原字典值</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户访问控制时校验数据权限，防止越权</li>\r\n\t\t\t\t\t\t\t\t\t        <li>导出Excel时屏蔽公式，防止CSV注入风险</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-boot到最新版本2.5.10</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-boot-mybatis到最新版2.2.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级pagehelper到最新版1.4.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本6.1.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-table到最新版本1.19.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>服务监控新增运行参数信息显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务目标字符串验证包名白名单</li>\r\n\t\t\t\t\t\t\t\t\t        <li>文件上传接口新增原/新文件名返回参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务屏蔽违规的字符</li>\r\n\t\t\t\t\t\t\t\t\t        <li>分页数据新增分页参数合理化参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表格父子视图添加点击事件打开示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化上传文件名称命名规则</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化加载字典缓存数据</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化任务队列满时任务拒绝策略</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化IE11上传预览不显示的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化Excel格式化不同类型的日期对象</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化国际化配置多余的zh请求问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化新版Chrome浏览器回退出现的遮罩层</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复EMAIL类型回退键被禁止问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复Xss注解字段值为空时的异常问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v472\">v4.7.2</a><code class=\"pull-right\">2021.12.23</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v472\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>自定义xss校验注解实现</li>\r\n\t\t\t\t\t\t\t\t\t        <li>进入修改页面方法添加权限标识</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成创建按钮添加超级管理员权限</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成创建表检查关键字，防止注入风险</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复定时任务多参数逗号分隔的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复表格插件一起使用出现的声明报错问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复代码生成主子表模板删除方法缺少事务</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本v5.8.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级velocity到最新版本2.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.79</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级log4j2到最新版2.17.0 防止漏洞风险</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级thymeleaf到最新版3.0.14 阻止远程代码执行漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化修改/授权角色实时生效</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修整tomcat配置参数已过期问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>前端添加单独的二代身份证校验</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化新增部门时验证用户所属部门</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化查询用户的角色组&岗位组代码</li>\r\n\t\t\t\t\t\t\t\t\t        <li>请求分页方法设置成通用方便灵活调用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化日期类型错误提示与图标重叠问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v471\">v4.7.1</a><code class=\"pull-right\">2021.11.10</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v471\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>新增是否开启页签功能</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成的模块增加创建表功能</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel导入支持@Excels注解</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持导入导出标题信息</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持自定义数据处理器</li>\r\n\t\t\t\t\t\t\t\t\t        <li>日志注解新增是否保存响应参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>防重提交注解支持配置间隔时间/提示消息</li>\r\n\t\t\t\t\t\t\t\t\t        <li>网页部分操作禁止使用后退键（Backspace）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>实例演示中增加多层窗口获取值</li>\r\n\t\t\t\t\t\t\t\t\t        <li>弹出层openOptions增加动画属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-boot到最新版本2.5.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级spring-boot-mybatis到最新版2.2.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级pagehelper到最新版1.4.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本v5.8.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版1.2.8</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.78</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级thymeleaf-extras-shiro到最新版本v2.1.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-fileinput到最新版本v5.2.4</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改阿里云maven仓库地址为新版地址</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务屏蔽违规字符</li>\r\n\t\t\t\t\t\t\t\t\t        <li>增加sendGet无参请求方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成去掉多余的排序字段</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化启动脚本参数优化</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化页签关闭右侧清除iframe元素</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化多表格切换表单查询参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化表格实例切换event不能为空</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化mybatis全局默认的执行器</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化导入Excel数据关闭时清理file</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化Excel导入图片可能出现的异常</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化记录登录信息，防止不必要的修改</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化aop语法，使用spring自动注入注解</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复无法被反转义问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复拖拽行数据错位问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复新窗口打开页面关闭弹窗报错</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复富文本回退键被禁止&控制台报错问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复自定义弹出层全屏参数无效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复树表代码生成短字段无法识别问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复apple/webkit浏览器时间无法格式化</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复后端主子表代码模板方法名生成错误问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v470\">v4.7.0</a><code class=\"pull-right\">2021.09.01</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v470\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>优化弹出层显示在顶层窗口</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务支持在线生成cron表达式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持Image图片导入</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持配置是否开启记住我功能</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改时检查用户数据权限范围</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表单重置开始/结束时间控件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增多图上传示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>启用父部门状态排除顶级节点</li>\r\n\t\t\t\t\t\t\t\t\t        <li>富文本默认dialogsInBody属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>去除默认分页合理化参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>顶部菜单跳转添加绝对路径</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本v5.8.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版本v1.8.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级commons.io到最新版本v2.11.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级jquery到最新版v3.6.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级icheck到最新版v1.0.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layer到最新版本v3.5.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layui到最新版本v2.6.8</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级laydate到最新版本v5.3.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级select2到最新版v4.0.13</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级cropper到最新版本v1.5.12</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级summernote到最新版本v0.8.18</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级duallistbox到最新版本v3.0.9</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级jquery.validate到最新版本v1.19.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-suggest到最新版本v0.1.29</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-select到最新版本v1.13.18</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-fileinput到最新版本v5.2.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>查询表格指定列值增加是否去重属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>删除sourceMappingURL源映射</li>\r\n\t\t\t\t\t\t\t\t\t        <li>去除多余的favicon.ico引入</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化代码生成模板</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化XSS跨站脚本过滤</li>\r\n\t\t\t\t\t\t\t\t\t        <li>补充定时任务表字段注释</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务屏蔽ldap远程调用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务屏蔽http(s)远程调用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务对检查异常进行事务回滚</li>\r\n\t\t\t\t\t\t\t\t\t        <li>调度日志详细页添加关闭按钮</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化异常打印输出信息</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化移动端进入首页样式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化用户操作不能删除自己</li>\r\n\t\t\t\t\t\t\t\t\t        <li>默认开始/结束时间绑定控件选择类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v462\">v4.6.2</a><code class=\"pull-right\">2021.07.01</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v462\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>优化参数&字典缓存操作</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（导出方式&导出文件类型）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格示例（自定义视图分页）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增示例（表格列拖拽）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>集成yuicompressor实现(CSS/JS压缩)</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（是否支持打印页面showPrint）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持bat脚本执行应用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复存在的SQL注入漏洞问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务屏蔽rmi远程调用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>导出Excel文件支持数据流下载方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>实例演示弹层组件增加相册层示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>删除操作日志记录信息</li>\r\n\t\t\t\t\t\t\t\t\t        <li>增加表格重置分页的参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>限制超级管理员不允许操作</li>\r\n\t\t\t\t\t\t\t\t\t        <li>树级结构更新子节点使用replaceFirst</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持动态生成密匙，防止默认密钥泄露</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级pagehelper到最新版1.3.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本v5.7.4</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级swagger到最新版本v3.0.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级commons.io到最新版本v2.10.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级commons.fileupload到最新版本v1.4</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-table到最新版本v1.18.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本v1.2.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.76</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layui到最新版本v2.6.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级layer到最新版本v3.5.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级laydate到最新版本v5.3.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化表格树移动端&边框显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格刷新options配置方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化图片工具类读取文件，防止异常</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复表格图片预览移动端宽高无效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>主子表通用操作封装处理增加文本域类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>日志注解兼容获取json类型的参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复表单向导插件有滚动条时底部工具栏无法固定问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复导出角色数据范围翻译缺少仅本人</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修正Velocity模板初始字符集</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级mybatis到最新版3.5.6 阻止远程代码执行漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化代码生成导出模板名称</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改个人中心密码长度提醒</li>\r\n\t\t\t\t\t\t\t\t\t        <li>实例演示中弹出表格增加以回调形式回显到父窗体</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复登录页面弹窗文字不显示的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v461\">v4.6.1</a><code class=\"pull-right\">2021.04.12</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v461\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>新增IE浏览器版本过低提示页面</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增详细信息tab页签方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增解锁屏幕打开上次页签</li>\r\n\t\t\t\t\t\t\t\t\t        <li>数据监控默认账户密码防止越权访问</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格示例（导出选择列）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>个人信息添加手机&邮箱重复验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>个人中心刷新后样式问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>操作日志返回参数添加非空验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>velocity剔除commons-collections版本，防止3.2.1版本的反序列化漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>子表模板默认日期格式化</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成预览语言根据后缀名高亮显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成主子表相同字段导致数据问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级SpringBoot到最新版本2.2.13</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版1.7.1 阻止身份认证绕过漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrapTable到最新版本v1.18.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrapTable相关组件到最新版本v1.18.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.75</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本v1.2.4</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本v5.6.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改ip字段长度防止ipv6地址长度不够</li>\r\n\t\t\t\t\t\t\t\t\t        <li>搜索建议示例选择后隐藏列表</li>\r\n\t\t\t\t\t\t\t\t\t        <li>主子表示例增加初始化数据</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化Excel导入增加空行判断</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复横向菜单无法打开页签问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复导入数据为负浮点数时，导入结果会丢失精度问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化更多操作按钮左侧移入内容闪现消失情况</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复主子表提交中列隐藏后出现列偏移问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>单据打印网页时通过hidden-print隐藏元素</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表格销毁清除记住选择数据</li>\r\n\t\t\t\t\t\t\t\t\t        <li>增加表格动态列示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成选择主子表关联元素必填</li>\r\n\t\t\t\t\t\t\t\t\t        <li>tree根据Id和Name选中指定节点增加空判断</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v46\">v4.6.0</a><code class=\"pull-right\">2021.01.01</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v46\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>新增缓存监控管理</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增锁定屏幕功能</li>\r\n\t\t\t\t\t\t\t\t\t        <li>菜单新增是否刷新页面</li>\r\n\t\t\t\t\t\t\t\t\t        <li>删除用户和角色解绑关联</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增密码强度字符范围提示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>防止匿名访问进行过滤</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级SpringBoot到最新版本2.2.12</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级poi到最新版本4.1.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bitwalker到最新版本1.21</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-fileinput到最新版本5.1.3</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrapTable到最新版本v1.18.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrapTable相关组件到最新版本v1.18.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本v5.3.6</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增示例（标签 & 提示）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>添加单据打印示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改表格初始参数sortName默认值为undefined</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（自定义打印页面模板printPageBuilder）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（是否显示行间隔色striped）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（渲染完成后执行的事件onPostBody）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持Image图片导出</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel支持注解align对齐方式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel支持导入Boolean型数据</li>\r\n\t\t\t\t\t\t\t\t\t        <li>主子表操作添加通用addColumn方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成日期控件区分范围</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成数据库文本类型生成表单文本域</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复生成主子表外键名错误</li>\r\n\t\t\t\t\t\t\t\t\t        <li>选项卡新增是否刷新属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复树表格表头跟表格宽度不同步的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表格树加载完成触发tooltip方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>使用widthUnit定义树表格选项单位</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复主子表editColumn序列问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复添加全屏在无参数时没有替换url参数问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>弹出层openOptions移动端自适应</li>\r\n\t\t\t\t\t\t\t\t\t        <li>防止错误页返回主页出现嵌套问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>设置回显数据字典验证防止空值</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v451\">v4.5.1</a><code class=\"pull-right\">2020.11.18</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v451\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>阻止任意文件下载漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版1.7.0 阻止权限绕过漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本v1.2.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格行触发事件（onCheck、onUncheck、onCheckAll、onUncheckAll）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复多页签关闭非当前选项出现空白问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成预览支持高亮显示</li>\r\n\t\t\t\t\t\t\t\t\t        <li>mapperLocations配置支持分隔符</li>\r\n\t\t\t\t\t\t\t\t\t        <li>权限信息调整</li>\r\n\t\t\t\t\t\t\t\t\t        <li>个人中心头像和上传头像增加默认图片</li>\r\n\t\t\t\t\t\t\t\t\t        <li>全局配置类保持和其他应用命名相同</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v45\">v4.5.0</a><code class=\"pull-right\">2020.10.20</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v45\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>新增菜单导航显示风格（default为左侧导航菜单，topnav为顶部导航菜单）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>菜单&数据权限新增（展开/折叠 全选/全不选 父子联动）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>账号密码支持自定义更新周期</li>\r\n\t\t\t\t\t\t\t\t\t        <li>初始密码支持自定义修改策略</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增校验用户修改新密码不能与旧密码相同</li>\r\n\t\t\t\t\t\t\t\t\t        <li>添加检查密码范围支持的特殊字符包括：~!@#$%^&*()-=_+</li>\r\n\t\t\t\t\t\t\t\t\t        <li>注册账号设置默认用户名称及密码最后更新时间</li>\r\n\t\t\t\t\t\t\t\t\t        <li>去除用户手机邮箱部门必填验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增日期格式化方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成添加bit类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>树结构加载添加callBack回调方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复用户管理页面滚动返回顶部条失效</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复代码生成模板文件上传组件缺少ctx的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>限制系统内置参数不允许删除</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格列宽拖动插件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增Ajax局部刷新demo</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增是否开启页脚功能</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（通过自定义函数设置标题样式headerStyle）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（通过自定义函数设置页脚样式footerStyle）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复窗体大小改变后浮动提示框失效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>生成代码补充必填样式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>生成页面时不忽略remark属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>字典数据列表页添加关闭按钮</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持自动统计数据总和</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级springboot到2.1.17 提升安全性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级pagehelper到最新版1.3.0</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级druid到最新版本v1.2.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.74</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrap-fileinput到最新版本5.1.2</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级oshi到最新版本v5.2.5</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表单向导插件更换为jquery-smartwizard</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改主子表提交示例代码防止渲染失效</li>\r\n\t\t\t\t\t\t\t\t\t        <li>添加导入数据弹出窗体自定义宽高</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户信息参数返回忽略掉密码字段</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化关闭窗体添加index参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>回显数据字典（字符串数组）增加空值判断</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改前端密码长度校验和错误提示不符问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>AjaxResult重写put方法，以方便链式调用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>增强验证码校验的语义，更易懂</li>\r\n\t\t\t\t\t\t\t\t\t        <li>导入excel整形值校验优化</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel导出类型NUMERIC支持精度浮点类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>导出Excel调整targetAttr获取值方法，防止get方法不规范</li>\r\n\t\t\t\t\t\t\t\t\t        <li>输入框组验证错误后置图标提示颜色</li>\r\n\t\t\t\t\t\t\t\t\t        <li>上传媒体类型添加视频格式</li>\r\n\t\t\t\t\t\t\t\t\t        <li>数据权限判断参数类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修正数据库字符串类型nvarchar</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化递归子节点</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复多表格搜索formId无效</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v44\">v4.4.0</a><code class=\"pull-right\">2020.08.24</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v44\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>升级bootstrapTable到最新版本1.17.1</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版1.6.0 阻止权限绕过漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.73</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成支持同步数据库</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成支持富文本控件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户密码支持自定义配置规则</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格自动刷新插件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格打印配置插件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>更换图片裁剪工具为cropper</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel支持sort导出排序</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成支持自定义路径</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成支持选择上级菜单</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成支持上传控件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（自定义加载文本的字体大小loadingFontSize）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel注解支持设置BigDecimal精度&舍入规则</li>\r\n\t\t\t\t\t\t\t\t\t        <li>操作日志记录排除敏感属性字段</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复不同浏览器附件下载中文名乱码的问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户分配角色不允许选择超级管理员角色</li>\r\n\t\t\t\t\t\t\t\t\t        <li>更换表格冻结列插件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>添加右侧冻结列示例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级表格行编辑&移动端适应插件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复更新表格插件后无法设置实例配置问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复更新表格插件后导致的主子表错误</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复页面存在多表格，回调函数res数据不正确问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>强退&过期清理登录账号缓存会话</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表格树标题内容支持html语义化标签</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复配置应用的访问路径首页页签重复问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化openTab打开时滚动到当前页签</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表格请求方式method支持自定义配置</li>\r\n\t\t\t\t\t\t\t\t\t        <li>菜单页签联动优化</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户邮箱长度限制修改为50</li>\r\n\t\t\t\t\t\t\t\t\t        <li>主子表示例添加日期格式案例</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改表格行内编辑示例旧值参数</li>\r\n\t\t\t\t\t\t\t\t\t        <li>操作日志查询方式调整</li>\r\n\t\t\t\t\t\t\t\t\t        <li>唯一限制条件只返回单条数据</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改Excel设置STRING单元格类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>添加获取当前的环境配置方法</li>\r\n\t\t\t\t\t\t\t\t\t        <li>截取返回参数长度，防止超出异常</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务cron表达式验证</li>\r\n\t\t\t\t\t\t\t\t\t        <li>拆分表格插件，按需引入</li>\r\n\t\t\t\t\t\t\t\t\t        <li>多行文本框补齐必填错误提示背景</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v431\">v4.3.1</a><code class=\"pull-right\">2020.07.05</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v431\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>国家信息安全漏洞（请务必保持cipherKey密钥唯一性）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级shiro到最新版1.5.3 阻止权限绕过漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改验证码在使用后清除，防止多次使用</li>\r\n\t\t\t\t\t\t\t\t\t        <li>检查字符支持小数点&降级改成异常提醒</li>\r\n\t\t\t\t\t\t\t\t\t        <li>openOptions函数中加入自定义maxmin属性</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持openOptions方法最大化</li>\r\n\t\t\t\t\t\t\t\t\t        <li>支持openOptions方法多个按钮回调</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增isLinkage支持页签与菜单联动</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改代码生成导入表结构出现异常页面不提醒问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>优化用户头像发生错误，则显示一个默认头像</li>\r\n\t\t\t\t\t\t\t\t\t        <li>Excel导出支持字典类型</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v43\">v4.3.0</a><code class=\"pull-right\">2020.06.22</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v43\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成模板支持主子表</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成显示类型支持复选框</li>\r\n\t\t\t\t\t\t\t\t\t        <li>前端表单样式修改成圆角</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增回显数据字典（字符串数组）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复浏览器手动缩放比例后菜单无法自适应问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>限制用户不允许选择系统管理员角色</li>\r\n\t\t\t\t\t\t\t\t\t        <li>用户信息添加输入框组图标&鼠标按下显示密码</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>\r\n\t\t\t\t\t\t\t\t\t        <li>升级Bootstrap版本到v3.3.7</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复selectColumns方法获取子对象数据无效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改数据源类型优先级，先根据方法，再根据类</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修改上级部门（选择项排除本身和下级）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>首页菜单显示调整</li>\r\n\t\t\t\t\t\t\t\t\t        <li>添加是否开启swagger配置</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增示例（主子表提交）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增示例（多级联动下拉示例）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增示例（表格属性data数据加载）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格列参数（是否列选项可见ignore）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（是否启用显示卡片视图cardView）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（是否显示全屏按钮showFullscreen）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（是否启用分页条无限循环的功能paginationLoop）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增表格参数（是否显示表头showHeader）</li>\r\n\t\t\t\t\t\t\t\t\t        <li>表格添加显示/隐藏所有列方法 showAllColumns/hideAllColumns</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复部分情况节点不展开问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复关闭标签页后刷新还是上次地址问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复选择菜单后刷新页面，菜单箭头显示不对问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复jquery表单序列化时复选框未选中不会序列化到对象中问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Excel支持readConverterExp读取字符串组内容</li>\r\n\t\t\t\t\t\t\t\t\t        <li>更换IP地址查询接口</li>\r\n\t\t\t\t\t\t\t\t\t        <li>默认关闭获取ip地址</li>\r\n\t\t\t\t\t\t\t\t\t        <li>操作处理ajaxSuccess判断修正</li>\r\n\t\t\t\t\t\t\t\t\t        <li>HttpUtils.sendPost()方法，参数无需拼接参数到url</li>\r\n\t\t\t\t\t\t\t\t\t        <li>通用http发送方法增加参数 contentType 编码类型</li>\r\n\t\t\t\t\t\t\t\t\t        <li>HTML过滤器不替换&实体</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成浮点型改用BigDecimal</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复表单构建单选和多选框渲染问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成模板调整，字段为String并且必填则加空串条件</li>\r\n\t\t\t\t\t\t\t\t\t        <li>字典数据查询列表根据dictSort升序排序</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复树表对imageView和tooltip方法无效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复Long类型比较相等问题调整</li>\r\n\t\t\t\t\t\t\t\t\t        <li>示例demo页面清除html链接，防止点击后跳转出现404</li>\r\n\t\t\t\t\t\t\t\t\t        <li>在线用户强退方法合并</li>\r\n\t\t\t\t\t\t\t\t\t        <li>添加校验部门包含未停用的子部门</li>\r\n\t\t\t\t\t\t\t\t\t        <li>取消回车自动提交表单</li>\r\n\t\t\t\t\t\t\t\t\t        <li>'A','I','BUTTON' 标签忽略clickToSelect事件，防止点击操作按钮时选中</li>\r\n\t\t\t\t\t\t\t\t\t        <li>邮箱显示截取部分字符串，防止低分辨率错位</li>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成列属性根据sort排序</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复更多操作部分浏览器不兼容情况</li>\r\n\t\t\t\t\t\t\t\t\t        <li>图片预览事件属性修正</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复冻结列排序样式无效问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>修复context-path的情况下个人中心刷新导致样式问题</li>\r\n\t\t\t\t\t\t\t\t\t        <li>全屏editFull打开适配表树</li>\r\n\t\t\t\t\t\t\t\t\t        <li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v42\">v4.2.0</a><code class=\"pull-right\">2020.03.23</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v42\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>用户管理添加分配角色页面</li>\r\n\t\t\t\t\t\t\t\t\t        <li>定时任务添加调度日志按钮</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增是否开启用户注册功能</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增页面滚动显示返回顶部按钮</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>用户&角色&任务添加更多操作按钮</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>iframe框架页会话过期弹出超时提示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>移动端登录不显示左侧菜单</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>侧边栏添加一套深蓝色主题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>首页logo固定，不随菜单滚动</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持mode配置history（表示去掉地址栏的#）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>任务分组字典翻译（调度日志详细）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>字典管理添加缓存读取</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>字典数据列表标签显示样式</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>参数管理支持缓存操作</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>日期控件清空结束时间设置开始默认值为2099-12-31</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格树添加获取数据后响应回调处理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>批量替换表前缀调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持表格导入模板的弹窗表单加入其它输入控件</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表单重置刷新表格树</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增支持导出数据字段排序</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格参数（是否单选checkbox）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>druid未授权不允许访问</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格树父节点兼容0,'0','',null</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表单必填的项添加星号</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复select2不显示校验错误信息</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加自定义HTML过滤器</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复多数据源下开关关闭出现异常问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复翻页记住选择项数据问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>用户邮箱长度限制20</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改错误页面返回主页出现嵌套问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格浮动提示单双引号转义</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持配置四级菜单</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级shiro到最新版1.4.2 阻止rememberMe漏洞攻击</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级summernote到最新版本v0.8.12</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>导入Excel根据dateFormat属性格式处理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复War部署无法正常shutdown,ehcache内存泄漏</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复代码生成短字段无法识别问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复serviceImpl模版，修改方法判断日期错误</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成模板增加导出功能日志记录</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成唯一编号调整为tableId</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成查询时忽略大小写</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成支持翻页记住选中</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成表注释未填写也允许导入</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Global全局配置类修改为注解，防止多环境配置下读取问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复多表格情况下，firstLoad只对第一个表格生效</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>处理Maven打包出现警告问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>默认主题样式，防止网速慢情况下出现空白</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复文件上传多级目录识别问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>锚链接解码url，防止中文导致页面不能加载问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复右键Tab页刷新事件重复请求问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>角色禁用&菜单隐藏不查询权限</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v41\">v4.1.0</a><code class=\"pull-right\">2019.10.22</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v41\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>支持多表格实例操作</li>\r\n\t\t\t\t\t\t\t\t\t        <li>浮动提示方法tooltip支持弹窗</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成&字典数据支持模糊条件查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>增加页签全屏方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>增加清除表单验证错误信息方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持iframe局部刷新页面</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持在线切换主题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改图片预览设置的高宽参数颠倒问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>操作日志新增解锁账户功能</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>管理员用户&角色不允许操作</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>去掉jsoup包调用自定义转义工具</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加时间轴示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复翻页记住选择时获取指定列值的问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成sql脚本添加导出按钮</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加表格父子视图示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加表格行内编辑示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级fastjson到最新版1.2.60 阻止漏洞攻击</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级echarts到最新版4.2.1</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>操作日志新增返回参数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持mybatis通配符扫描任意多个包</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>权限验证多种情况处理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复树形类型的代码生成的部分必要属性无法显示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复非表格插件情况下重置出现异常</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复富文本编辑器有序列表冲突</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成表前缀配置支持多个</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复自动去除表前缀配置无效问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>菜单列表按钮数据可见不显示（权限标识控制）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复设置会话超时时间无效问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增本地资源通用下载方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>操作日志记录新增请求方式</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成单选按钮属性重名修复</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>优化select2下拉框宽度不会随浏览器改变</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复代码生成树表异常</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v40\">v4.0.0</a><code class=\"pull-right\">2019.08.08</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v40\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>代码生成支持预览、编辑，保存方案</li>\r\n\t\t\t\t\t\t\t\t\t        <li>新增防止表单重复提交注解</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增后端校验（和前端保持一致）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增同一个用户最大会话数控制</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Excel导出子对象支持多个字段</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>定时任务支持静态调用和多参数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>定时任务增加分组条件查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>字典类型增加任务分组数据</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格是否首次加载数据</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增parentTab选项卡可在同一页签打开</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>多数据源支持类注解（允许继承父类的注解）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>部门及以下数据权限（调整为以下及所有子节点）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增角色数据权限配（仅本人数据权限）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改菜单权限显示问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>上传文件修改路径及返回名称</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加报表插件及示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加首页统计模板</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加表格拖拽示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加卡片列表示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加富文本编辑器示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加表格动态增删改查示例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加用户页面岗位选择框提示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>点击菜单操作添加背景高亮显示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格树新增showSearch是否显示检索信息</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>解决表格列设置sortName无效问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格图片预览支持自定义设置宽高</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加表格列浮动提示（单击文本复制）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>PC端收起菜单后支持浮动显示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>详细操作样式调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改用户更新描述空串不更新问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>导入修改为模板渲染</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改菜单及部门排序规则</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>角色导出数据范围表达式翻译</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加summernote富文本字体大小</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>优化表格底部下边框防重叠&汇总像素问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>树表格支持属性多层级访问</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复IE浏览器用户管理界面右侧留白问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>重置按钮刷新表格</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>重置密码更新用户缓存</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>优化验证码属性参数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持数据监控配置用户名和密码</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>文件上传修改按钮背景及加载动画</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持配置一级菜单href跳转</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>侧边栏添加一套浅色主题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>树表格添加回调函数（校验异常状态）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>用户个人中心适配手机端显示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Excel支持设置导出类型&更换样式</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>检查属性改变修改为克隆方式（防止热部署强转异常）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t    </div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v34\">v3.4.0</a><code class=\"pull-right\">2019.06.03</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v34\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t        <li>新增实例演示菜单及demo</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增页签右键操作</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>菜单管理新增打开方式</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增点击某行触发的事件</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增双击某行触发的事件</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增单击某格触发的事件</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增双击某格触发的事件</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增是否启用显示细节视图</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持上传任意格式文件</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复角色权限注解失效问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>左侧的菜单栏宽度调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增响应完成后自定义回调函数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持前端及其他模块直接获取用户信息</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级swagger到最新版2.9.2</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级jquery.slimscroll到最新版1.3.8</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级select2到最新版4.0.7</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增角色配置本部门数据权限</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增角色配置本部门及以下数据权限</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>优化底部操作防止跳到页面顶端</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改冻结列选框无效及样式问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复部门四层级修改祖级无效问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>更换开关切换按钮样式</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增select2-bootstrap美化下拉框</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>添加表格内图片预览方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复权限校验失败跳转页面路径错误</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>国际化资源文件调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>通知公告布局调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>删除页签操作功能</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格树新增查询指定列值</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>更改系统接口扫描方式及完善测试案例</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格列浮动提示及字典回显默认去背景</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复启用翻页记住前面的选择check没选中问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>去除监控页面底部的广告</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>日期控件功问题修复及data功能增强</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增角色权限可见性（前端直接调用）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增获取当前登录用户方法（前端及子模块调用）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复热部署重启导致菜单丢失问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>优化业务校验失败普通请求跳转页面</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>操作日志新增状态条件查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>操作类型支持多选条件查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>通知公告防止滚动触底回弹优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t </div>\r\n                             <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v33\">v3.3.0</a><code class=\"pull-right\">2019.04.01</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v33\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增线程池统一管理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增支持左右冻结列</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格字符超长浮动提示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级datepicker拓展并汉化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级druid到最新版本v1.1.14</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复个人头像为图片服务器跨域问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改上传文件按日期存储</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格客户端分页选项</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格的高度参数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格销毁方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格下拉按钮切换方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格分页跳转到指定页码</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格启用点击选中行参数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复表格数据重新加载未触发部分按钮禁用</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>使用jsonview展示操作日志参数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增方法（addTab、editTab）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修改用户管理界面为Tab打开方式</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表单验证代码优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复@Excel注解 prompt 属性使用报错</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复combo属性Excel兼容性问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增@Excel导入导出支持父类字段</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复关闭最后选项卡无法激活滚动问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>增加日期控件显示类型及回显格式扩展选项</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复定时任务执行失败后入库状态为成功状态</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持定时任务并发开关控制</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>优化权限校验失败普通请求跳转页面</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>捕获线程池执行任务抛出的异常</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复IE浏览器导出功能报错</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增角色管理分配用户功能</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格翻页记住前面的选择</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>调整用户个人中心页面</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复界面存在的一些安全问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v32\">v3.2.0</a><code class=\"pull-right\">2019.01.18</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v32\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>部门修改时不允许选择最后节点</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复部门菜单排序字段无效</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复光驱磁盘导致服务监控异常</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>登录界面去除check插件</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>验证码文本字符间距修正</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级SpringBoot到最新版本2.1.1</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级MYSQL驱动</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修正登录必填项位置偏移</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Session会话检查优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Excel注解支持多级获取</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增序列号生成方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复WAR部署tomcat退出线程异常</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>全屏操作增加默认确认/关闭</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复个人信息可能导致漏洞</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>字典数据根据下拉选择新增类型</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级Summernote到最新版本v0.8.11</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增用户数据导入</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>首页主题样式更换</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>layer扩展主题更换</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>用户管理移动端默认隐藏左侧布局</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>详细信息弹出层显示在顶层</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格支持切换状态（用户/角色/定时任务）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Druid数据源支持配置继承</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修正部分iPhone手机端表格适配问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增防止重复提交表单方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格数据统计汇总方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持富文本上传图片文件</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v31\">v3.1.0</a><code class=\"pull-right\">2018.12.03</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v31\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增内网不获取IP地址</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增cron表达式有效校验</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>定时任务新增详细信息</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>定时任务默认策略修改（不触发立即执行）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>定时任务显示下一个执行周期</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持前端任意日期格式处理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>上传头像删除多余提交按钮</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格增加行间隔色配置项</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格增加转义HTML字符串配置项</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>表格增加显示/隐藏指定列</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>代码生成优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>操作日志参数格式化显示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>页签新增新增全屏显示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增一键打包部署</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>Excel注解新增多个参数</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增提交静默更新表格方法</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增服务监控菜单</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v30\">v3.0.0</a><code class=\"pull-right\">2018.10.08</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v30\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级poi到最新版3.17</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>导出修改临时目录绝对路径</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级laydate到最新版5.0.9</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>升级SpringBoot到最新版本2.0.5</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>优化开始/结束时间校验限制</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>重置密码参数表中获取默认值</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复头像修改显示问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增数据权限过滤注解</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增表格检索折叠按钮</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增清空（登录、操作、调度）日志</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>固定按钮位置（提交/关闭）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>部门/菜单支持（展开/折叠）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>部分细节调整优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>项目采用分模块</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v24\">v2.4.0</a><code class=\"pull-right\">2018.09.03</code>\r\n\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div id=\"v24\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持部门多级查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复菜单状态查询无效</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持IP地址开关</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持XSS开关</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>记录日志异步处理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>字典回显样式更改为下拉框</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>菜单类型必填校验</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>修复在线用户排序报错</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>增加重置按钮</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持注解导入数据</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持弹层外区域关闭</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>备注更换为文本区域</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增角色逻辑删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>新增部门逻辑删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>支持部门数据权限</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>管理员默认拥有所有授权</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>字典数据采用分页</li>\r\n\t\t\t\t\t\t\t\t\t\t\t<li>部分细节调整优化</li>\r\n\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t</div>\r\n                            <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v23\">v2.3.0</a><code class=\"pull-right\">2018.08.06</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v23\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t        <li>支持表格不分页开关控制</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>修改字典类型同步修改字典数据</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>代码生成新增修改后缀处理</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>代码生成新增实体toString</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>代码生成非字符串去除!=''</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>导出数据前加载遮罩层</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>部门删除校验条件修改</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>搜索查询下载优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>手机打开弹出层自适应</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>角色岗位禁用显示置灰</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>角色禁用不显示菜单</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增导出权限</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>角色权限唯一校验</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>岗位名称编码唯一校验</li>\r\n                                                <li>TreeTable优化</li>\r\n                                                <li>支持多数据源</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n                                <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v22\">v2.2.0</a><code class=\"pull-right\">2018.07.23</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v22\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t        <li>修复批量生成代码异常问题</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>修复定时器保存失败问题</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>修复热部署转换问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持查询菜单管理，部门管理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>大多数功能支持时间查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>自定义导出注解自动匹配column</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增任务执行策略</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>操作详细动态显示类型</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持动态回显字典数据</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>后台代码优化调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n                                <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v21\">v2.1.0</a><code class=\"pull-right\">2018.07.10</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v21\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t        <li>新增登录超时提醒</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>修复定时器热部署转换问题</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>修复登录验证码校验无效问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>定时任务新增立即执行一次</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>存在字典数据不允许删除字典</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>字典数据支持按名称查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>代码生成增加日志注解&表格优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>修复用户逻辑删除后能登录问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>表格支持多字段动态排序</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持三级菜单显示</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增ry.sh启动程序脚本</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n                            \t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v20\">v2.0.0</a><code class=\"pull-right\">2018.07.02</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v20\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t        <li>升级SpringBoot到最新版本2.0.3</li>\r\n\t\t\t\t\t\t\t\t\t\t        <li>新增公告管理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>表单校验示提体验优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>前端通用方法封装调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>前端去除js文件，合并到html</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>操作加载遮罩层</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持全屏模式操作</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持注解导出数据</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>系统支持多查询&下载</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>系统样式调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n                                <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v16\">v1.1.6</a><code class=\"pull-right\">2018.06.04</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v16\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增用户列表部门列</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增登录地点</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增swagger</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>修复排序数字校验</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>优化头像上传文件类型限定为图片</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增XSS过滤</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增热部署提高开发效率</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>修复treegrid居中无效</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>角色多条件查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n                            \t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v15\">v1.1.5</a><code class=\"pull-right\">2018.05.28</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v15\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>优化登录失败刷新验证码</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增用户登录地址时间</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>修复ajax超时退出问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增html调用数据字典(若依首创)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>调整系统部分样式</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增用户逻辑删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增管理员不允许删除修改</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>升级bootstrapTable到最新版本1.12.1</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>升级layer到最新版本3.1.1</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t    <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v14\">v1.1.4</a><code class=\"pull-right\">2018.05.20</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v14\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增参数管理</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>修复头像上传bug</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>手机邮箱唯一校验</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持手机邮箱登录</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>代码生成优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持模糊查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持切换主题皮肤</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>修改权限即时生效</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>修复页签Tab关闭问题</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n\t\t\t\t\t\t\t\t\t   <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t   <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v13\">v1.1.3</a><code class=\"pull-right\">2018.05.14</code>\r\n\t\t\t\t\t\t\t\t\t   </h5>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t<div id=\"v13\" class=\"panel-collapse collapse\">\r\n\t\t\t\t\t\t\t\t\t\t<div class=\"panel-body\">\r\n\t\t\t\t\t\t\t\t\t\t   <ol>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增验证码（数组计算、字符验证）</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增cookie记住我</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增头像上传</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>用户名密码长度限制</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>通用字段提取</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持自定义条件查询</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>部门名称必填、时间格式调整</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>其他细节优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t</ol>\r\n\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v12\">v1.1.2</a><code class=\"pull-right\">2018.05.07</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v12\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增个人信息修改</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>菜单存在子菜单不允许删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>菜单分配角色不允许删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>角色分配人员不允许删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>岗位使用后不允许删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>保证用户的数据完整性加入事物</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增环境使用手册、数据建模</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>Thymeleaf升级到3.0</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持非ROOT部署</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v11\">v1.1.1</a><code class=\"pull-right\">2018.04.23</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v11\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增表单构建器</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>代码生成优化</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持新增主部门</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持选择上级部门、上级菜单</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增字典管理单条删除</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>优化一些其他细节</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v10\">v1.1.0</a><code class=\"pull-right\">2018.04.20</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v10\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>支持密码盐</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持新增主目录</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持批量生成代码</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>支持表格导出(csv、txt、doc、excel)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>自动适应宽高模式窗体</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>重复校验(角色名、菜单名、部门名)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>优化一些其他细节</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v09\">v1.0.9</a><code class=\"pull-right\">2018.04.14</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v09\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增代码生成(生成包括 java、html、js、xml、sql)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增按钮权限控制隐藏(若依首创)</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n\t\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v08\">v1.0.8</a><code class=\"pull-right\">2018.04.08</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v08\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增定时任务(新增、修改、删除、查询、启动/暂停)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增调度日志(查询、删除)</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            \t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v07\">v1.0.7</a><code class=\"pull-right\">2018.04.04</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v07\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增岗位管理(新增、修改、删除、查询)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>优化用户管理，菜单管理部分细节</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n\t\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v06\">v1.0.6</a><code class=\"pull-right\">2018.03.15</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v06\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增字典管理(新增、删除、修改、查询、数据选择)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增用户密码重置</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>优化一些其他细节</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n\t\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v05\">v1.0.5</a><code class=\"pull-right\">2018.03.12</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v05\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增菜单管理(新增、删除、修改、查询、图标选择)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>部门管理优化(添加责任人、联系电话、邮箱、修改者)</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n\t\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v04\">v1.0.4</a><code class=\"pull-right\">2018.03.11</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v04\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增角色管理(新增、删除、修改、查询、菜单选择)</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n\t\t\t\t\t\t\t\t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v03\">v1.0.3</a><code class=\"pull-right\">2018.03.08</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v03\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增用户管理(新增、删除、修改、查询、部门选择)</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            \t<div class=\"panel panel-default\">\r\n\t\t\t\t\t\t\t\t\t<div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v02\">v1.0.2</a><code class=\"pull-right\">2018.03.04</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v02\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增部门管理 (新增、删除、修改、查询)</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"panel panel-default\">\r\n                                    <div class=\"panel-heading\">\r\n                                        <h5 class=\"panel-title\">\r\n\t\t\t\t\t\t\t\t\t\t\t<a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v01\">v1.0.1</a><code class=\"pull-right\">2018.03.03</code>\r\n\t\t\t\t\t\t\t\t\t\t</h5>\r\n                                    </div>\r\n                                    <div id=\"v01\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                            \t<li>新增在线用户 (批量强退、单条强退、查询)</li>\r\n                                                <li>新增登录日志 (批量删除、查询)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增操作日志 (批量删除、查询、详细)</li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<li>新增数据监控 (监控DB池连接和SQL的执行)</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                                <div class=\"panel panel-default\">\r\n                                    <div class=\"panel-heading\">\r\n                                        <h4 class=\"panel-title\">\r\n                                            <a data-toggle=\"collapse\" data-parent=\"#version\" href=\"#v00\">v1.0.0</a><code class=\"pull-right\">2018.03.01</code>\r\n                                        </h4>\r\n                                    </div>\r\n                                    <div id=\"v00\" class=\"panel-collapse collapse\">\r\n                                        <div class=\"panel-body\">\r\n                                            <ol>\r\n                                                <li>若依管理系统正式发布。</li>\r\n                                            </ol>\r\n                                        </div>\r\n                                    </div>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-4\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>捐赠</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"alert alert-warning\">\r\n                            \t请作者喝杯咖啡（点击图片放大）\r\n                        </div>\r\n                        <p id=\"pay-qrcode\">\r\n                            <a href=\"javascript:;\"><img th:src=\"@{/img/pay.png}\" width=\"100%\" alt=\"请使用手机支付宝或者微信扫码支付\">\r\n                            </a>\r\n                        </p>\r\n\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <script th:src=\"@{/js/jquery.min.js}\"></script>\r\n    <script th:src=\"@{/js/bootstrap.min.js}\"></script>\r\n    <script th:src=\"@{/ajax/libs/layer/layer.min.js}\"></script>\r\n    <script type=\"text/javascript\">\r\n\t    $('#pay-qrcode').click(function(){\r\n\t        var html=$(this).html();\r\n\t        parent.layer.open({\r\n\t            title: false,\r\n\t            type: 1,\r\n\t            closeBtn:false,\r\n\t            shadeClose:true,\r\n\t            area: ['600px', '360px'],\r\n\t            content: html\r\n\t        });\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/main_v1.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>统计</title>\r\n    <link rel=\"shortcut icon\" href=\"favicon.ico\">\r\n    <link href=\"../static/css/bootstrap.min.css\" th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/font-awesome.min.css\" th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/animate.min.css\" th:href=\"@{/css/animate.min.css}\" rel=\"stylesheet\"/>\r\n    <link href=\"../static/css/style.min.css\" th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\r\n</head>\r\n\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content\">\r\n\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <span class=\"label label-success pull-right\">月</span>\r\n                        <h5>收入</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <h1 class=\"no-margins\">40 886,200</h1>\r\n                        <div class=\"stat-percent font-bold text-success\">98% <i class=\"fa fa-bolt\"></i>\r\n                        </div>\r\n                        <small>总收入</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <span class=\"label label-info pull-right\">全年</span>\r\n                        <h5>订单</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <h1 class=\"no-margins\">275,800</h1>\r\n                        <div class=\"stat-percent font-bold text-info\">20% <i class=\"fa fa-level-up\"></i>\r\n                        </div>\r\n                        <small>新订单</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <span class=\"label label-primary pull-right\">今天</span>\r\n                        <h5>访客</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <h1 class=\"no-margins\">106,120</h1>\r\n                        <div class=\"stat-percent font-bold text-navy\">44% <i class=\"fa fa-level-up\"></i>\r\n                        </div>\r\n                        <small>新访客</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-3\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <span class=\"label label-danger pull-right\">最近一个月</span>\r\n                        <h5>活跃用户</h5>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <h1 class=\"no-margins\">80,600</h1>\r\n                        <div class=\"stat-percent font-bold text-danger\">38% <i class=\"fa fa-level-down\"></i>\r\n                        </div>\r\n                        <small>12月</small>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        \r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>订单</h5>\r\n                        <div class=\"pull-right\">\r\n                            <div class=\"btn-group\">\r\n                                <button type=\"button\" class=\"btn btn-xs btn-white active\">天</button>\r\n                                <button type=\"button\" class=\"btn btn-xs btn-white\">月</button>\r\n                                <button type=\"button\" class=\"btn btn-xs btn-white\">年</button>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"row\">\r\n                            <div class=\"col-sm-9\">\r\n                                <div class=\"flot-chart\">\r\n                                    <div class=\"flot-chart-content\" id=\"flot-dashboard-chart\"></div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"col-sm-3\">\r\n                                <ul class=\"stat-list\">\r\n                                    <li>\r\n                                        <h2 class=\"no-margins\">2,346</h2>\r\n                                        <small>订单总数</small>\r\n                                        <div class=\"stat-percent\">48% <i class=\"fa fa-level-up text-navy\"></i>\r\n                                        </div>\r\n                                        <div class=\"progress progress-mini\">\r\n                                            <div style=\"width: 48%;\" class=\"progress-bar\"></div>\r\n                                        </div>\r\n                                    </li>\r\n                                    <li>\r\n                                        <h2 class=\"no-margins \">4,422</h2>\r\n                                        <small>最近一个月订单</small>\r\n                                        <div class=\"stat-percent\">60% <i class=\"fa fa-level-down text-navy\"></i>\r\n                                        </div>\r\n                                        <div class=\"progress progress-mini\">\r\n                                            <div style=\"width: 60%;\" class=\"progress-bar\"></div>\r\n                                        </div>\r\n                                    </li>\r\n                                    <li>\r\n                                        <h2 class=\"no-margins \">9,180</h2>\r\n                                        <small>最近一个月销售额</small>\r\n                                        <div class=\"stat-percent\">22% <i class=\"fa fa-bolt text-navy\"></i>\r\n                                        </div>\r\n                                        <div class=\"progress progress-mini\">\r\n                                            <div style=\"width: 22%;\" class=\"progress-bar\"></div>\r\n                                        </div>\r\n                                    </li>\r\n                                 </ul>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        \r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>用户项目列表</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <table class=\"table table-hover no-margins\">\r\n                            <thead>\r\n                                <tr>\r\n                                    <th>状态</th>\r\n                                    <th>日期</th>\r\n                                    <th>用户</th>\r\n                                    <th>值</th>\r\n                                </tr>\r\n                            </thead>\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td><small>进行中...</small>\r\n                                    </td>\r\n                                    <td><i class=\"fa fa-clock-o\"></i> 11:20</td>\r\n                                    <td>青衣5858</td>\r\n                                    <td class=\"text-navy\"> <i class=\"fa fa-level-up\"></i> 24%</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td><span class=\"label label-warning\">已取消</span>\r\n                                    </td>\r\n                                    <td><i class=\"fa fa-clock-o\"></i> 10:40</td>\r\n                                    <td>徐子崴</td>\r\n                                    <td class=\"text-navy\"> <i class=\"fa fa-level-up\"></i> 66%</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td><small>进行中...</small>\r\n                                    </td>\r\n                                    <td><i class=\"fa fa-clock-o\"></i> 01:30</td>\r\n                                    <td>姜岚昕</td>\r\n                                    <td class=\"text-navy\"> <i class=\"fa fa-level-up\"></i> 54%</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td><small>进行中...</small>\r\n                                    </td>\r\n                                    <td><i class=\"fa fa-clock-o\"></i> 02:20</td>\r\n                                    <td>武汉大兵哥</td>\r\n                                    <td class=\"text-navy\"> <i class=\"fa fa-level-up\"></i> 12%</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td><small>进行中...</small>\r\n                                    </td>\r\n                                    <td><i class=\"fa fa-clock-o\"></i> 09:40</td>\r\n                                    <td>荆莹儿</td>\r\n                                    <td class=\"text-navy\"> <i class=\"fa fa-level-up\"></i> 22%</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td><span class=\"label label-primary\">已完成</span>\r\n                                    </td>\r\n                                    <td><i class=\"fa fa-clock-o\"></i> 04:10</td>\r\n                                    <td>栾某某</td>\r\n                                    <td class=\"text-navy\"> <i class=\"fa fa-level-up\"></i> 66%</td>\r\n                                </tr>\r\n                                <tr>\r\n                                    <td><small>进行中...</small>\r\n                                    </td>\r\n                                    <td><i class=\"fa fa-clock-o\"></i> 12:08</td>\r\n                                    <td>范范范二妮</td>\r\n                                    <td class=\"text-navy\"> <i class=\"fa fa-level-up\"></i> 23%</td>\r\n                                </tr>\r\n                            </tbody>\r\n                        </table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n         </div>\r\n      </div>\r\n    </div>\r\n    <script th:src=\"@{/js/jquery.min.js}\"></script>\r\n    <script th:src=\"@{/js/bootstrap.min.js}\"></script>\r\n    <script th:src=\"@{/ajax/libs/flot/jquery.flot.js}\"></script>\r\n    \r\n    <th:block th:include=\"include :: sparkline-js\" />\r\n    <script type=\"text/javascript\">\r\n\t    $(document).ready(function () {\r\n\t        var data2 = [\r\n\t            [gd(2012, 1, 1), 7], [gd(2012, 1, 2), 6], [gd(2012, 1, 3), 4], [gd(2012, 1, 4), 8],\r\n\t            [gd(2012, 1, 5), 9], [gd(2012, 1, 6), 7], [gd(2012, 1, 7), 5], [gd(2012, 1, 8), 4],\r\n\t            [gd(2012, 1, 9), 7], [gd(2012, 1, 10), 8], [gd(2012, 1, 11), 9], [gd(2012, 1, 12), 6],\r\n\t            [gd(2012, 1, 13), 4], [gd(2012, 1, 14), 5], [gd(2012, 1, 15), 11], [gd(2012, 1, 16), 8],\r\n\t            [gd(2012, 1, 17), 8], [gd(2012, 1, 18), 11], [gd(2012, 1, 19), 11], [gd(2012, 1, 20), 6],\r\n\t            [gd(2012, 1, 21), 6], [gd(2012, 1, 22), 8], [gd(2012, 1, 23), 11], [gd(2012, 1, 24), 13],\r\n\t            [gd(2012, 1, 25), 7], [gd(2012, 1, 26), 9], [gd(2012, 1, 27), 9], [gd(2012, 1, 28), 8],\r\n\t            [gd(2012, 1, 29), 5], [gd(2012, 1, 30), 8], [gd(2012, 1, 31), 25]\r\n\t        ];\r\n\t\r\n\t        var data3 = [\r\n\t            [gd(2012, 1, 1), 800], [gd(2012, 1, 2), 500], [gd(2012, 1, 3), 600], [gd(2012, 1, 4), 700],\r\n\t            [gd(2012, 1, 5), 500], [gd(2012, 1, 6), 456], [gd(2012, 1, 7), 800], [gd(2012, 1, 8), 589],\r\n\t            [gd(2012, 1, 9), 467], [gd(2012, 1, 10), 876], [gd(2012, 1, 11), 689], [gd(2012, 1, 12), 700],\r\n\t            [gd(2012, 1, 13), 500], [gd(2012, 1, 14), 600], [gd(2012, 1, 15), 700], [gd(2012, 1, 16), 786],\r\n\t            [gd(2012, 1, 17), 345], [gd(2012, 1, 18), 888], [gd(2012, 1, 19), 888], [gd(2012, 1, 20), 888],\r\n\t            [gd(2012, 1, 21), 987], [gd(2012, 1, 22), 444], [gd(2012, 1, 23), 999], [gd(2012, 1, 24), 567],\r\n\t            [gd(2012, 1, 25), 786], [gd(2012, 1, 26), 666], [gd(2012, 1, 27), 888], [gd(2012, 1, 28), 900],\r\n\t            [gd(2012, 1, 29), 178], [gd(2012, 1, 30), 555], [gd(2012, 1, 31), 993]\r\n\t        ];\r\n\t\r\n\t\r\n\t        var dataset = [\r\n\t            {\r\n\t                label: \"订单数\",\r\n\t                data: data3,\r\n\t                color: \"#1ab394\",\r\n\t                bars: {\r\n\t                    show: true,\r\n\t                    align: \"center\",\r\n\t                    barWidth: 24 * 60 * 60 * 600,\r\n\t                    lineWidth: 0\r\n\t                }\r\n\t\r\n\t            }, {\r\n\t                label: \"付款数\",\r\n\t                data: data2,\r\n\t                yaxis: 2,\r\n\t                color: \"#464f88\",\r\n\t                lines: {\r\n\t                    lineWidth: 1,\r\n\t                    show: true,\r\n\t                    fill: true,\r\n\t                    fillColor: {\r\n\t                        colors: [{\r\n\t                            opacity: 0.2\r\n\t                        }, {\r\n\t                            opacity: 0.2\r\n\t                        }]\r\n\t                    }\r\n\t                },\r\n\t                splines: {\r\n\t                    show: false,\r\n\t                    tension: 0.6,\r\n\t                    lineWidth: 1,\r\n\t                    fill: 0.1\r\n\t                },\r\n\t            }\r\n\t        ];\r\n\t\r\n\t\r\n\t        var options = {\r\n\t            xaxis: {\r\n\t                mode: \"time\",\r\n\t                tickSize: [3, \"day\"],\r\n\t                tickLength: 0,\r\n\t                axisLabel: \"Date\",\r\n\t                axisLabelUseCanvas: true,\r\n\t                axisLabelFontSizePixels: 12,\r\n\t                axisLabelFontFamily: 'Arial',\r\n\t                axisLabelPadding: 10,\r\n\t                color: \"#838383\"\r\n\t            },\r\n\t            yaxes: [{\r\n\t                    position: \"left\",\r\n\t                    max: 1070,\r\n\t                    color: \"#838383\",\r\n\t                    axisLabelUseCanvas: true,\r\n\t                    axisLabelFontSizePixels: 12,\r\n\t                    axisLabelFontFamily: 'Arial',\r\n\t                    axisLabelPadding: 3\r\n\t            }, {\r\n\t                    position: \"right\",\r\n\t                    clolor: \"#838383\",\r\n\t                    axisLabelUseCanvas: true,\r\n\t                    axisLabelFontSizePixels: 12,\r\n\t                    axisLabelFontFamily: ' Arial',\r\n\t                    axisLabelPadding: 67\r\n\t            }\r\n\t            ],\r\n\t            legend: {\r\n\t                noColumns: 1,\r\n\t                labelBoxBorderColor: \"#000000\",\r\n\t                position: \"nw\"\r\n\t            },\r\n\t            grid: {\r\n\t                hoverable: false,\r\n\t                borderWidth: 0,\r\n\t                color: '#838383'\r\n\t            }\r\n\t        };\r\n\t\r\n\t        function gd(year, month, day) {\r\n\t            return new Date(year, month - 1, day).getTime();\r\n\t        }\r\n\t\r\n\t        var previousPoint = null,\r\n\t            previousLabel = null;\r\n\t\r\n\t        $.plot($(\"#flot-dashboard-chart\"), dataset, options);\r\n\t    });\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/monitor/cache/cache.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('缓存监控')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content\">\r\n        <input type=\"hidden\" id=\"cacheName\">\r\n        <div class=\"col-sm-12\">\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-4\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-bars\"></i> 缓存列表</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a href=\"javascript:getCacheNames()\"><i class=\"fa fa-refresh\"></i></a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <table class=\"table table-hover no-margins\">\r\n                                <thead>\r\n                                    <tr>\r\n                                        <th></th>\r\n                                        <th>缓存名称</th>\r\n                                        <th>操作</th>\r\n                                    </tr>\r\n                                </thead>\r\n                                <tbody id=\"cacheNames\">\r\n                                    <tr th:fragment=\"fragment-cache-names\" th:each=\"cacheName, stat : ${cacheNames}\">\r\n                                        <td>[[${stat.index + 1}]]</td>\r\n                                        <td style=\"word-wrap:break-word;word-break:break-all;\" th:onclick=\"getCacheKeys([[${cacheName}]])\">[[${cacheName}]]</td>\r\n                                        <td style=\"width: 50px\"><a href=\"javascript:;\" th:onclick=\"clearCacheName([[${cacheName}]])\" title=\"清空\"><i class=\"fa fa-trash-o text-danger\"></i></a></td>\r\n                                    </tr>\r\n                                </tbody>\r\n                            </table>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-4\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-key\"></i> 键名列表</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a href=\"javascript:getCacheKeys('', true)\"><i class=\"fa fa-refresh\"></i></a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <table class=\"table table-hover no-margins\">\r\n                                <thead>\r\n                                    <tr>\r\n                                        <th></th>\r\n                                        <th>缓存键名</th>\r\n                                        <th>操作</th>\r\n                                    </tr>\r\n                                </thead>\r\n                                <tbody id=\"cacheKeys\">\r\n                                    <tr th:fragment=\"fragment-cache-kyes\" th:each=\"cacheKey, stat : ${cacheKeys}\">\r\n                                        <td>[[${stat.index + 1}]]</td>\r\n                                        <td style=\"word-wrap:break-word;word-break:break-all;\" th:onclick=\"getCacheValue([[${cacheName}]], [[${cacheKey}]])\">[[${cacheKey}]]</td>\r\n                                        <td style=\"width: 50px\"><a href=\"javascript:;\" th:onclick=\"clearCacheKey([[${cacheName}]], [[${cacheKey}]])\" title=\"清空\"><i class=\"fa fa-trash-o text-danger\"></i></a></td>\r\n                                    </tr>\r\n                                </tbody>\r\n                                </div>\r\n                            </table>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-4\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-file-text\"></i> 缓存内容</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a href=\"javascript:clearAll()\"><i class=\"fa fa-refresh\"></i> 清理全部</a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n\t                        <div class=\"row\" id=\"cacheValue\">\r\n\t                            <div class=\"col-sm-12\" th:fragment=\"fragment-cache-value\">\r\n\t                                <div class=\"form-group\">\r\n\t                                    <label>缓存名称：</label>\r\n\t                                    <input type=\"text\" class=\"form-control\" th:value=\"${cacheName}\">\r\n\t                                </div>\r\n\t                                <div class=\"form-group\">\r\n\t                                    <label>缓存键名：</label>\r\n\t                                    <input type=\"text\"class=\"form-control\" th:value=\"${cacheKey}\">\r\n\t                                </div>\r\n\t                                <div class=\"form-group\">\r\n\t                                    <label>缓存内容：</label>\r\n\t                                    <textarea class=\"form-control\" style=\"height: 100px\">[[${cacheValue}]]</textarea>\r\n\t                                </div>\r\n\t                            </div>\r\n\t                        </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n</body>\r\n<th:block th:include=\"include :: footer\" />\r\n<script th:inline=\"javascript\">\r\nvar prefix = ctx + \"monitor/cache\";\r\n\r\nfunction getCacheNames() {\r\n    $.ajax({\r\n        type: \"post\",\r\n        url: prefix + \"/getNames\",\r\n        success: function(data) {\r\n            $(\"#cacheNames\").html(data);\r\n            $.modal.msgSuccess(\"刷新缓存列表成功\");\r\n        }\r\n    });\r\n}\r\n\r\nfunction getCacheKeys(cacheName, isMsg) {\r\n\tvar _cacheName = $.common.isNotEmpty(cacheName) ? cacheName : $(\"#cacheName\").val();\r\n    $.ajax({\r\n        type: \"post\",\r\n        url: prefix + \"/getKeys\",\r\n        data: {\r\n            \"cacheName\": _cacheName\r\n        },\r\n        success: function(data) {\r\n            $(\"#cacheKeys\").html(data);\r\n            $(\"#cacheName\").val(_cacheName);\r\n            if (isMsg) {\r\n                $.modal.msgSuccess(\"刷新键名列表成功\");\r\n            }\r\n        }\r\n    });\r\n}\r\n\r\nfunction getCacheValue(cacheName, cacheKey) {\r\n    $.ajax({\r\n        type: \"post\",\r\n        url: prefix + \"/getValue\",\r\n        data: {\r\n            \"cacheName\": cacheName,\r\n            \"cacheKey\": cacheKey\r\n        },\r\n        success: function(data) {\r\n            $(\"#cacheValue\").html(data);\r\n        }\r\n    });\r\n}\r\n\r\nfunction clearCacheName(cacheName){\r\n\t$.post(prefix + \"/clearCacheName\", {cacheName: cacheName}, function(result) {\r\n\t\tif (result.code == web_status.SUCCESS) {\r\n\t\t\t$.modal.msgSuccess(\"清理缓存[\" + cacheName + \"]成功\")\r\n\t\t\tgetCacheKeys(cacheName);\r\n        } else {\r\n            $.modal.msgError(result.msg);\r\n        }\r\n\t});\r\n}\r\n\r\nfunction clearCacheKey(cacheName, cacheKey) {\r\n\t$.post(prefix + \"/clearCacheKey\", {cacheName: cacheName, cacheKey: cacheKey}, function(result) {\r\n\t\tif (result.code == web_status.SUCCESS) {\r\n\t\t\t$.modal.msgSuccess(\"清理缓存[\" + cacheKey + \"]成功\")\r\n\t\t\tgetCacheKeys(cacheName);\r\n        } else {\r\n            $.modal.msgError(result.msg);\r\n        }\r\n\t});\r\n}\r\n\r\nfunction clearAll(){\r\n\t$.get(prefix + \"/clearAll\", function(result) {\r\n\t\tif (result.code == web_status.SUCCESS) {\r\n\t\t\t$.modal.msgSuccess(\"清理全部缓存成功\")\r\n        } else {\r\n            $.modal.msgError(result.msg);\r\n        }\r\n\t});\r\n}\r\n</script>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/monitor/logininfor/logininfor.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('登录日志列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"logininfor-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label>登录地址：</label><input type=\"text\" name=\"ipaddr\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label>登录名称：</label><input type=\"text\" name=\"loginName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label>登录状态：</label><select name=\"status\" th:with=\"type=${@dict.getType('sys_common_status')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-time\">\r\n\t\t\t\t\t\t\t\t<label>登录时间： </label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\"/>\r\n\t\t\t\t\t\t\t\t<span>-</span>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"monitor:logininfor:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-danger\" onclick=\"$.operate.clean()\" shiro:hasPermission=\"monitor:logininfor:remove\">\r\n\t                <i class=\"fa fa-trash\"></i> 清空\r\n\t            </a>\r\n\t            <a class=\"btn btn-primary single disabled\" onclick=\"unlock()\" shiro:hasPermission=\"monitor:logininfor:unlock\">\r\n\t\t\t\t\t<i class=\"fa fa-unlock\"></i> 解锁\r\n\t\t\t\t</a>\r\n\t            <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"monitor:logininfor:export\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n\t        </div>\r\n        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n\t    var datas = [[${@dict.getType('sys_common_status')}]];\r\n\t\tvar prefix = ctx + \"monitor/logininfor\";\r\n\t\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        cleanUrl: prefix + \"/clean\",\r\n\t\t        removeUrl: prefix + \"/remove\",\r\n\t\t        exportUrl: prefix + \"/export\",\r\n\t\t        queryParams: queryParams,\r\n\t\t        sortName: \"loginTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        modalName: \"登录日志\",\r\n\t\t        escape: true,\r\n\t\t        showPageGo: true,\r\n\t\t        rememberSelected: true,\r\n\t\t        columns: [{\r\n\t\t        \tfield: 'state',\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'infoId',\r\n\t\t            title: '访问编号'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginName',\r\n\t\t            title: '登录名称',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'ipaddr',\r\n\t\t            title: '登录地址',\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginLocation',\r\n\t\t            title: '登录地点'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'browser',\r\n\t\t            title: '浏览器'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'os',\r\n\t\t            title: '操作系统'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'status',\r\n\t\t            title: '登录状态',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \treturn $.table.selectDictLabel(datas, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'msg',\r\n\t\t            title: '操作信息'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginTime',\r\n\t\t            title: '登录时间',\r\n\t\t            sortable: true\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction queryParams(params) {\r\n\t\t\tvar search = $.table.queryParams(params);\r\n\t\t\tsearch.params = {\r\n\t\t\t    beginTime : beginOfTime($(\"#startTime\").val()),\r\n\t\t\t    endTime : endOfTime($(\"#endTime\").val())\r\n\t\t\t};\r\n\t\t\treturn search;\r\n\t\t}\r\n\t\t\r\n\t\tfunction unlock() {\r\n            $.operate.post(prefix + \"/unlock?loginName=\" + $.table.selectColumns(\"loginName\"));\r\n        }\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/monitor/online/online.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('在线用户列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"online-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t登录地址：<input type=\"text\" name=\"ipaddr\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t登录名称：<input type=\"text\" name=\"loginName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t            <a class=\"btn btn-danger multiple disabled\" onclick=\"javascript:batchForceLogout()\" shiro:hasPermission=\"monitor:online:batchForceLogout\">\r\n\t                <i class=\"fa fa-sign-out\"></i> 强退\r\n\t            </a>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: bootstrap-table-export-js\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar forceFlag = [[${@permission.hasPermi('monitor:online:forceLogout')}]];\r\n\t\tvar prefix = ctx + \"monitor/online\";\r\n\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t    \tuniqueId: \"sessionId\",\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        exportUrl: prefix + \"/export\",\r\n\t\t        sortName: \"lastAccessTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        showExport: true,\r\n\t\t        escape: true,\r\n\t\t        columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n                    title: \"序号\",\r\n                    formatter: function (value, row, index) {\r\n                 \t    return $.table.serialNumber(index);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            field: 'sessionId',\r\n\t\t            title: '会话编号',\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginName',\r\n\t\t            title: '登录名称',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'deptName',\r\n\t\t            title: '部门名称'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'ipaddr',\r\n\t\t            title: '主机'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginLocation',\r\n\t\t            title: '登录地点'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'browser',\r\n\t\t            title: '浏览器'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'os',\r\n\t\t            title: '操作系统'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'status',\r\n\t\t            title: '会话状态',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                if (value == 'on_line') {\r\n\t\t                    return '<span class=\"badge badge-primary\">在线</span>';\r\n\t\t                } else if (value == 'off_line') {\r\n\t\t                    return '<span class=\"badge badge-danger\">离线</span>';\r\n\t\t                }\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'startTimestamp',\r\n\t\t            title: '登录时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'lastAccessTime',\r\n\t\t            title: '最后访问时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                var msg = '<a class=\"btn btn-danger btn-xs ' + forceFlag + '\" href=\"javascript:void(0)\" onclick=\"forceLogout(\\'' + row.sessionId + '\\')\"><i class=\"fa fa-sign-out\"></i>强退</a> ';\r\n\t\t                return msg;\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\r\n\t\t// 单条强退\r\n\t\tfunction forceLogout(sessionId) {\r\n\t\t    $.modal.confirm(\"确定要强制选中用户下线吗？\", function() {\r\n\t\t    \tvar data = { \"ids\": sessionId };\r\n\t\t        $.operate.post(prefix + \"/batchForceLogout\", data);\r\n\t\t    })\r\n\t\t}\r\n\r\n\t\t// 批量强退\r\n\t\tfunction batchForceLogout() {\r\n\t\t    var rows = $.table.selectColumns(\"sessionId\");\r\n\t\t    if (rows.length == 0) {\r\n\t\t        $.modal.alertWarning(\"请选择要强退的用户\");\r\n\t\t        return;\r\n\t\t    }\r\n\t\t    $.modal.confirm(\"确认要强退选中的\" + rows.length + \"条数据吗?\", function() {\r\n\t\t        var url = prefix + \"/batchForceLogout\";\r\n\t\t        var data = { \"ids\": rows.join() };\r\n\t\t        $.operate.post(url, data);\r\n\t\t    });\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/monitor/operlog/detail.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <th:block th:include=\"include :: header('操作日志详细')\" />\n    <th:block th:include=\"include :: jsonview-css\" />\n    <style type=\"text/css\">.method-tag{display:inline-block;padding:1px 8px;border-radius:3px;font-size:11px;font-weight:700;margin-right:6px;vertical-align:middle}.method-GET{background:#e8f5e9;color:#27ae60}.method-POST{background:#e3f2fd;color:#1565c0}.method-PUT{background:#fff3e0;color:#e65100}.method-DELETE{background:#ffebee;color:#c62828}.error-msg{background:#fff8f8;border-left:3px solid #e74c3c;border-radius:3px;padding:8px 12px;color:#c0392b;font-size:12px;line-height:1.7;word-break:break-all;white-space:pre-wrap}.code-wrap{background:#f7f9fb;border:1px solid #e8ecf0;border-radius:4px;overflow:hidden;max-height:260px;position:relative}.code-wrap pre{margin:0;padding:12px 14px;font-size:12px;line-height:1.6;font-family:Consolas,'SFMono-Regular',monospace;color:#444;white-space:pre-wrap;word-break:break-all;overflow:auto;max-height:240px;display:block}.code-action{position:absolute;top:8px;right:12px;z-index:10;margin:0;padding:0}.btn-copy{font-size:12px;color:#666;background:rgba(255,255,255,0.9);border:1px solid #dde1e7;border-radius:3px;padding:2px 10px;cursor:pointer}.btn-copy:hover{background:#fff;border-color:#409eff}.mono{font-family:Consolas,'SFMono-Regular',monospace;font-size:12px;color:#555}</style>\n</head>\n<body class=\"white-bg\">\n<div class=\"wrapper wrapper-content\">\n<div class=\"detail-wrap\">\n\n    <!-- 基本信息 -->\n    <div class=\"detail-card\">\n        <div class=\"detail-card-title\"><i class=\"fa fa-info-circle\"></i>基本信息</div>\n        <table class=\"detail-table\">\n            <tr>\n                <th>操作模块</th>\n                <td th:text=\"${operLog.title}\">-</td>\n                <th>业务类型</th>\n                <td th:text=\"${@dict.getLabel('sys_oper_type', operLog.businessType)}\">-</td>\n            </tr>\n            <tr>\n                <th>操作时间</th>\n                <td th:text=\"${#dates.format(operLog.operTime,'yyyy-MM-dd HH:mm:ss')}\">-</td>\n                <th>执行状态</th>\n                <td>\n                    <span th:if=\"${operLog.status == 0}\" class=\"tag-ok\"><i class=\"fa fa-check\"></i> 正常</span>\n                    <span th:if=\"${operLog.status != 0}\" class=\"tag-err\"><i class=\"fa fa-times\"></i> 异常</span>\n                </td>\n            </tr>\n        </table>\n    </div>\n\n    <!-- 操作人员 -->\n    <div class=\"detail-card\">\n        <div class=\"detail-card-title\"><i class=\"fa fa-user-o\"></i>操作人员</div>\n        <table class=\"detail-table\">\n            <tr>\n                <th>操作人员</th>\n                <td th:text=\"${operLog.operName}\">-</td>\n            </tr>\n            <tr th:if=\"${not #strings.isEmpty(operLog.deptName)}\">\n                <th>所属部门</th>\n                <td th:text=\"${operLog.deptName}\">-</td>\n            </tr>\n            <tr>\n                <th>操作地址</th>\n                <td><span th:text=\"${operLog.operIp}\">-</span>&nbsp;&nbsp;<span style=\"color:#999;\" th:text=\"${operLog.operLocation}\"></span></td>\n            </tr>\n        </table>\n    </div>\n\n    <!-- 请求信息 -->\n    <div class=\"detail-card\">\n        <div class=\"detail-card-title\"><i class=\"fa fa-exchange\"></i>请求信息</div>\n        <table class=\"detail-table\">\n            <tr>\n                <th>请求地址</th>\n                <td>\n                    <span th:class=\"${'method-tag method-' + operLog.requestMethod}\" th:text=\"${operLog.requestMethod}\">POST</span>\n                    <span th:text=\"${operLog.operUrl}\">-</span>\n                </td>\n            </tr>\n            <tr>\n                <th>操作方法</th>\n                <td class=\"mono\" th:text=\"${operLog.method}\">-</td>\n            </tr>\n            <tr>\n                <th>消耗时间</th>\n                <td><span th:text=\"${operLog.costTime}\">0</span> 毫秒</td>\n            </tr>\n        </table>\n    </div>\n\n    <!-- 请求参数 -->\n    <div class=\"detail-card\">\n        <div class=\"detail-card-title\"><i class=\"fa fa-arrow-circle-up\"></i>请求参数</div>\n        <div style=\"padding: 6px 18px 14px;\">\n            <div class=\"code-wrap\">\n                <div class=\"code-action\">\n                    <button class=\"btn-copy\" onclick=\"copyCode('operParam')\"><i class=\"fa fa-copy\"></i> 复制</button>\n                </div>\n                <pre id=\"operParam\"></pre>\n            </div>\n        </div>\n    </div>\n\n    <!-- 返回参数 -->\n    <div class=\"detail-card\">\n        <div class=\"detail-card-title\"><i class=\"fa fa-arrow-circle-down\"></i>返回参数</div>\n        <div style=\"padding: 6px 18px 14px;\">\n            <div class=\"code-wrap\">\n                <div class=\"code-action\">\n                    <button class=\"btn-copy\" onclick=\"copyCode('jsonResult')\"><i class=\"fa fa-copy\"></i> 复制</button>\n                </div>\n                <pre id=\"jsonResult\"></pre>\n            </div>\n        </div>\n    </div>\n\n    <!-- 异常信息（仅异常时显示） -->\n    <div class=\"detail-card\" th:if=\"${operLog.status != 0}\">\n        <div class=\"detail-card-title\" style=\"color:#c0392b;\"><i class=\"fa fa-warning\"></i>异常信息</div>\n        <div style=\"padding: 12px 18px;\">\n            <div class=\"error-msg\" th:text=\"${operLog.errorMsg}\">-</div>\n        </div>\n    </div>\n\n</div>\n</div>\n\n<th:block th:include=\"include :: footer\" />\n<th:block th:include=\"include :: jsonview-js\" />\n<script th:inline=\"javascript\">\n    $(function() {\n        var operParam = [[${operLog.operParam}]];\n        if ($.common.isNotEmpty(operParam) && operParam.length < 2000) {\n            $(\"#operParam\").JSONView(operParam);\n        } else {\n            $(\"#operParam\").text(operParam || '（无参数）');\n        }\n        var jsonResult = [[${operLog.jsonResult}]];\n        if ($.common.isNotEmpty(jsonResult) && jsonResult.length < 2000) {\n            $(\"#jsonResult\").JSONView(jsonResult);\n        } else {\n            $(\"#jsonResult\").text(jsonResult || '（无返回数据）');\n        }\n    });\n\n    function copyCode(id) {\n        var text = document.getElementById(id).innerText || '';\n        if (navigator.clipboard) {\n            navigator.clipboard.writeText(text).then(function() { showToast('已复制'); });\n        } else {\n            var ta = document.createElement('textarea');\n            ta.value = text;\n            document.body.appendChild(ta);\n            ta.select();\n            document.execCommand('copy');\n            document.body.removeChild(ta);\n            showToast('已复制');\n        }\n    }\n\n    function showToast(msg) {\n        var t = document.createElement('div');\n        t.textContent = msg;\n        t.style.cssText = 'position:fixed;bottom:24px;left:50%;transform:translateX(-50%);' +\n            'background:rgba(0,0,0,0.7);color:#fff;padding:6px 18px;border-radius:16px;' +\n            'font-size:12px;z-index:9999;pointer-events:none;';\n        document.body.appendChild(t);\n        setTimeout(function(){ document.body.removeChild(t); }, 1800);\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/monitor/operlog/operlog.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('操作日志列表')\" />\r\n\t<th:block th:include=\"include :: bootstrap-select-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"operlog-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label>操作地址：</label><input type=\"text\" name=\"operIp\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label>系统模块： </label><input type=\"text\" name=\"title\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label>操作人员： </label><input type=\"text\" name=\"operName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-selectpicker\">\r\n\t\t\t\t\t\t\t\t<label>操作类型： </label><select id=\"businessTypes\" name=\"businessTypes\" th:with=\"type=${@dict.getType('sys_oper_type')}\" class=\"selectpicker\" data-none-selected-text=\"请选择\" multiple>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<label>操作状态：</label><select name=\"status\" th:with=\"type=${@dict.getType('sys_common_status')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-time\">\r\n\t\t\t\t\t\t\t\t<label>操作时间： </label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\"/>\r\n\t\t\t\t\t\t\t\t<span>-</span>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"searchPre()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"resetPre()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"monitor:operlog:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-danger\" onclick=\"$.operate.clean()\" shiro:hasPermission=\"monitor:operlog:remove\">\r\n\t                <i class=\"fa fa-trash\"></i> 清空\r\n\t            </a>\r\n\t            <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"monitor:operlog:export\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n\t        </div>\r\n\t        \r\n\t\t\t<div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t<table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: bootstrap-select-js\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar detailFlag = [[${@permission.hasPermi('monitor:operlog:detail')}]];\r\n\t\tvar datas = [[${@dict.getType('sys_oper_type')}]];\r\n\t\tvar prefix = ctx + \"monitor/operlog\";\r\n\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        cleanUrl: prefix + \"/clean\",\r\n\t\t        detailUrl: prefix + \"/detail/{id}\",\r\n\t\t        removeUrl: prefix + \"/remove\",\r\n\t\t        exportUrl: prefix + \"/export\",\r\n\t\t        queryParams: queryParams,\r\n\t\t        sortName: \"operTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        modalName: \"操作日志\",\r\n\t\t        escape: true,\r\n\t\t        showPageGo: true,\r\n\t\t        rememberSelected: true,\r\n\t\t        columns: [{\r\n\t\t        \tfield: 'state',\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'operId',\r\n\t\t            title: '日志编号'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'title',\r\n\t\t            title: '系统模块',\r\n                    formatter: function(value, row, index) {\r\n                        return $.table.tooltip(value);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            field: 'businessType',\r\n\t\t            title: '操作类型',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                return $.table.selectDictLabel(datas, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'operName',\r\n\t\t            title: '操作人员',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'deptName',\r\n\t\t            title: '部门名称'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'operIp',\r\n\t\t            title: '操作地址'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'operLocation',\r\n\t\t            title: '操作地点'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'status',\r\n\t\t            title: '操作状态',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                if (value == 0) {\r\n\t\t                    return '<span class=\"badge badge-primary\">成功</span>';\r\n\t\t                } else if (value == 1) {\r\n\t\t                    return '<span class=\"badge badge-danger\">失败</span>';\r\n\t\t                }\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'operTime',\r\n\t\t            title: '操作时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'costTime',\r\n\t\t            title: '消耗时间',\r\n\t\t            sortable: true,\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                return $.common.sprintf(\"%s毫秒\", value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                var actions = [];\r\n\t\t                actions.push('<a class=\"btn btn-warning btn-xs ' + detailFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.detail(\\'' + row.operId + '\\')\"><i class=\"fa fa-search\"></i>详细</a>');\r\n\t\t                return actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction queryParams(params) {\r\n\t\t\tvar search = $.table.queryParams(params);\r\n\t\t\tsearch.params = {\r\n\t\t\t    beginTime : beginOfTime($(\"#startTime\").val()),\r\n\t\t\t    endTime : endOfTime($(\"#endTime\").val())\r\n\t\t\t};\r\n\t\t\tsearch.businessTypes = $.common.join($('#businessTypes').selectpicker('val'));\r\n\t\t\treturn search;\r\n\t\t}\r\n\t\t\r\n\t\tfunction searchPre() {\r\n\t\t    $.table.search('operlog-form', 'bootstrap-table');\r\n\t\t}\r\n\t\t\r\n\t\tfunction resetPre() {\r\n\t\t\tresetDate();\r\n\t\t\t$(\"#operlog-form\")[0].reset();\r\n\t\t\t$(\"#businessTypes\").selectpicker('refresh');\r\n\t\t\t$.table.search('operlog-form', 'bootstrap-table', 1);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/monitor/server/server.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('服务器监控')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content\">\r\n        <div class=\"col-sm-12\">\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-microchip\"></i> CPU</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\"><i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"close-link\"><i class=\"fa fa-times\"></i></a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <table class=\"table table-hover no-margins\">\r\n                                <thead>\r\n                                    <tr>\r\n                                        <th>属性</th>\r\n                                        <th>值</th>\r\n                                    </tr>\r\n                                </thead>\r\n                                <tbody>\r\n                                    <tr>\r\n                                        <td>核心数</td>\r\n                                        <td th:text=\"${server.cpu.cpuNum}\">0个</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <td>用户使用率</td>\r\n                                        <td th:text=\"${server.cpu.used + '%'}\">0%</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <td>系统使用率</td>\r\n                                        <td th:text=\"${server.cpu.sys + '%'}\">0%</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <td>当前空闲率</td>\r\n                                        <td th:text=\"${server.cpu.free + '%'}\">0%</td>\r\n                                    </tr>\r\n                                </tbody>\r\n                            </table>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                \r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-ticket\"></i> 内存</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\"><i class=\"fa fa-chevron-up\"></i></a>\r\n                                <a class=\"close-link\"><i class=\"fa fa-times\"></i></a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <table class=\"table table-hover no-margins\">\r\n                                <thead>\r\n                                    <tr>\r\n                                        <th>属性</th>\r\n                                        <th>内存</th>\r\n                                        <th>JVM</th>\r\n                                    </tr>\r\n                                </thead>\r\n                                <tbody>\r\n                                    <tr>\r\n                                        <td>总内存</td>\r\n                                        <td th:text=\"${server.mem.total + 'G'}\">0GB</td>\r\n                                        <td th:text=\"${server.jvm.total + 'M'}\">0MB</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <td>已用内存</td>\r\n                                        <td th:text=\"${server.mem.used + 'G'}\">0GB</td>\r\n                                        <td th:text=\"${server.jvm.used + 'M'}\">0MB</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <td>剩余内存</td>\r\n                                        <td th:text=\"${server.mem.free + 'G'}\">0GB</td>\r\n                                        <td th:text=\"${server.jvm.free + 'M'}\">0MB</td>\r\n                                    </tr>\r\n                                    <tr>\r\n                                        <td>使用率</td>\r\n                                        <td th:class=\"${server.mem.usage gt 80} ? 'text-danger'\">[[${server.mem.usage}]]%</td>\r\n                                        <td th:class=\"${server.jvm.usage gt 80} ? 'text-danger'\">[[${server.jvm.usage}]]%</td>\r\n                                    </tr>\r\n                                </tbody>\r\n                            </table>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            \r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-windows\"></i> 服务器信息</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\">\r\n                                    <i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"close-link\">\r\n                                    <i class=\"fa fa-times\"></i>\r\n                                </a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n                            <div class=\"row\">\r\n                                <div class=\"col-sm-12\">\r\n                                    <table class=\"table table-hover margin bottom\">\r\n                                        <tbody>\r\n                                            <tr>\r\n                                                <td>服务器名称</td>\r\n                                                <td th:text=\"${server.sys.computerName}\">RuoYi</td>\r\n                                                <td>操作系统</td>\r\n                                                <td th:text=\"${server.sys.osName}\">Linux</td>\r\n                                            </tr>\r\n                                            <tr>\r\n                                                <td>服务器IP</td>\r\n                                                <td th:text=\"${server.sys.computerIp}\">127.0.0.1</td>\r\n                                                <td>系统架构</td>\r\n                                                <td th:text=\"${server.sys.osArch}\">amd64</td>\r\n                                            </tr>\r\n                                        </tbody>\r\n                                    </table>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            \r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-coffee\"></i> Java虚拟机信息</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\">\r\n                                    <i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"close-link\">\r\n                                    <i class=\"fa fa-times\"></i>\r\n                                </a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n\r\n                            <div class=\"row\">\r\n                                <div class=\"col-sm-12\">\r\n                                    <table class=\"table table-hover margin bottom\" style=\"table-layout:fixed;\">\r\n                                        <tbody>\r\n                                            <tr>\r\n                                                <td>Java名称</td>\r\n                                                <td th:text=\"${server.jvm.name}\">Java</td>\r\n                                                <td>Java版本</td>\r\n                                                <td th:text=\"${server.jvm.version}\">1.8.0</td>\r\n                                            </tr>\r\n                                            <tr>\r\n                                                <td>启动时间</td>\r\n                                                <td th:text=\"${server.jvm.startTime}\">2018-12-31 00:00:00</td>\r\n                                                <td>运行时长</td>\r\n                                                <td th:text=\"${server.jvm.runTime}\">0天0时0分0秒</td>\r\n                                            </tr>\r\n                                            <tr>\r\n                                                <td colspan=\"1\">安装路径</td>\r\n                                                <td colspan=\"3\" th:text=\"${server.jvm.home}\"></td>\r\n                                            </tr>\r\n                                             <tr>\r\n                                                <td colspan=\"1\">项目路径</td>\r\n                                                <td colspan=\"3\" th:text=\"${server.sys.userDir}\"></td>\r\n                                            </tr>\r\n                                            <tr>\r\n                                                <td colspan=\"1\">运行参数</td>\r\n                                                <td colspan=\"3\" th:text=\"${server.jvm.inputArgs}\"></td>\r\n                                            </tr>\r\n                                        </tbody>\r\n                                    </table>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            \r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <div class=\"ibox float-e-margins\">\r\n                        <div class=\"ibox-title\">\r\n                            <h5><i class=\"fa fa-hdd-o\"></i> 磁盘状态</h5>\r\n                            <div class=\"ibox-tools\">\r\n                                <a class=\"collapse-link\">\r\n                                    <i class=\"fa fa-chevron-up\"></i>\r\n                                </a>\r\n                                <a class=\"close-link\">\r\n                                    <i class=\"fa fa-times\"></i>\r\n                                </a>\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"ibox-content\">\r\n\r\n                            <div class=\"row\">\r\n                                <div class=\"col-sm-12\">\r\n                                    <table class=\"table table-hover margin bottom\">\r\n                                        <thead>\r\n                                            <tr>\r\n                                                <th>盘符路径</th>\r\n                                                <th>文件系统</th>\r\n                                                <th>盘符类型</th>\r\n                                                <th>总大小</th>\r\n                                                <th>可用大小</th>\r\n                                                <th>已用大小</th>\r\n                                                <th>已用百分比</th>\r\n                                            </tr>\r\n                                        </thead>\r\n                                        <tbody>\r\n                                            <tr th:each=\"sysFile : ${server.sysFiles}\">\r\n                                                <td th:text=\"${sysFile.dirName}\">C:\\</td>\r\n                                                <td th:text=\"${sysFile.sysTypeName}\">NTFS</td>\r\n                                                <td th:text=\"${sysFile.typeName}\">local</td>\r\n                                                <td th:text=\"${sysFile.total}\">0GB</td>\r\n                                                <td th:text=\"${sysFile.free}\">0GB</td>\r\n                                                <td th:text=\"${sysFile.used}\">0GB</td>\r\n                                                <td th:class=\"${sysFile.usage gt 80} ? 'text-danger'\">[[${sysFile.usage}]]%</td>\r\n                                            </tr>\r\n                                        </tbody>\r\n                                    </table>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n</body>\r\n<th:block th:include=\"include :: footer\" />\r\n<script>\r\n    $(\".modal\").appendTo(\"body\"), $(\"[data-toggle=popover]\").popover(), $(\".collapse-link\").click(function() {\r\n        var div_ibox = $(this).closest(\"div.ibox\"),\r\n        e = $(this).find(\"i\"),\r\n        i = div_ibox.find(\"div.ibox-content\");\r\n        i.slideToggle(200),\r\n        e.toggleClass(\"fa-chevron-up\").toggleClass(\"fa-chevron-down\"),\r\n        div_ibox.toggleClass(\"\").toggleClass(\"border-bottom\"),\r\n        setTimeout(function() {\r\n        \tdiv_ibox.resize();\r\n        }, 50);\r\n    }), $(\".close-link\").click(function () {\r\n\t\tvar div_ibox = $(this).closest(\"div.ibox\");\r\n\t\tdiv_ibox.remove()\r\n\t});\r\n</script>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/register.html",
    "content": "<!DOCTYPE html>\n<html  lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">\n    <title>注册若依系统</title>\n    <meta name=\"description\" content=\"若依后台管理框架\">\n    <link href=\"../static/css/bootstrap.min.css\" th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../static/css/font-awesome.min.css\" th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../static/css/style.min.css\" th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../static/css/login.min.css\" th:href=\"@{/css/login.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../static/ruoyi/css/ry-ui.css\" th:href=\"@{/ruoyi/css/ry-ui.css?v=4.8.2}\" rel=\"stylesheet\"/>\n    <!-- 360浏览器急速模式 -->\n    <meta name=\"renderer\" content=\"webkit\">\n    <!-- 避免IE使用兼容模式 -->\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"shortcut icon\" href=\"../static/favicon.ico\" th:href=\"@{favicon.ico}\"/>\n    <style type=\"text/css\">label.error { position:inherit;  }</style>\n</head>\n<body class=\"signin\">\n    <div class=\"signinpanel\">\n        <div class=\"row\">\n            <div class=\"col-sm-7\">\n                <div class=\"signin-info\">\n                    <div class=\"logopanel m-b\">\n                        <h1><img alt=\"[ 若依 ]\" src=\"../static/ruoyi.png\" th:src=\"@{/ruoyi.png}\"></h1>\n                    </div>\n                    <div class=\"m-b\"></div>\n                    <h4>欢迎使用 <strong>若依 后台管理系统</strong></h4>\n                    <ul class=\"m-b\">\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> SpringBoot</li>\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Mybatis</li>\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Shiro</li>\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Thymeleaf</li>\n                        <li><i class=\"fa fa-arrow-circle-o-right m-r-xs\"></i> Bootstrap</li>\n                    </ul>\n                    <strong>已经注册过? <a th:href=\"@{/login}\">直接登录&raquo;</a></strong>\n                </div>\n            </div>\n            <div class=\"col-sm-5\">\n                <form id=\"registerForm\" autocomplete=\"off\">\n                    <h4 class=\"no-margins\">注册：</h4>\n                    <p class=\"m-t-md\">你若不离不弃，我必生死相依</p>\n                    <input type=\"text\"     name=\"username\" class=\"form-control uname\"         placeholder=\"用户名\"   maxlength=\"20\" />\n                    <input type=\"password\" name=\"password\" class=\"form-control pword\"         placeholder=\"密码\"     maxlength=\"20\" />\n                    <input type=\"password\" name=\"confirmPassword\" class=\"form-control pword\"  placeholder=\"确认密码\" maxlength=\"20\" />\n\t\t\t\t\t<div class=\"row m-t\" th:if=\"${captchaEnabled==true}\">\n\t\t\t\t\t\t<div class=\"col-xs-6\">\n\t\t\t\t\t\t    <input type=\"text\" name=\"validateCode\" class=\"form-control code\"  placeholder=\"验证码\"   maxlength=\"5\" >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"col-xs-6\">\n\t\t\t\t\t\t\t<a href=\"javascript:void(0);\" title=\"点击更换验证码\">\n\t\t\t\t\t\t\t\t<img th:src=\"@{/captcha/captchaImage(type=${captchaType})}\" class=\"imgcode\" width=\"85%\"/>\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n                    <div class=\"checkbox-custom\" th:classappend=\"${captchaEnabled==false} ? 'm-t'\">\n\t\t\t\t        <input type=\"checkbox\" id=\"acceptTerm\" name=\"acceptTerm\"> <label for=\"acceptTerm\">我已阅读并同意</label>\n\t\t\t\t        <a href=\"https://gitee.com/y_project/RuoYi/blob/master/README.md\" target=\"_blank\">使用条款</a>\n\t\t\t\t    </div>\n                    <button class=\"btn btn-success btn-block\" id=\"btnSubmit\" data-loading=\"正在验证注册，请稍候...\">注册</button>\n                </form>\n            </div>\n        </div>\n        <div class=\"signup-footer\">\n            <div class=\"pull-left\">\n                &copy; 2018-2026 All Rights Reserved. RuoYi <br>\n            </div>\n        </div>\n    </div>\n<script th:inline=\"javascript\"> var ctx = [[@{/}]]; var captchaType = [[${captchaType}]]; var captchaEnabled = [[${captchaEnabled}]];</script>\n<!-- 全局js -->\n<script src=\"../static/js/jquery.min.js\" th:src=\"@{/js/jquery.min.js}\"></script>\n<script src=\"../static/ajax/libs/validate/jquery.validate.min.js\" th:src=\"@{/ajax/libs/validate/jquery.validate.min.js}\"></script>\n<script src=\"../static/ajax/libs/validate/jquery.validate.extend.js\" th:src=\"@{/ajax/libs/validate/jquery.validate.extend.js}\"></script>\n<script src=\"../static/ajax/libs/layer/layer.min.js\" th:src=\"@{/ajax/libs/layer/layer.min.js}\"></script>\n<script src=\"../static/ajax/libs/blockUI/jquery.blockUI.js\" th:src=\"@{/ajax/libs/blockUI/jquery.blockUI.js}\"></script>\n<script src=\"../static/ruoyi/js/ry-ui.js\" th:src=\"@{/ruoyi/js/ry-ui.js?v=4.8.2}\"></script>\n<script src=\"../static/ruoyi/register.js\" th:src=\"@{/ruoyi/register.js}\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/skin.html",
    "content": "<!DOCTYPE html>\n<html  lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"renderer\" content=\"webkit\">\n    <title>主题选择</title>\n    <!--[if lt IE 9]>\n    <meta http-equiv=\"refresh\" content=\"0;ie.html\"/>\n    <![endif]-->\n    <link rel=\"shortcut icon\" href=\"../static/favicon.ico\" th:href=\"@{favicon.ico}\"/>\n    <link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/style.min.css}\" rel=\"stylesheet\"/>\n    <style type=\"text/css\">\n\t\t.list-unstyled{margin:10px;}\n\t\t.full-opacity-hover{opacity:1;filter:alpha(opacity=1);border:1px solid #fff}\n\t\t.full-opacity-hover:hover{border:1px solid #f00;}\n\t</style>\n</head>\n<body class=\"gray-bg\">\n<ul class=\"list-unstyled clearfix\">\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-blue|theme-dark\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #367fa9\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #3c8dbc\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #2f4050\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">蓝</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-green|theme-dark\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #008d4c\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #00a65a\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">绿</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-purple|theme-dark\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #555299\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #605ca8\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">紫</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-red|theme-dark\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #dd4b39\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #d73925\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">红</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-yellow|theme-dark\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #f39c12\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #e08e0b\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">黄</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-blue|theme-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #367fa9\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #3c8dbc\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">蓝灰</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-green|theme-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #008d4c\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #00a65a\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">绿灰</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-purple|theme-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #555299\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #605ca8\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">紫灰</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-red|theme-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #dd4b39\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #d73925\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">红灰</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-yellow|theme-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #f39c12\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #e08e0b\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">黄灰</p>\n\t</li>\n\t\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-blue|theme-blue\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #367fa9\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #3c8dbc\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: rgba(15,41,80,1)\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">蓝浅</p>\n\t</li>\n\t<li style=\"float:left; width: 33.33333%; padding: 5px;\">\n\t\t<a href=\"javascript:\" data-skin=\"skin-green|theme-blue\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n\t\t\t<span style=\"width: 20%; float: left; height: 13px; background: #008d4c\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 13px; background: #00a65a\"></span>\n\t\t\t<span style=\"width: 20%; float: left; height: 30px; background: rgba(15,41,80,1)\"></span>\n\t\t\t<span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n\t\t</a>\n\t\t<p class=\"text-center\">绿浅</p>\n\t</li>\n</ul>\n</body>\n<script th:src=\"@{/js/jquery.min.js}\"></script>\n<script th:src=\"@{/ruoyi/js/common.js?v=4.8.2}\"></script>\n<script type=\"text/javascript\">\n//皮肤样式列表\nvar skins = [\"skin-blue\", \"skin-green\", \"skin-purple\", \"skin-red\", \"skin-yellow\"];\n\n// 主题样式列表\nvar themes = [\"theme-dark\", \"theme-light\", \"theme-blue\"];\n\n$(\"[data-skin]\").on('click',\nfunction(e) {\n    var skin = $(this).data('skin');\n    $.each(skins, function(i) {\n        parent.$(\"body\").removeClass(skins[i]);\n    });\n    $.each(themes, function(i) {\n        parent.$(\"body\").removeClass(themes[i]);\n    });\n    parent.$(\"body\").addClass(skin.split('|')[0]);\n    parent.$(\"body\").addClass(skin.split('|')[1]);\n    storage.set('skin', skin);\n});\n</script>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/config/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增参数')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n        <form class=\"form-horizontal m\" id=\"form-config-add\" name=\"form-config-add\">\r\n        <div class=\"form-group\">\t\r\n            <label class=\"col-sm-3 control-label is-required\">参数名称：</label>\r\n            <div class=\"col-sm-8\">\r\n                <input id=\"configName\" name=\"configName\" class=\"form-control\" type=\"text\" required>\r\n            </div>\r\n        </div>\r\n        <div class=\"form-group\">\t\r\n            <label class=\"col-sm-3 control-label is-required\">参数键名：</label>\r\n            <div class=\"col-sm-8\">\r\n                <input id=\"configKey\" name=\"configKey\" class=\"form-control\" type=\"text\" required>\r\n            </div>\r\n        </div>\r\n        <div class=\"form-group\">\t\r\n            <label class=\"col-sm-3 control-label is-required\">参数键值：</label>\r\n            <div class=\"col-sm-8\">\r\n                <textarea id=\"configValue\" name=\"configValue\" class=\"form-control\" rows=\"4\" required></textarea>\r\n            </div>\r\n        </div>\r\n        <div class=\"form-group\">\r\n\t\t\t<label class=\"col-sm-3 control-label\">系统内置：</label>\r\n\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_yes_no')}\">\r\n\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"configType\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t\t<div class=\"form-group\">\t\r\n            <label class=\"col-sm-3 control-label\">备注：</label>\r\n            <div class=\"col-sm-8\">\r\n                <textarea id=\"remark\" name=\"remark\" class=\"form-control\"></textarea>\r\n            </div>\r\n        </div>\r\n    </form>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n\t    var prefix = ctx + \"system/config\";\r\n\t\r\n\t    $(\"#form-config-add\").validate({\r\n\t    \tonkeyup: false,\r\n\t        rules: {\r\n\t            configKey: {\r\n\t                remote: {\r\n\t                    url: prefix + \"/checkConfigKeyUnique\",\r\n\t                    type: \"post\",\r\n\t                    dataType: \"json\",\r\n\t                    data: {\r\n\t                        \"configKey\": function() {\r\n\t                            return $.common.trim($(\"#configKey\").val());\r\n\t                        }\r\n\t                    }\r\n\t                }\r\n\t            },\r\n\t        },\r\n\t        messages: {\r\n\t            \"configKey\": {\r\n\t                remote: \"参数键名已经存在\"\r\n\t            }\r\n\t        },\r\n\t        focusCleanup: true\r\n\t    });\r\n\t    \r\n\t    function submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t            $.operate.save(prefix + \"/add\", $('#form-config-add').serialize());\r\n\t        }\r\n\t    }\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/config/config.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('参数列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"config-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t参数名称：<input type=\"text\" name=\"configName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t参数键名：<input type=\"text\" name=\"configKey\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t系统内置：<select name=\"configType\" th:with=\"type=${@dict.getType('sys_yes_no')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-time\">\r\n\t\t\t\t\t\t\t\t<label>创建时间： </label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[beginTime]\"/>\r\n\t\t\t\t\t\t\t\t<span>-</span>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[endTime]\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t        <a class=\"btn btn-success\" onclick=\"$.operate.add()\" shiro:hasPermission=\"system:config:add\">\r\n\t\t            <i class=\"fa fa-plus\"></i> 新增\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"system:config:edit\">\r\n\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"system:config:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"system:config:export\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-danger\" onclick=\"refreshCache()\" shiro:hasPermission=\"system:config:remove\">\r\n\t\t            <i class=\"fa fa-refresh\"></i> 刷新缓存\r\n\t\t        </a>\r\n\t        </div>\r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t            <table id=\"bootstrap-table\"></table>\r\n\t        </div>\r\n\t    </div>\r\n\t</div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script th:inline=\"javascript\">\r\n        var editFlag = [[${@permission.hasPermi('system:config:edit')}]];\r\n        var removeFlag = [[${@permission.hasPermi('system:config:remove')}]];\r\n        var datas = [[${@dict.getType('sys_yes_no')}]];\r\n        var prefix = ctx + \"system/config\";\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n                createUrl: prefix + \"/add\",\r\n                updateUrl: prefix + \"/edit/{id}\",\r\n                removeUrl: prefix + \"/remove\",\r\n                exportUrl: prefix + \"/export\",\r\n                sortName: \"configId\",\r\n\t\t        sortOrder: \"asc\",\r\n                modalName: \"参数\",\r\n                columns: [{\r\n                    checkbox: true\r\n                },\r\n                {\r\n                    field: 'configId',\r\n                    title: '参数主键'\r\n                },\r\n                {\r\n                    field: 'configName',\r\n                    title: '参数名称',\r\n                    formatter: function(value, row, index) {\r\n                        return $.table.tooltip(value);\r\n                    }\r\n                },\r\n                {\r\n                    field: 'configKey',\r\n                    title: '参数键名',\r\n                    formatter: function(value, row, index) {\r\n                        return $.table.tooltip(value);\r\n                    }\r\n                },\r\n                {\r\n                    field: 'configValue',\r\n                    title: '参数键值',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                        return $.table.tooltip(value, 10, \"open\");\r\n                    }\r\n                },\r\n                {\r\n                    field: 'configType',\r\n                    title: '系统内置',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                        return $.table.selectDictLabel(datas, value);\r\n                    }\r\n                },\r\n                {\r\n                    field: 'remark',\r\n                    title: '备注',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                        return $.table.tooltip(value, 10, \"open\");\r\n                    }\r\n                },\r\n                {\r\n                    field: 'createTime',\r\n                    title: '创建时间'\r\n                },\r\n                {\r\n                    title: '操作',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                        var actions = [];\r\n                        actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.configId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.configId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n                        return actions.join('');\r\n                    }\r\n                }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n        \r\n        /** 刷新参数缓存 */\r\n        function refreshCache() {\r\n            $.operate.get(prefix + \"/refreshCache\");\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/config/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改参数')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n        <form class=\"form-horizontal m\" id=\"form-config-edit\" th:object=\"${config}\">\r\n            <input id=\"configId\" name=\"configId\" th:field=\"*{configId}\"  type=\"hidden\">\r\n            <div class=\"form-group\">\t\r\n                <label class=\"col-sm-3 control-label is-required\">参数名称：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <input id=\"configName\" name=\"configName\" th:field=\"*{configName}\" class=\"form-control\" type=\"text\" required>\r\n                </div>\r\n            </div>\r\n            <div class=\"form-group\">\t\r\n                <label class=\"col-sm-3 control-label is-required\">参数键名：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <input id=\"configKey\" name=\"configKey\" th:field=\"*{configKey}\" class=\"form-control\" type=\"text\" required>\r\n                </div>\r\n            </div>\r\n            <div class=\"form-group\">\t\r\n                <label class=\"col-sm-3 control-label is-required\">参数键值：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <textarea id=\"configValue\" name=\"configValue\" class=\"form-control\" rows=\"4\" required>[[*{configValue}]]</textarea>\r\n                </div>\r\n            </div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">系统内置：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_yes_no')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"configType\" th:value=\"${dict.dictValue}\" th:field=\"*{configType}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\t\r\n\t            <label class=\"col-sm-3 control-label\">备注：</label>\r\n\t            <div class=\"col-sm-8\">\r\n\t                <textarea id=\"remark\" name=\"remark\" class=\"form-control\">[[*{remark}]]</textarea>\r\n\t            </div>\r\n\t        </div>\r\n    \t</form>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script type=\"text/javascript\">\r\n\t    var prefix = ctx + \"system/config\";\r\n\t    \r\n\t    $(\"#form-config-edit\").validate({\r\n\t    \tonkeyup: false,\r\n\t        rules: {\r\n\t            configKey: {\r\n\t                remote: {\r\n\t                    url: prefix + \"/checkConfigKeyUnique\",\r\n\t                    type: \"post\",\r\n\t                    dataType: \"json\",\r\n\t                    data: {\r\n\t                        \"configId\": function() {\r\n\t                        \treturn $(\"#configId\").val();\r\n\t                        },\r\n\t                        \"configKey\": function() {\r\n\t                        \treturn $.common.trim($(\"#configKey\").val());\r\n\t                        }\r\n\t                    }\r\n\t                }\r\n\t            },\r\n\t        },\r\n\t        messages: {\r\n\t            \"configKey\": {\r\n\t                remote: \"参数键名已经存在\"\r\n\t            }\r\n\t        },\r\n\t        focusCleanup: true\r\n\t    });\r\n\t    \r\n\t    function submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-config-edit').serialize());\r\n\t        }\r\n\t    }\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dept/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增部门')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-dept-add\">\r\n\t\t\t<input id=\"treeId\" name=\"parentId\" type=\"hidden\" th:value=\"${dept?.deptId}\"   />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">上级部门：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"input-group\">\r\n\t\t\t\t\t\t<input class=\"form-control\" type=\"text\" onclick=\"selectDeptTree()\" id=\"treeName\" readonly=\"true\" th:value=\"${dept?.deptName}\" required>\r\n\t\t\t\t\t    <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n\t\t\t\t    </div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">部门名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"deptName\" id=\"deptName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">显示排序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"orderNum\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">负责人：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"leader\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">联系电话：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"phone\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">邮箱：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"email\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">部门状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/dept\";\r\n\t\t\r\n\t\t$(\"#form-dept-add\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tdeptName:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: prefix + \"/checkDeptNameUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"parentId\": function() {\r\n\t\t                \t\treturn $(\"input[name='parentId']\").val();\r\n\t\t                    },\r\n\t\t                \t\"deptName\" : function() {\r\n\t\t                        return $.common.trim($(\"#deptName\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\torderNum:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t\temail:{\r\n                    email:true,\r\n        \t\t},\r\n        \t\tphone:{\r\n        \t\t\tisPhone:true,\r\n        \t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"deptName\": {\r\n\t\t            remote: \"部门已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/add\", $('#form-dept-add').serialize());\r\n\t        }\r\n\t    }\r\n\t\r\n\t\t/*部门管理-新增-选择父部门树*/\r\n\t\tfunction selectDeptTree() {\r\n\t\t\tvar treeId = $(\"#treeId\").val();\r\n\t\t\tif ($.common.isEmpty(treeId)) {\r\n       \t\t\t$.modal.alertWarning(\"请先添加用户所属的部门！\");\r\n       \t\t\treturn;\r\n       \t\t}\r\n\t\t\tvar options = {\r\n\t\t\t\ttitle: '部门选择',\r\n\t\t\t\twidth: \"380\",\r\n\t\t\t\turl: prefix + \"/selectDeptTree/\" + treeId + \"/0\",\r\n\t\t\t\tcallBack: doSubmit\r\n\t\t\t};\r\n\t\t\t$.modal.openOptions(options);\r\n\t\t}\r\n\t\t\r\n\t\tfunction doSubmit(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#treeId\").val(body.find('#treeId').val());\r\n   \t\t\t$(\"#treeName\").val(body.find('#treeName').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dept/dept.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('部门列表')\" />\n</head>\n<body class=\"gray-bg\">\n\t<div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 search-collapse\">\n\t\t\t\t<form id=\"dept-form\">\n\t\t\t\t\t<div class=\"select-list\">\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t部门名称：<input type=\"text\" name=\"deptName\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t部门状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_normal_disable')}\">\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\n\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.treeTable.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</div>\n                \n            <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\n\t\t        <a class=\"btn btn-success\" onclick=\"$.operate.add(100)\" shiro:hasPermission=\"system:dept:add\">\n                    <i class=\"fa fa-plus\"></i> 新增\n                </a>\n                <a class=\"btn btn-primary\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"system:dept:edit\">\n\t\t            <i class=\"fa fa-edit\"></i> 修改\n\t\t        </a>\n                <a class=\"btn btn-info\" onclick=\"saveSort()\">\n                    <i class=\"fa fa-sort-amount-asc\"></i> 保存排序\n                </a>\n                <a class=\"btn btn-default\" id=\"expandAllBtn\">\n                    <i class=\"fa fa-exchange\"></i> 展开/折叠\n                </a>\n\t        </div>\n       \t\t <div class=\"col-sm-12 select-table table-striped\">\n\t            <table id=\"bootstrap-tree-table\"></table>\n\t        </div>\n\t    </div>\n\t</div>\n\t<th:block th:include=\"include :: footer\" />\n\t<script th:inline=\"javascript\">\n\t\tvar addFlag = [[${@permission.hasPermi('system:dept:add')}]];\n\t\tvar editFlag = [[${@permission.hasPermi('system:dept:edit')}]];\n\t\tvar removeFlag = [[${@permission.hasPermi('system:dept:remove')}]];\n\t\tvar datas = [[${@dict.getType('sys_normal_disable')}]];\n\t\tvar prefix = ctx + \"system/dept\"\n\t\tvar originalOrders = {};\n\n\t\t$(function() {\n\t\t    var options = {\n\t\t        code: \"deptId\",\n\t\t        parentCode: \"parentId\",\n\t\t        uniqueId: \"deptId\",\n\t\t        url: prefix + \"/list\",\n\t\t        createUrl: prefix + \"/add/{id}\",\n\t\t        updateUrl: prefix + \"/edit/{id}\",\n\t\t        removeUrl: prefix + \"/remove/{id}\",\n\t\t        modalName: \"部门\",\n\t\t        columns: [{\n                    field: 'selectItem', \n                    radio: true\n                 },\n                 {\n\t\t            field: 'deptName',\n\t\t            title: '部门名称',\n\t\t            align: \"left\"\n\t\t        },\n\t\t        {\n\t\t            field: 'orderNum',\n\t\t            title: '排序',\n\t\t            align: \"left\",\n\t\t            formatter: function(value, row, index) {\n\t\t                var deptIdText = $.common.sprintf(\"<input type='hidden' name='deptIds' value='%s'>\", row.deptId);\n\t\t                var orderNumText = $.common.sprintf(\"<input type='text' name='orderNums' value='%s' class='form-control' style='display:inline-block;width:60px;text-align:center;'>\", row.orderNum);\n\t\t                originalOrders[row.deptId] = row.orderNum;\n\t\t                return deptIdText + orderNumText;\n\t\t            }\n\t\t        },\n\t\t        {\n\t\t            field: 'status',\n\t\t            title: '状态',\n\t\t            align: \"left\",\n\t\t            formatter: function(value, item, index) {\n\t\t            \treturn $.table.selectDictLabel(datas, item.status);\n\t\t            }\n\t\t        },\n\t\t        {\n\t\t            field: 'createTime',\n\t\t            title: '创建时间',\n\t\t            align: \"left\"\n\t\t        },\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'left',\n\t\t            formatter: function(value, row, index) {\n\t\t                if (row.parentId != 0) {\n\t\t                    var actions = [];\n\t\t                    actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.deptId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\n\t\t                    actions.push('<a class=\"btn btn-info  btn-xs ' + addFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.add(\\'' + row.deptId + '\\')\"><i class=\"fa fa-plus\"></i>新增</a> ');\n\t\t                    actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.deptId + '\\')\"><i class=\"fa fa-trash\"></i>删除</a>');\n\t\t                    return actions.join('');\n\t\t                } else {\n\t\t                    return \"\";\n\t\t                }\n\t\t            }\n\t\t        }]\n\t\t    };\n\t\t    $.treeTable.init(options);\n\t\t});\n\n\t\t/* 保存排序-部门 */\n\t\tfunction saveSort() {\n\t\t\tvar changedDeptIds = [];\n\t\t\tvar changedOrderNums = [];\n\t\t    $(\"input[name='deptIds']\").each(function() {\n\t\t        var deptId = $(this).val();\n\t\t        var currentOrder = $(this).next(\"input[name='orderNums']\").val();\n\t\t        if (String(originalOrders[deptId]) !== String(currentOrder)) {\n\t\t            changedDeptIds.push(deptId);\n\t\t            changedOrderNums.push(currentOrder);\n\t\t        }\n\t\t    });\n\t\t    if (changedDeptIds.length === 0) {\n\t\t        $.modal.alertWarning(\"未检测到排序修改\");\n\t\t        return;\n\t\t    }\n\t\t    $.operate.post(prefix + \"/updateSort\", { \"deptIds\": changedDeptIds.join(\",\"), \"orderNums\": changedOrderNums.join(\",\") });\n\t\t}\n\t</script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dept/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改部门')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-dept-edit\" th:object=\"${dept}\">\r\n\t\t\t<input name=\"deptId\" type=\"hidden\" th:field=\"*{deptId}\" />\r\n\t\t\t<input id=\"treeId\" name=\"parentId\" type=\"hidden\" th:field=\"*{parentId}\" />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">上级部门：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"input-group\">\r\n\t\t\t\t\t\t<input class=\"form-control\" type=\"text\" id=\"treeName\" onclick=\"selectDeptTree()\" readonly=\"true\" th:field=\"*{parentName}\">\r\n\t\t\t\t\t    <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n\t\t\t\t    </div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">部门名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"deptName\" th:field=\"*{deptName}\" id=\"deptName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">显示排序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"orderNum\" th:field=\"*{orderNum}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">负责人：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"leader\" th:field=\"*{leader}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">联系电话：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"phone\" th:field=\"*{phone}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">邮箱：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"email\" th:field=\"*{email}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">部门状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:field=\"*{status}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/dept\";\r\n\t\t\r\n\t\t$(\"#form-dept-edit\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tdeptName:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: prefix + \"/checkDeptNameUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"deptId\": function() {\r\n\t\t                        return $(\"#deptId\").val();\r\n\t\t                    },\r\n\t\t                    \"parentId\": function() {\r\n\t\t                        return $(\"input[name='parentId']\").val();\r\n\t\t                    },\r\n\t\t        \t\t\t\"deptName\": function() {\r\n\t\t                        return $.common.trim($(\"#deptName\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\torderNum:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t\temail:{\r\n                    email:true,\r\n        \t\t},\r\n        \t\tphone:{\r\n        \t\t\tisPhone:true,\r\n        \t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"deptName\": {\r\n\t\t            remote: \"部门已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-dept-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t\r\n\t\t/*部门管理-修改-选择部门树*/\r\n\t\tfunction selectDeptTree() {\r\n\t\t\tvar deptId = $(\"#treeId\").val();\r\n\t\t\tvar excludeId = $(\"input[name='deptId']\").val();\r\n\t\t\tif(deptId > 0) {\r\n\t\t\t    var options = {\r\n\t\t\t\t\ttitle: '部门选择',\r\n\t\t\t\t\twidth: \"380\",\r\n\t\t\t\t\turl: prefix + \"/selectDeptTree/\" + $(\"#treeId\").val() + \"/\" + excludeId,\r\n\t\t\t\t\tcallBack: doSubmit\r\n\t\t\t\t};\r\n\t\t\t\t$.modal.openOptions(options);\r\n\t\t\t} else {\r\n        \t\t$.modal.alertError(\"父部门不能选择\");\r\n        \t}\r\n\t\t}\r\n\t\t\r\n\t\tfunction doSubmit(index, layero){\r\n\t\t\tvar tree = layero.find(\"iframe\")[0].contentWindow.$._tree;\r\n\t\t\tif ($.tree.notAllowLastLevel(tree)) {\r\n\t   \t\t\tvar body = $.modal.getChildFrame(index);\r\n\t   \t\t\t$(\"#treeId\").val(body.find('#treeId').val());\r\n\t   \t\t\t$(\"#treeName\").val(body.find('#treeName').val());\r\n\t   \t\t\t$.modal.close(index);\r\n\t\t\t}\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dept/tree.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('部门树选择')\" />\r\n\t<th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<style>\r\n\tbody{height:auto;font-family: \"Microsoft YaHei\";}\r\n\tbutton{font-family: \"SimSun\",\"Helvetica Neue\",Helvetica,Arial;}\r\n</style>\r\n<body class=\"hold-transition box box-main\">\r\n\t<input id=\"treeId\"   name=\"treeId\"    type=\"hidden\" th:value=\"${dept.deptId}\"/>\r\n\t<input id=\"treeName\" name=\"treeName\"  type=\"hidden\" th:value=\"${dept.deptName}\"/>\r\n\t<div class=\"wrapper\"><div class=\"treeShowHideButton\" onclick=\"$.tree.toggleSearch();\">\r\n\t\t<label id=\"btnShow\" title=\"显示搜索\" style=\"display:none;\">︾</label>\r\n\t\t<label id=\"btnHide\" title=\"隐藏搜索\">︽</label>\r\n\t</div>\r\n\t<div class=\"treeSearchInput\" id=\"search\">\r\n\t\t<label for=\"keyword\">关键字：</label><input type=\"text\" class=\"empty\" id=\"keyword\" maxlength=\"50\">\r\n\t\t<button class=\"btn\" id=\"btn\" onclick=\"$.tree.searchNode()\"> 搜索 </button>\r\n\t</div>\r\n\t<div class=\"treeExpandCollapse\">\r\n\t\t<a href=\"javascript:;\" onclick=\"$.tree.expand()\">展开</a> /\r\n\t\t<a href=\"javascript:;\" onclick=\"$.tree.collapse()\">折叠</a>\r\n\t</div>\r\n\t<div id=\"tree\" class=\"ztree treeselect\"></div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: ztree-js\" />\r\n\t<script th:inline=\"javascript\">\r\n\t    var prefix = ctx + \"system/dept\"\r\n\t    var deptId = [[${deptId}]];\r\n\t    var excludeId = [[${excludeId}]];\r\n\t\t$(function() {\r\n\t\t\tvar url = prefix + \"/treeData/\" + excludeId;\r\n\t\t\tvar options = {\r\n\t\t        url: url,\r\n\t\t        expandLevel: 2,\r\n\t\t        onClick : zOnClick\r\n\t\t    };\r\n\t\t\t$.tree.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction zOnClick(event, treeId, treeNode) {\r\n\t\t    var treeId = treeNode.id;\r\n\t\t    var treeName = treeNode.name;\r\n\t\t    $(\"#treeId\").val(treeId);\r\n\t\t    $(\"#treeName\").val(treeName);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dict/data/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增字典数据')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-dict-add\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典标签：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictLabel\" id=\"dictLabel\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典键值：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictValue\" id=\"dictValue\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">字典类型：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" id=\"dictType\" name=\"dictType\" readonly=\"true\" th:value=\"${dictType}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">样式属性：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" id=\"cssClass\" name=\"cssClass\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典排序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictSort\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">回显样式：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<select name=\"listClass\" class=\"form-control m-b\">\r\n\t\t\t\t\t    <option value=\"\">---请选择---</option>\r\n\t                    <option value=\"default\">默认</option>\r\n\t                    <option value=\"primary\">主要</option>\r\n\t                    <option value=\"success\">成功</option>\r\n\t                    <option value=\"info\">   信息</option>\r\n\t                    <option value=\"warning\">警告</option>\r\n\t                    <option value=\"danger\"> 危险</option>\r\n\t                </select>\r\n\t                <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> table表格字典列显示样式属性</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">系统默认：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_yes_no')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"isDefault\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\"></textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/dict/data\";\r\n\t\r\n\t\t$(\"#form-dict-add\").validate({\r\n\t\t\trules:{\r\n\t\t\t\tdictSort:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tfocusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/add\", $('#form-dict-add').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dict/data/data.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('字典数据列表')\" />\r\n\t<th:block th:include=\"include :: select2-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"data-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t    <li>\r\n\t\t\t\t\t\t\t\t字典名称：<select id=\"dictType\" name=\"dictType\" class=\"form-control\">\r\n\t\t\t\t\t                <option th:each=\"dict : ${dictList}\" th:text=\"${dict['dictName']}\" th:value=\"${dict['dictType']}\" th:field=\"*{dict.dictType}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t字典标签：<input type=\"text\" name=\"dictLabel\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t数据状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t\t\t\t      <option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t      <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t      </select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"resetPre()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t       <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t            <a class=\"btn btn-success\" onclick=\"add()\" shiro:hasPermission=\"system:dict:add\">\r\n\t                <i class=\"fa fa-plus\"></i> 新增\r\n\t            </a>\r\n\t            <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"system:dict:edit\">\r\n\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t        </a>\r\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"system:dict:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"system:dict:export\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-danger\" onclick=\"closeItem()\">\r\n\t\t            <i class=\"fa fa-reply-all\"></i> 关闭\r\n\t\t        </a>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: select2-js\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar editFlag = [[${@permission.hasPermi('system:dict:edit')}]];\r\n\t\tvar removeFlag = [[${@permission.hasPermi('system:dict:remove')}]];\r\n\t\tvar datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\t\tvar prefix = ctx + \"system/dict/data\";\r\n\r\n\t\t$(function() {\r\n\t\t\tvar options = {\r\n\t\t\t\turl: prefix + \"/list\",\r\n\t\t\t\tcreateUrl: prefix + \"/add/{id}\",\r\n\t\t\t\tupdateUrl: prefix + \"/edit/{id}\",\r\n\t\t\t\tremoveUrl: prefix + \"/remove\",\r\n\t\t\t\texportUrl: prefix + \"/export\",\r\n\t\t\t\tqueryParams: queryParams,\r\n\t\t\t\tsortName: \"dictSort\",\r\n\t\t        sortOrder: \"asc\",\r\n\t\t\t\tmodalName: \"数据\",\r\n\t\t\t\tcolumns: [{\r\n\t\t\t\t\t\tcheckbox: true\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfield: 'dictCode',\r\n\t\t\t\t\t\ttitle: '字典编码'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfield: 'dictLabel',\r\n\t\t\t\t\t\ttitle: '字典标签',\r\n\t\t\t\t\t\tformatter: function(value, row, index) {\r\n\t\t\t\t\t\t\tvar listClass = $.common.equals(\"default\", row.listClass) || $.common.isEmpty(row.listClass) ? \"\" : \"badge badge-\" + row.listClass;\r\n\t\t\t\t\t\t\tvar cssClass = $.common.isNotEmpty(row.cssClass) ? row.cssClass : listClass;\r\n\t\t\t\t\t\t\treturn $.common.sprintf(\"<span class='%s'>%s</span>\", cssClass, value);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfield: 'dictValue',\r\n\t\t\t\t\t\ttitle: '字典键值'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfield: 'dictSort',\r\n\t\t\t\t\t\ttitle: '字典排序'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfield: 'status',\r\n\t\t\t\t\t\ttitle: '状态',\r\n\t\t\t\t\t\talign: 'center',\r\n\t\t\t\t\t\tformatter: function(value, row, index) {\r\n\t\t\t\t\t\t\treturn $.table.selectDictLabel(datas, value);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfield: 'remark',\r\n\t\t\t\t\t\ttitle: '备注'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfield: 'createTime',\r\n\t\t\t\t\t\ttitle: '创建时间',\r\n\t\t\t\t\t\tsortable: true\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttitle: '操作',\r\n\t\t\t\t\t\talign: 'center',\r\n\t\t\t\t\t\tformatter: function(value, row, index) {\r\n\t\t\t\t\t\t\tvar actions = [];\r\n\t\t\t\t\t\t\tactions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.dictCode + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n\t\t\t\t\t\t\tactions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.dictCode + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\t\treturn actions.join('');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}]\r\n\t\t\t\t};\r\n\t\t\t$.table.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction queryParams(params) {\r\n\t\t\tvar search = $.table.queryParams(params);\r\n\t\t\tsearch.dictType = $(\"#dictType\").val();\r\n\t\t\treturn search;\r\n\t\t}\r\n\t\t\r\n\t\t/*字典数据-新增字典*/\r\n\t\tfunction add() {\r\n\t\t    var dictType = $(\"#dictType option:selected\").val();\r\n\t\t    $.operate.add(dictType);\r\n\t\t}\r\n\t\t\r\n\t\tfunction resetPre() {\r\n\t\t\t$.form.reset();\r\n\t\t\t$(\"#dictType\").val($(\"#dictType\").val()).trigger(\"change\");\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dict/data/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改字典数据')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-dict-edit\" th:object=\"${dict}\">\r\n\t\t\t<input name=\"dictCode\"  type=\"hidden\"  th:field=\"*{dictCode}\" />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典标签：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictLabel\" id=\"dictLabel\" th:field=\"*{dictLabel}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典键值：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictValue\" id=\"dictValue\" th:field=\"*{dictValue}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">字典类型：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" readonly=\"true\" th:field=\"*{dictType}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">样式属性：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" id=\"cssClass\" name=\"cssClass\" th:field=\"*{cssClass}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典排序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictSort\" th:field=\"*{dictSort}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">回显样式：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<select name=\"listClass\" class=\"form-control m-b\">\r\n\t\t\t\t\t    <option value=\"\"        th:field=\"*{listClass}\">---请选择---</option>\r\n\t                    <option value=\"default\" th:field=\"*{listClass}\">默认</option>\r\n\t                    <option value=\"primary\" th:field=\"*{listClass}\">主要</option>\r\n\t                    <option value=\"success\" th:field=\"*{listClass}\">成功</option>\r\n\t                    <option value=\"info\"    th:field=\"*{listClass}\">信息</option>\r\n\t                    <option value=\"warning\" th:field=\"*{listClass}\">警告</option>\r\n\t                    <option value=\"danger\"  th:field=\"*{listClass}\">危险</option>\r\n\t                </select>\r\n\t                <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> table表格字典列显示样式属性</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">系统默认：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_yes_no')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"isDefault\" th:value=\"${dict.dictValue}\" th:field=\"*{isDefault}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:field=\"*{status}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\">[[*{remark}]]</textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/dict/data\";\r\n\t\r\n\t\t$(\"#form-dict-edit\").validate({\r\n\t\t\trules:{\r\n\t\t\t\tdictSort:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tfocusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-dict-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dict/type/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增字典类型')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-dict-add\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictName\" id=\"dictName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典类型：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictType\" id=\"dictType\" required>\r\n\t\t\t\t\t<span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 数据存储中的Key值，如：sys_user_sex</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\"></textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/dict\";\r\n\t\r\n\t\t$(\"#form-dict-add\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tdictType:{\r\n\t\t\t\t\tminlength: 5,\r\n\t\t\t\t\tremote: {\r\n\t\t                url: prefix + \"/checkDictTypeUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \tname : function() {\r\n\t\t                        return $.common.trim($(\"#dictType\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"dictType\": {\r\n\t\t            remote: \"该字典类型已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/add\", $('#form-dict-add').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dict/type/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改字典类型')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-dict-edit\" th:object=\"${dict}\">\r\n\t\t\t<input id=\"dictId\" name=\"dictId\"  type=\"hidden\" th:field=\"*{dictId}\" />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictName\" id=\"dictName\" th:field=\"*{dictName}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">字典类型：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"dictType\" id=\"dictType\" th:field=\"*{dictType}\" required>\r\n\t\t\t\t\t<span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 数据存储中的Key值，如：sys_user_sex</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:field=\"*{status}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\">[[*{remark}]]</textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/dict\";\r\n\t\r\n\t\t$(\"#form-dict-edit\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tdictType:{\r\n\t\t\t\t\tminlength: 5,\r\n\t\t\t\t\tremote: {\r\n\t\t                url: prefix + \"/checkDictTypeUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \tdictId : function() {\r\n\t\t                        return $(\"#dictId\").val();\r\n\t\t                    },\r\n\t\t                \tdictType : function() {\r\n\t\t                \t\treturn $.common.trim($(\"#dictType\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"dictType\": {\r\n\t\t            remote: \"该字典类型已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-dict-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dict/type/tree.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('字典树选择')\" />\r\n\t<th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<style>\r\n\tbody{height:auto;font-family: \"Microsoft YaHei\";}\r\n\tbutton{font-family: \"SimSun\",\"Helvetica Neue\",Helvetica,Arial;}\r\n</style>\r\n<body class=\"hold-transition box box-main\">\r\n\t<input id=\"columnId\" type=\"hidden\" th:value=\"${columnId}\"/>\r\n\t<input id=\"treeId\"   type=\"hidden\" th:value=\"${dict?.dictId}\"/>\r\n\t<input id=\"dictType\" type=\"hidden\" th:value=\"${dict?.dictType}\"/>\r\n\t<div class=\"wrapper\"><div class=\"treeShowHideButton\" onclick=\"$.tree.toggleSearch();\">\r\n\t\t<label id=\"btnShow\" title=\"显示搜索\" style=\"display:none;\">︾</label>\r\n\t\t<label id=\"btnHide\" title=\"隐藏搜索\">︽</label>\r\n\t</div>\r\n\t<div class=\"treeSearchInput\" id=\"search\">\r\n\t\t<label for=\"keyword\">关键字：</label><input type=\"text\" class=\"empty\" id=\"keyword\" maxlength=\"50\">\r\n\t\t<button class=\"btn\" id=\"btn\" onclick=\"$.tree.searchNode()\"> 搜索 </button>\r\n\t</div>\r\n\t<div id=\"tree\" class=\"ztree treeselect\"></div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: ztree-js\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\t$(function() {\r\n\t\t\tvar url = ctx + \"system/dict/treeData\";\r\n\t\t\tvar options = {\r\n\t\t        url: url,\r\n\t\t        onClick : zOnClick\r\n\t\t    };\r\n\t\t\t$.tree.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction zOnClick(event, treeId, treeNode) {\r\n\t\t    $(\"#dictType\").val(treeNode.title);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/dict/type/type.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('字典类型列表')\" />\n\t<style>.drawer-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.18);z-index:1040}.drawer-panel{position:fixed;top:0;right:0;width:800px;max-width:95vw;height:100%;background:#fff;z-index:1050;box-shadow:-4px 0 24px rgba(0,0,0,0.13);transform:translateX(100%);transition:transform .28s cubic-bezier(.4,0,.2,1);display:flex;flex-direction:column}.drawer-panel.open{transform:translateX(0)}.drawer-head{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;border-bottom:1px solid #e8ecf0;background:#f7f9fb;flex-shrink:0}.drawer-head-left{display:flex;align-items:center;gap:10px}.drawer-title{font-size:14px;font-weight:600;color:#2c3e50}.drawer-subtitle{font-size:12px;color:#95a5a6;font-family:monospace}.drawer-close{background:0;border:0;font-size:18px;color:#aaa;cursor:pointer;line-height:1;padding:2px 6px;border-radius:4px}.drawer-close:hover{background:#f0f2f5;color:#555}.drawer-body{flex:1;overflow-y:auto;padding:16px 20px}.drawer-loading{display:flex;align-items:center;justify-content:center;height:120px;color:#aaa;font-size:13px;gap:8px}.drawer-empty{text-align:center;color:#bbb;padding:40px 0;font-size:13px}.dict-card-wrap{border:1px solid #e8ecf0;border-radius:6px;overflow:hidden;margin-bottom:8px}.dict-card{display:grid;grid-template-columns:1fr 1fr 1fr}.dict-card-row{display:grid;grid-template-columns:82px 1fr;border-bottom:1px solid #f0f4f8;border-right:1px solid #f0f4f8}.dict-card-row:nth-child(3n){border-right:0}.dict-card-row:nth-last-child(-n+3){border-bottom:0}.dict-card-key{padding:9px 14px;font-size:12px;color:#888;background:#f7f9fb;border-right:1px solid #f0f4f8}.dict-card-val{padding:9px 14px;font-size:13px;color:#2c3e50;word-break:break-all}.dict-card-row.dict-card-full{grid-column:1 / -1;border-right:0;border-bottom:0}.dict-badge{display:inline-block;padding:2px 8px;border-radius:3px;font-size:11px;font-weight:600}.dict-badge-ok{background:#f0faf4;color:#27ae60;border:1px solid #b7dfca}.dict-badge-off{background:#fff5f5;color:#e74c3c;border:1px solid #f5c6c6}.drawer-stats{display:flex;gap:12px;margin-bottom:14px}.drawer-stat{flex:1;background:#f7f9fb;border:1px solid #e8ecf0;border-radius:6px;padding:10px 14px;text-align:center}.drawer-stat-num{font-size:20px;font-weight:700;color:#2c3e50}.drawer-stat-label{font-size:11px;color:#95a5a6;margin-top:2px}</style>\n</head>\n<body class=\"gray-bg\">\n\t<div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 search-collapse\">\n\t\t\t\t<form id=\"type-form\">\n\t\t\t\t\t<div class=\"select-list\">\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t字典名称：<input type=\"text\" name=\"dictName\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t字典类型：<input type=\"text\" name=\"dictType\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t字典状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_normal_disable')}\">\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\n\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li class=\"select-time\">\n\t\t\t\t\t\t\t\t<label>创建时间： </label>\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[beginTime]\"/>\n\t\t\t\t\t\t\t\t<span>-</span>\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[endTime]\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t\t\n\t       <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\n\t            <a class=\"btn btn-success\" onclick=\"$.operate.add()\" shiro:hasPermission=\"system:dict:add\">\n\t                <i class=\"fa fa-plus\"></i> 新增\n\t            </a>\n\t            <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"system:dict:edit\">\n\t\t            <i class=\"fa fa-edit\"></i> 修改\n\t\t        </a>\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"system:dict:remove\">\n\t\t            <i class=\"fa fa-remove\"></i> 删除\n\t\t        </a>\n\t\t        <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"system:dict:export\">\n\t\t            <i class=\"fa fa-download\"></i> 导出\n\t\t        </a>\n\t\t        <a class=\"btn btn-danger\" onclick=\"refreshCache()\" shiro:hasPermission=\"system:dict:remove\">\n\t\t            <i class=\"fa fa-refresh\"></i> 刷新缓存\n\t\t        </a>\n\t        </div>\n\t        \n\t        <div class=\"col-sm-12 select-table table-striped\">\n\t\t\t    <table id=\"bootstrap-table\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t\n\t<!-- 抽屉遮罩 -->\n\t<div class=\"drawer-mask\" id=\"drawerMask\" onclick=\"closeDrawer()\"></div>\n\n\t<!-- 抽屉面板 -->\n\t<div class=\"drawer-panel\" id=\"drawerPanel\">\n\t\t<div class=\"drawer-head\">\n\t\t\t<div class=\"drawer-head-left\">\n\t\t\t\t<i class=\"fa fa-list-ul\" style=\"color:#5b9bd5;\"></i>\n\t\t\t\t<span class=\"drawer-title\" id=\"drawerTitle\">字典数据</span>\n\t\t\t\t<span class=\"drawer-subtitle\" id=\"drawerSubtitle\"></span>\n\t\t\t</div>\n\t\t\t<button class=\"drawer-close\" onclick=\"closeDrawer()\" title=\"关闭\">&#10005;</button>\n\t\t</div>\n\t\t<div class=\"drawer-body\" id=\"drawerBody\">\n\t\t\t<div class=\"drawer-loading\"><i class=\"fa fa-spinner fa-spin\"></i> 加载中...</div>\n\t\t</div>\n\t</div>\n\t\n\t<th:block th:include=\"include :: footer\" />\n\t<script th:inline=\"javascript\">\n\t\tvar editFlag = [[${@permission.hasPermi('system:dict:edit')}]];\n\t\tvar listFlag = [[${@permission.hasPermi('system:dict:list')}]];\n\t\tvar removeFlag = [[${@permission.hasPermi('system:dict:remove')}]];\n\t\tvar datas = [[${@dict.getType('sys_normal_disable')}]];\n\t\tvar prefix = ctx + \"system/dict\";\n\n\t\t$(function() {\n\t\t    var options = {\n\t\t        url: prefix + \"/list\",\n\t\t        createUrl: prefix + \"/add\",\n\t\t        updateUrl: prefix + \"/edit/{id}\",\n\t\t        removeUrl: prefix + \"/remove\",\n\t\t        exportUrl: prefix + \"/export\",\n\t\t        sortName: \"dictId\",\n\t\t        sortOrder: \"asc\",\n\t\t        modalName: \"类型\",\n\t\t        columns: [{\n\t\t            checkbox: true\n\t\t        },\n\t\t        {\n\t\t            field: 'dictId',\n\t\t            title: '字典主键'\n\t\t        },\n\t\t        {\n\t\t            field: 'dictName',\n\t\t            title: '字典名称',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t            field: 'dictType',\n\t\t            title: '字典类型',\n\t\t            sortable: true,\n\t\t            formatter: function(value, row, index) {\n\t\t                return '<a href=\"javascript:void(0)\" onclick=\"view(\\'' + row.dictId + '\\')\">' + value + '</a>';\n\t\t            }\n\t\t        },\n\t\t        {\n\t\t            field: 'status',\n\t\t            title: '状态',\n\t\t            align: 'center',\n\t\t            formatter: function(value, row, index) {\n\t\t            \treturn $.table.selectDictLabel(datas, value);\n\t\t            }\n\t\t        },\n\t\t        {\n\t\t            field: 'remark',\n\t\t            title: '备注',\n\t\t            formatter: function(value, row, index) {\n                        return $.table.tooltip(value);\n\t\t\t        }\n\t\t        },\n\t\t        {\n\t\t            field: 'createTime',\n\t\t            title: '创建时间',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'center',\n\t\t            formatter: function(value, row, index) {\n\t\t                var actions = [];\n\t\t                actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.dictId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\n\t\t                actions.push('<a class=\"btn btn-info btn-xs ' + listFlag + '\" href=\"javascript:void(0)\" onclick=\"detail(\\'' + row.dictId + '\\')\"><i class=\"fa fa-list-ul\"></i>列表</a> ');\n\t\t                actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.dictId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\n\t\t                return actions.join('');\n\t\t            }\n\t\t        }]\n\t\t    };\n\t\t    $.table.init(options);\n\t\t});\n\n\t\t/*字典列表-详细*/\n\t\tfunction detail(dictId) {\n\t\t    var url = prefix + '/detail/' + dictId;\n\t\t    $.modal.openTab(\"字典数据\", url);\n\t\t}\n\t\t\n\t\t/** 刷新字典缓存 */\n        function refreshCache() {\n            $.operate.get(prefix + \"/refreshCache\");\n        }\n\t\t\n        /* 打开抽屉并加载字典数据 */\n\t\tfunction view(dictId) {\n\t\t\tvar row = null;\n\t\t\tvar $rows = $(\"#bootstrap-table\").bootstrapTable('getData');\n\t\t\tfor (var i = 0; i < $rows.length; i++) {\n\t\t\t\tif (String($rows[i].dictId) === String(dictId)) { row = $rows[i]; break; }\n\t\t\t}\n\t\t\tvar typeName = row ? row.dictName : '字典数据';\n\t\t\tvar typeKey  = row ? row.dictType : '';\n\n\t\t\t$(\"#drawerTitle\").text(typeName);\n\t\t\t$(\"#drawerSubtitle\").text(typeKey);\n\t\t\t$(\"#drawerBody\").html('<div class=\"drawer-loading\"><i class=\"fa fa-spinner fa-spin\"></i> 加载中...</div>');\n\n\t\t\t$(\"#drawerMask\").show();\n\t\t\t$(\"#drawerPanel\").addClass(\"open\");\n\t\t\t$(\"body\").css(\"overflow\", \"hidden\");\n\n\t\t\t// 请求字典数据列表\n\t\t\t$.ajax({\n\t\t\t\turl: ctx + \"system/dict/data/list\",\n\t\t\t\ttype: \"post\",\n\t\t\t\tdata: { dictType: typeKey, pageSize: 100, pageNum: 1 },\n\t\t\t\tdataType: \"json\",\n\t\t\t\tsuccess: function(res) {\n\t\t\t\t\tvar rows = (res && res.rows) ? res.rows : [];\n\t\t\t\t\trenderDrawer(rows);\n\t\t\t\t},\n\t\t\t\terror: function() {\n\t\t\t\t\t$(\"#drawerBody\").html('<div class=\"drawer-empty\"><i class=\"fa fa-exclamation-circle\"></i><br>加载失败，请重试</div>');\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* 渲染抽屉内容 */\n\t\tfunction renderDrawer(rows) {\n\t\t\tif (!rows || rows.length === 0) {\n\t\t\t\t$(\"#drawerBody\").html('<div class=\"drawer-empty\"><i class=\"fa fa-inbox fa-2x\"></i><br><br>暂无字典数据</div>');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar okCount  = rows.filter(function(r){ return r.status === '0'; }).length;\n\t\t\tvar offCount = rows.length - okCount;\n\n\t\t\tvar html = '';\n\t\t\t// 统计\n\t\t\thtml += '<div class=\"drawer-stats\">';\n\t\t\thtml += '  <div class=\"drawer-stat\"><div class=\"drawer-stat-num\">' + rows.length + '</div><div class=\"drawer-stat-label\">共计条目</div></div>';\n\t\t\thtml += '  <div class=\"drawer-stat\"><div class=\"drawer-stat-num\" style=\"color:#27ae60;\">' + okCount + '</div><div class=\"drawer-stat-label\">正常</div></div>';\n\t\t\tif (offCount > 0) {\n\t\t\t\thtml += '  <div class=\"drawer-stat\"><div class=\"drawer-stat-num\" style=\"color:#e74c3c;\">' + offCount + '</div><div class=\"drawer-stat-label\">停用</div></div>';\n\t\t\t}\n\t\t\thtml += '</div>';\n\n\t\t\t// 数据卡片列表\n\t\t\tfor (var i = 0; i < rows.length; i++) {\n\t\t\t\tvar r = rows[i];\n\t\t\t\tvar statusBadge = (r.status === '0')\n\t\t\t\t\t? '<span class=\"dict-badge dict-badge-ok\">正常</span>'\n\t\t\t\t\t: '<span class=\"dict-badge dict-badge-off\">停用</span>';\n\n\t\t\t\tvar labelHtml = r.dictLabel;\n\t\t\t\tif (r.listClass && r.listClass !== 'default') {\n\t\t\t\t\tlabelHtml = '<span class=\"badge badge-' + r.listClass + '\">' + r.dictLabel + '</span>';\n\t\t\t\t} else if (r.cssClass) {\n\t\t\t\t\tlabelHtml = '<span class=\"' + r.cssClass + '\">' + r.dictLabel + '</span>';\n\t\t\t\t}\n\n\t\t\t\thtml += '<div class=\"dict-card-wrap\"><div class=\"dict-card\">';\n\t\t\t\thtml += '  <div class=\"dict-card-row\"><div class=\"dict-card-key\">标签</div><div class=\"dict-card-val\">' + labelHtml + '</div></div>';\n\t\t\t\thtml += '  <div class=\"dict-card-row\"><div class=\"dict-card-key\">键值</div><div class=\"dict-card-val\"><code>' + r.dictValue + '</code></div></div>';\n\t\t\t\thtml += '  <div class=\"dict-card-row\"><div class=\"dict-card-key\">状态</div><div class=\"dict-card-val\">' + statusBadge + '</div></div>';\n\t\t\t\thtml += '</div></div>';\n\t\t\t}\n\t\t\t$(\"#drawerBody\").html(html);\n\t\t}\n\n\t\t/* 关闭抽屉 */\n\t\tfunction closeDrawer() {\n\t\t\t$(\"#drawerPanel\").removeClass(\"open\");\n\t\t\t$(\"#drawerMask\").hide();\n\t\t\t$(\"body\").css(\"overflow\", \"\");\n\t\t}\n\n\t\t/* ESC 关闭 */\n\t\t$(document).on(\"keydown\", function(e) {\n\t\t\tif (e.key === \"Escape\") closeDrawer();\n\t\t});\n\t</script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/menu/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增菜单')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-menu-add\">\r\n\t\t\t<input id=\"treeId\" name=\"parentId\" type=\"hidden\" th:value=\"${menu.menuId}\" />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">上级菜单：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"input-group\">\r\n\t\t\t\t\t    <input class=\"form-control\" type=\"text\" onclick=\"selectMenuTree()\" id=\"treeName\" readonly=\"true\" th:value=\"${menu.menuName}\">\r\n\t\t\t\t        <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n\t\t\t\t    </div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">菜单类型：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"menuType\" value=\"M\" /> 目录 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"menuType\" value=\"C\" /> 菜单 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"menuType\" value=\"F\" /> 按钮 </label>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">菜单名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"menuName\" id=\"menuName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\" title=\"访问的请求地址，如：`/system/user`，如外网地址需内链访问则以`http(s)://`开头\">请求地址：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"url\" name=\"url\" class=\"form-control\" type=\"text\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">打开方式：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<select id=\"target\" name=\"target\" class=\"form-control m-b\">\r\n\t                    <option value=\"menuItem\">页签</option>\r\n\t                    <option value=\"menuBlank\">新窗口</option>\r\n\t                </select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">权限标识：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"perms\" name=\"perms\" class=\"form-control\" type=\"text\">\r\n\t\t\t\t\t<span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 控制器中定义的权限标识，如：@RequiresPermissions(\"\")</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\" title=\"数字越小越靠前\">显示排序：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"orderNum\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\" title=\"单击选择需要使用的FontAwesome图标\">图标：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"icon\" name=\"icon\" class=\"form-control\" type=\"text\" placeholder=\"选择图标\">\r\n                    <div class=\"ms-parent\" style=\"width: 100%;\">\r\n                        <div class=\"icon-drop animated flipInX\" style=\"display: none;max-height:200px;overflow-y:auto\">\r\n                            <div data-th-include=\"system/menu/icon\"></div>\r\n                        </div>\r\n                    </div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\" title=\"选择隐藏则菜单将不会出现在侧边栏，也没有权限被访问\">菜单状态：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-3\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_show_hide')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"visible\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t\t<label class=\"col-sm-2 control-label is-refresh\" title=\"打开菜单选项卡是否刷新页面\">是否刷新：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-3 is-refresh\">\r\n\t\t\t\t    <div class=\"radio-box\">\r\n\t\t\t\t\t\t<input type=\"radio\" id=\"refresh-no\" name=\"isRefresh\" value=\"1\" checked>\r\n\t\t\t\t\t\t<label for=\"refresh-no\">否</label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"radio-box\">\r\n\t\t\t\t\t\t<input type=\"radio\" id=\"refresh-yes\" name=\"isRefresh\" value=\"0\">\r\n\t\t\t\t\t\t<label for=\"refresh-yes\">是</label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t <script>\r\n        var prefix = ctx + \"system/menu\";\r\n        \r\n        $(\"#form-menu-add\").validate({\r\n        \tonkeyup: false,\r\n        \trules:{\r\n        \t\tmenuType:{\r\n        \t\t\trequired:true,\r\n        \t\t},\r\n        \t\tmenuName:{\r\n        \t\t\tremote: {\r\n                        url: prefix + \"/checkMenuNameUnique\",\r\n                        type: \"post\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                        \t\"parentId\": function() {\r\n\t\t                \t\treturn $(\"input[name='parentId']\").val();\r\n\t\t                    },\r\n                        \t\"menuName\" : function() {\r\n                                return $.common.trim($(\"#menuName\").val());\r\n                            }\r\n                        }\r\n                    }\r\n        \t\t},\r\n        \t\torderNum:{\r\n        \t\t\tdigits:true\r\n        \t\t},\r\n        \t},\r\n        \tmessages: {\r\n                \"menuName\": {\r\n                    remote: \"菜单已经存在\"\r\n                }\r\n            },\r\n            focusCleanup: true\r\n        });\r\n        \r\n        function submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t            $.operate.save(prefix + \"/add\", $('#form-menu-add').serialize());\r\n\t        }\r\n\t    }\r\n\r\n        $(function() {\r\n        \t$(\"input[name='icon']\").focus(function() {\r\n                $(\".icon-drop\").show();\r\n            });\r\n        \t$(\"#form-menu-add\").click(function(event) {\r\n        \t    var obj = event.srcElement || event.target;\r\n        \t    if (!$(obj).is(\"input[name='icon']\")) {\r\n        \t    \t$(\".icon-drop\").hide();\r\n        \t    }\r\n        \t});\r\n        \t$(\".icon-drop\").find(\".ico-list i\").on(\"click\", function() {\r\n        \t\t$('#icon').val($(this).attr('class'));\r\n            });\r\n        \t$('input').on('ifChecked', function(event){  \r\n        \t\tvar menuType = $(event.target).val();\r\n        \t\tif (menuType == \"M\") {\r\n                    $(\"#url\").parents(\".form-group\").hide();\r\n                    $(\"#perms\").parents(\".form-group\").hide();\r\n                    $(\"#icon\").parents(\".form-group\").show();\r\n                    $(\"#target\").parents(\".form-group\").hide();\r\n                    $(\".is-refresh\").hide();\r\n                } else if (menuType == \"C\") {\r\n                \t$(\"#url\").parents(\".form-group\").show();\r\n                    $(\"#perms\").parents(\".form-group\").show();\r\n                    $(\"#icon\").parents(\".form-group\").show();\r\n                    $(\"#target\").parents(\".form-group\").show();\r\n                    $(\".is-refresh\").show();\r\n                } else if (menuType == \"F\") {\r\n                \t$(\"#url\").parents(\".form-group\").hide();\r\n                    $(\"#perms\").parents(\".form-group\").show();\r\n                    $(\"#icon\").parents(\".form-group\").hide();\r\n                    $(\"#target\").parents(\".form-group\").hide();\r\n                    $(\".is-refresh\").hide();\r\n                }\r\n        \t});  \r\n        });\r\n\r\n        /*菜单管理-新增-选择菜单树*/\r\n        function selectMenuTree() {\r\n        \tvar treeId = $(\"#treeId\").val();\r\n        \tvar menuId = treeId > 0 ? treeId : 1;\r\n        \tvar url = prefix + \"/selectMenuTree/\" + menuId;\r\n\t\t\tvar options = {\r\n\t\t\t\ttitle: '菜单选择',\r\n\t\t\t\twidth: \"380\",\r\n\t\t\t\turl: url,\r\n\t\t\t\tcallBack: doSubmit\r\n\t\t\t};\r\n\t\t\t$.modal.openOptions(options);\r\n\t\t}\r\n\t\t\r\n\t\tfunction doSubmit(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#treeId\").val(body.find('#treeId').val());\r\n   \t\t\t$(\"#treeName\").val(body.find('#treeName').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/menu/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改菜单')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-menu-edit\" th:object=\"${menu}\">\r\n\t\t\t<input name=\"menuId\"   type=\"hidden\" th:field=\"*{menuId}\"   />\r\n\t\t\t<input id=\"treeId\" name=\"parentId\" type=\"hidden\" th:field=\"*{parentId}\" />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">上级菜单：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"input-group\">\r\n\t\t\t\t\t\t<input class=\"form-control\" type=\"text\" onclick=\"selectMenuTree()\" id=\"treeName\" readonly=\"true\" th:value=\"${menu.parentName == null ? '无' : menu.parentName}\">\r\n\t\t\t\t\t    <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n\t\t\t\t    </div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">菜单类型：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{menuType}\" name=\"menuType\" value=\"M\" /> 目录 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{menuType}\" name=\"menuType\" value=\"C\" /> 菜单 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{menuType}\" name=\"menuType\" value=\"F\" /> 按钮 </label>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">菜单名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"menuName\" id=\"menuName\" th:field=\"*{menuName}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\" title=\"访问的请求地址，如：`/system/user`，如外网地址需内链访问则以`http(s)://`开头\">请求地址：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"url\" name=\"url\" class=\"form-control\" type=\"text\" th:field=\"*{url}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">打开方式：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<select id=\"target\" name=\"target\" class=\"form-control m-b\">\r\n\t                    <option value=\"menuItem\" th:field=\"*{target}\">页签</option>\r\n\t                    <option value=\"menuBlank\" th:selected=\"*{target == 'menuBlank'}\">新窗口</option>\r\n\t                </select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">权限标识：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"perms\" name=\"perms\" class=\"form-control\" type=\"text\" th:field=\"*{perms}\">\r\n\t\t\t\t    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 控制器中定义的权限标识，如：@RequiresPermissions(\"\")</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\" title=\"数字越小越靠前\">显示排序：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"orderNum\" th:field=\"*{orderNum}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\" title=\"单击选择需要使用的FontAwesome图标\">图标：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"icon\" name=\"icon\" class=\"form-control\" type=\"text\" placeholder=\"选择图标\" th:field=\"*{icon}\">\r\n                    <div class=\"ms-parent\" style=\"width: 100%;\">\r\n                        <div class=\"icon-drop animated flipInX\" style=\"display: none;max-height:200px;overflow-y:auto\">\r\n                            <div data-th-include=\"system/menu/icon\"></div>\r\n                        </div>\r\n                    </div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\" title=\"选择隐藏则菜单将不会出现在侧边栏，也没有权限被访问\">菜单状态：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-3\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_show_hide')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"visible\" th:value=\"${dict.dictValue}\" th:field=\"*{visible}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t\t<label class=\"col-sm-2 control-label is-refresh\" title=\"打开菜单选项卡是否刷新页面\">是否刷新：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t<div class=\"col-sm-3 is-refresh\">\r\n\t\t\t\t    <div class=\"radio-box\">\r\n\t\t\t\t\t\t<input type=\"radio\" id=\"refresh-no\" name=\"isRefresh\" value=\"1\" th:field=\"*{isRefresh}\">\r\n\t\t\t\t\t\t<label for=\"refresh-no\">否</label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div class=\"radio-box\">\r\n\t\t\t\t\t\t<input type=\"radio\" id=\"refresh-yes\" name=\"isRefresh\" value=\"0\" th:field=\"*{isRefresh}\">\r\n\t\t\t\t\t\t<label for=\"refresh-yes\">是</label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t <script>\r\n        var prefix = ctx + \"system/menu\";\r\n\r\n        $(function() {\r\n            var menuType = $('input[name=\"menuType\"]:checked').val();\r\n            menuVisible(menuType);\r\n        });\r\n\r\n        $(\"#form-menu-edit\").validate({\r\n        \tonkeyup: false,\r\n        \trules:{\r\n        \t\tmenuType:{\r\n        \t\t\trequired:true,\r\n        \t\t},\r\n        \t\tmenuName:{\r\n        \t\t\tremote: {\r\n                        url: prefix + \"/checkMenuNameUnique\",\r\n                        type: \"post\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                        \t\"menuId\": function() {\r\n                                return $(\"#menuId\").val();\r\n                            },\r\n                            \"parentId\": function() {\r\n\t\t                \t\treturn $(\"input[name='parentId']\").val();\r\n\t\t                    },\r\n                \t\t\t\"menuName\": function() {\r\n                                return $.common.trim($(\"#menuName\").val());\r\n                            }\r\n                        }\r\n                    }\r\n        \t\t},\r\n        \t\torderNum:{\r\n        \t\t\tdigits:true\r\n        \t\t},\r\n        \t},\r\n        \tmessages: {\r\n                \"menuName\": {\r\n                    remote: \"菜单已经存在\"\r\n                }\r\n            },\r\n            focusCleanup: true\r\n        });\r\n        \r\n        function submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t            $.operate.save(prefix + \"/edit\", $('#form-menu-edit').serialize());\r\n\t        }\r\n\t    }\r\n\r\n        $(function() {\r\n            $(\"input[name='icon']\").focus(function() {\r\n                $(\".icon-drop\").show();\r\n            });\r\n            $(\"#form-menu-edit\").click(function(event) {\r\n                var obj = event.srcElement || event.target;\r\n                if (!$(obj).is(\"input[name='icon']\")) {\r\n                    $(\".icon-drop\").hide();\r\n                }\r\n            });\r\n            $(\".icon-drop\").find(\".ico-list i\").on(\"click\",\r\n            function() {\r\n                $('#icon').val($(this).attr('class'));\r\n            });\r\n            $('input').on('ifChecked',\r\n            function(event) {\r\n                var menuType = $(event.target).val();\r\n                menuVisible(menuType);\r\n            });\r\n        });\r\n\r\n        function menuVisible(menuType) {\r\n            if (menuType == \"M\") {\r\n                $(\"#url\").parents(\".form-group\").hide();\r\n                $(\"#perms\").parents(\".form-group\").hide();\r\n                $(\"#icon\").parents(\".form-group\").show();\r\n                $(\"#target\").parents(\".form-group\").hide();\r\n                $(\".is-refresh\").hide();\r\n            } else if (menuType == \"C\") {\r\n                $(\"#url\").parents(\".form-group\").show();\r\n                $(\"#perms\").parents(\".form-group\").show();\r\n                $(\"#icon\").parents(\".form-group\").show();\r\n                $(\"#target\").parents(\".form-group\").show();\r\n                $(\".is-refresh\").show();\r\n            } else if (menuType == \"F\") {\r\n                $(\"#url\").parents(\".form-group\").hide();\r\n                $(\"#perms\").parents(\".form-group\").show();\r\n                $(\"#icon\").parents(\".form-group\").hide();\r\n                $(\"#target\").parents(\".form-group\").hide();\r\n                $(\".is-refresh\").hide();\r\n            }\r\n        }\r\n\r\n        /*菜单管理-修改-选择菜单树*/\r\n        function selectMenuTree() {\r\n        \tvar menuId = $(\"#treeId\").val();\r\n        \tif(menuId > 0) {\r\n        \t\tvar url = prefix + \"/selectMenuTree/\" + menuId;\r\n        \t\t$.modal.open(\"选择菜单\", url, '380', '380');\r\n        \t} else {\r\n        \t\t$.modal.alertError(\"主菜单不能选择\");\r\n        \t}\r\n        }\r\n        \r\n        function selectMenuTree() {\r\n        \tvar menuId = $(\"#treeId\").val();\r\n        \tif(menuId > 0) {\r\n        \t\tvar url = prefix + \"/selectMenuTree/\" + menuId;\r\n        \t\tvar options = {\r\n       \t\t\t\ttitle: '菜单选择',\r\n       \t\t\t\twidth: \"380\",\r\n       \t\t\t\turl: url,\r\n       \t\t\t\tcallBack: doSubmit\r\n       \t\t\t};\r\n       \t\t\t$.modal.openOptions(options);\r\n        \t} else {\r\n        \t\t$.modal.alertError(\"主菜单不能选择\");\r\n        \t}\r\n\t\t}\r\n\t\t\r\n\t\tfunction doSubmit(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#treeId\").val(body.find('#treeId').val());\r\n   \t\t\t$(\"#treeName\").val(body.find('#treeName').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/menu/icon.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Font Awesome Ico list</title>\r\n    <link th:href=\"@{/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\r\n    <script th:src=\"@{/js/jquery.min.js}\"></script>\r\n    <style type=\"text/css\">\r\n        .ico-list .fa{\r\n            margin: 5px;\r\n            padding: 5px;\r\n            cursor:pointer;\r\n            font-size: 18px;\r\n            width: 28px;\r\n            border-radius: 3px;\r\n        }\r\n        .ico-list .fa:hover {\r\n            background-color: #1d9d74;\r\n            color: #ffffff;}\r\n    </style>\r\n</head>\r\n<body>\r\n<div class=\"ico-list\">\r\n     <i class=\"fa fa-address-book\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-address-book-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-address-card\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-address-card-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-adjust\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-american-sign-language-interpreting\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-anchor\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-archive\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-area-chart\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-arrows\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-arrows-h\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-arrows-v\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-asl-interpreting\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-assistive-listening-systems\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-asterisk\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-at\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-audio-description\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-automobile\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-balance-scale\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-ban\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bank\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bar-chart\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bar-chart-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-barcode\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bath\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bathtub\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-0\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-1\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-2\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-3\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-4\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-empty\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-full\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-half\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-quarter\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-battery-three-quarters\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bed\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-beer\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bell\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bell-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bell-slash\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bell-slash-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bicycle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-binoculars\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-birthday-cake\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-blind\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bluetooth\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bluetooth-b\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bolt\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bomb\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-book\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bookmark\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bookmark-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-braille\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-briefcase\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bug\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-building\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-building-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bullhorn\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bullseye\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-bus\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cab\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-calculator\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-calendar\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-calendar-check-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-calendar-minus-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-calendar-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-calendar-plus-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-calendar-times-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-camera\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-camera-retro\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-car\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-caret-square-o-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-caret-square-o-left\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-caret-square-o-right\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-caret-square-o-up\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cart-arrow-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cart-plus\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-certificate\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-check\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-check-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-check-circle-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-check-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-check-square-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-child\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-circle-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-circle-o-notch\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-circle-thin\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-clock-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-clone\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-close\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cloud\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cloud-download\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cloud-upload\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-code\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-code-fork\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-coffee\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cog\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cogs\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-comment\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-comment-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-commenting\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-commenting-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-comments\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-comments-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-compass\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-copyright\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-creative-commons\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-credit-card\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-credit-card-alt\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-crop\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-crosshairs\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cube\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cubes\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-cutlery\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-dashboard\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-database\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-deaf\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-deafness\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-desktop\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-diamond\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-dot-circle-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-download\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-drivers-license\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-drivers-license-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-edit\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-ellipsis-h\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-ellipsis-v\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-envelope\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-envelope-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-envelope-open\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-envelope-open-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-envelope-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-eraser\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-exchange\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-exclamation\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-exclamation-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-exclamation-triangle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-external-link\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-external-link-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-eye\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-eye-slash\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-eyedropper\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-fax\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-feed\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-female\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-fighter-jet\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-archive-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-audio-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-code-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-excel-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-image-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-movie-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-pdf-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-photo-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-picture-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-powerpoint-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-sound-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-video-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-word-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-file-zip-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-film\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-filter\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-fire\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-fire-extinguisher\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-flag\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-flag-checkered\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-flag-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-flash\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-flask\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-folder\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-folder-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-folder-open\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-folder-open-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-frown-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-futbol-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-gamepad\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-gavel\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-gear\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-gears\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-gift\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-glass\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-globe\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-graduation-cap\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-group\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-grab-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-lizard-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-paper-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-peace-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-pointer-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-rock-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-scissors-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-spock-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hand-stop-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-handshake-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hard-of-hearing\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hashtag\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hdd-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-headphones\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-heart\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-heart-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-heartbeat\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-history\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-home\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hotel\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass-1\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass-2\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass-3\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass-end\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass-half\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-hourglass-start\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-i-cursor\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-id-badge\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-id-card\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-id-card-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-image\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-inbox\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-industry\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-info\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-institution\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-key\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-keyboard-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-language\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-laptop\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-leaf\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-legal\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-lemon-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-level-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-level-up\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-life-bouy\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-life-buoy\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-life-ring\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-life-saver\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-lightbulb-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-line-chart\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-location-arrow\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-lock\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-low-vision\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-magic\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-magnet\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-mail-forward\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-mail-reply\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-mail-reply-all\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-male\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-map\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-map-marker\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-map-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-map-pin\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-map-signs\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-meh-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-microchip\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-microphone\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-microphone-slash\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-minus-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-minus-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-minus-square-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-mobile\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-mobile-phone\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-money\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-moon-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-mortar-board\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-motorcycle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-mouse-pointer\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-music\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-navicon\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-newspaper-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-object-group\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-object-ungroup\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-paint-brush\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-paper-plane\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-paw\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-pencil\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-pencil-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-pencil-square-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-percent\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-phone\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-phone-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-photo\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-picture-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-pie-chart\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-plane\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-plug\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-plus-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-plus-square-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-podcast\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-power-off\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-print\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-puzzle-piece\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-qrcode\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-question\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-question-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-question-circle-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-quote-left\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-quote-right\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-random\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-recycle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-refresh\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-registered\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-remove\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-reorder\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-reply\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-reply-all\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-retweet\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-road\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-rocket\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-rss\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-rss-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-s15\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-search\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-search-minus\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-search-plus\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-send\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-send-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-server\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-share\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-share-alt\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-share-alt-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-share-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-share-square-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-shield\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-ship\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-shopping-bag\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-shopping-basket\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-shopping-cart\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-shower\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sign-in\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sign-language\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sign-out\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-signal\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-signing\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sitemap\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sliders\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-smile-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-snowflake-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-soccer-ball-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-alpha-asc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-alpha-desc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-amount-asc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-amount-desc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-asc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-desc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-numeric-asc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-numeric-desc\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sort-up\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-space-shuttle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-spinner\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-spoon\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-square\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-square-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-star\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-star-half\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-star-half-empty\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-star-half-full\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-star-half-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-star-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sticky-note\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sticky-note-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-street-view\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-suitcase\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-sun-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-support\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tablet\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tachometer\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tag\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tags\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tasks\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-taxi\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-television\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-terminal\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-0\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-1\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-2\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-3\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-4\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-empty\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-full\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-half\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-quarter\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thermometer-three-quarters\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thumb-tack\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thumbs-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thumbs-o-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-thumbs-up\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-ticket\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-times\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-times-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-times-circle-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-times-rectangle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-times-rectangle-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tint\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-toggle-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-toggle-left\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-toggle-off\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-toggle-on\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-toggle-right\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-toggle-up\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-trademark\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-trash\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-trash-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tree\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-trophy\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-truck\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tty\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-tv\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-umbrella\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-universal-access\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-university\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-unlock\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-unlock-alt\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-unsorted\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-upload\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-user\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-user-circle\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-user-circle-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-user-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-user-plus\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-user-secret\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-user-times\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-vcard\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-vcard-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-video-camera\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-volume-control-phone\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-volume-down\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-volume-off\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-volume-up\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-warning\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-wheelchair\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-wheelchair-alt\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-wifi\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-window-close\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-window-close-o\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-window-maximize\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-window-minimize\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-window-restore\" aria-hidden=\"true\"></i>\r\n\r\n     <i class=\"fa fa-wrench\" aria-hidden=\"true\"></i>\r\n\r\n</div>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/menu/menu.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('菜单列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"menu-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t菜单名称：<input type=\"text\" name=\"menuName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t菜单状态：<select name=\"visible\" th:with=\"type=${@dict.getType('sys_show_hide')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.treeTable.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n                \r\n            <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t        <a class=\"btn btn-success\" onclick=\"$.operate.add(0)\" shiro:hasPermission=\"system:menu:add\">\r\n                    <i class=\"fa fa-plus\"></i> 新增\r\n                </a>\r\n                <a class=\"btn btn-primary\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"system:menu:edit\">\r\n\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-info\" onclick=\"saveSort()\">\r\n                    <i class=\"fa fa-sort-amount-asc\"></i> 保存排序\r\n                </a>\r\n                <a class=\"btn btn-default\" id=\"expandAllBtn\">\r\n                    <i class=\"fa fa-exchange\"></i> 展开/折叠\r\n                </a>\r\n\t        </div>\r\n       \t\t <div class=\"col-sm-12 select-table table-striped\">\r\n\t            <table id=\"bootstrap-tree-table\"></table>\r\n\t        </div>\r\n\t    </div>\r\n\t</div>\r\n\t\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar addFlag = [[${@permission.hasPermi('system:menu:add')}]];\r\n\t\tvar editFlag = [[${@permission.hasPermi('system:menu:edit')}]];\r\n\t\tvar removeFlag = [[${@permission.hasPermi('system:menu:remove')}]];\r\n\t\tvar datas = [[${@dict.getType('sys_show_hide')}]];\r\n\t\tvar prefix = ctx + \"system/menu\";\r\n\t\tvar originalOrders = {};\r\n\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        code: \"menuId\",\r\n\t\t        parentCode: \"parentId\",\r\n\t\t        uniqueId: \"menuId\",\r\n\t\t        expandAll: false,\r\n\t\t        expandFirst: false,\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        createUrl: prefix + \"/add/{id}\",\r\n\t\t        updateUrl: prefix + \"/edit/{id}\",\r\n\t\t        removeUrl: prefix + \"/remove/{id}\",\r\n\t\t        modalName: \"菜单\",\r\n\t\t        columns: [{\r\n                    field: 'selectItem', \r\n                    radio: true\r\n                 },\r\n                 {\r\n\t\t            title: '菜单名称',\r\n\t\t            field: 'menuName',\r\n\t\t            width: '20',\r\n\t\t            widthUnit: '%',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                if ($.common.isEmpty(row.icon)) {\r\n\t\t                    return row.menuName;\r\n\t\t                } else {\r\n\t\t                    return '<i class=\"' + row.icon + '\"></i> <span class=\"nav-label\">' + row.menuName + '</span>';\r\n\t\t                }\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'orderNum',\r\n\t\t            title: '排序',\r\n\t\t            width: '10',\r\n\t\t            widthUnit: '%',\r\n\t\t            align: \"center\",\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar menuIdText = $.common.sprintf(\"<input type='hidden' name='menuIds' value='%s'>\", row.menuId);\r\n                    \tvar orderNumText = $.common.sprintf(\"<input type='text' name='orderNums' value='%s' class='form-control' style='display: inline-block; width:60px; text-align:center;'>\", row.orderNum);\r\n                    \toriginalOrders[row.menuId] = row.orderNum;\r\n                    \treturn menuIdText + orderNumText;\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'url',\r\n\t\t            title: '请求地址',\r\n\t\t            width: '15',\r\n\t\t            widthUnit: '%',\r\n\t\t            align: \"center\",\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '类型',\r\n\t\t            field: 'menuType',\r\n\t\t            width: '10',\r\n\t\t            widthUnit: '%',\r\n\t\t            align: \"center\",\r\n\t\t            formatter: function(value, item, index) {\r\n\t\t                if (item.menuType == 'M') {\r\n\t\t                    return '<span class=\"label label-success\">目录</span>';\r\n\t\t                }\r\n\t\t                else if (item.menuType == 'C') {\r\n\t\t                    return '<span class=\"label label-primary\">菜单</span>';\r\n\t\t                }\r\n\t\t                else if (item.menuType == 'F') {\r\n\t\t                    return '<span class=\"label label-warning\">按钮</span>';\r\n\t\t                }\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'visible',\r\n\t\t            title: '可见',\r\n\t\t            width: '10',\r\n\t\t            widthUnit: '%',\r\n\t\t            align: \"center\",\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tif (row.menuType == 'F') {\r\n\t\t                    return '-';\r\n\t\t                }\r\n\t\t            \treturn $.table.selectDictLabel(datas, row.visible);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'perms',\r\n\t\t            title: '权限标识',\r\n\t\t            width: '15',\r\n\t\t            widthUnit: '%',\r\n\t\t            align: \"center\",\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            width: '20',\r\n\t\t            widthUnit: '%',\r\n\t\t            align: \"center\",\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                var actions = [];\r\n\t\t                actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.menuId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n\t\t                actions.push('<a class=\"btn btn-info btn-xs ' + addFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.add(\\'' + row.menuId + '\\')\"><i class=\"fa fa-plus\"></i>新增</a> ');\r\n\t\t                actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.menuId + '\\')\"><i class=\"fa fa-trash\"></i>删除</a>');\r\n\t\t                return actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.treeTable.init(options);\r\n\t\t});\r\n\r\n\t\t/* 保存排序-菜单 */\r\n\t\tfunction saveSort() {\r\n\t\t\tvar changedMenuIds = [];\r\n\t\t\tvar changedOrderNums = [];\r\n\t\t    $(\"input[name='menuIds']\").each(function() {\r\n\t\t        var menuId = $(this).val();\r\n\t\t        var currentOrder = $(this).next(\"input[name='orderNums']\").val();\r\n\t\t        if (originalOrders[menuId] !== currentOrder) {\r\n\t\t            changedMenuIds.push(menuId);\r\n\t\t            changedOrderNums.push(currentOrder);\r\n\t\t        }\r\n\t\t    });\r\n\t\t    if (changedMenuIds.length === 0) {\r\n\t\t        $.modal.alertWarning(\"未检测到排序修改\");\r\n\t\t        return;\r\n\t\t    }\r\n\t\t    $.operate.post(prefix + \"/updateSort\", { \"menuIds\": changedMenuIds.join(\",\"), \"orderNums\": changedOrderNums.join(\",\") });\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/menu/tree.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('菜单树选择')\" />\r\n\t<th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<style>\r\n\tbody{height:auto;font-family: \"Microsoft YaHei\";}\r\n\tbutton{font-family: \"SimSun\",\"Helvetica Neue\",Helvetica,Arial;}\r\n</style>\r\n<body class=\"hold-transition box box-main\">\r\n\t<input id=\"treeId\"   name=\"treeId\"    type=\"hidden\" th:value=\"${menu.menuId}\"/>\r\n\t<input id=\"treeName\" name=\"treeName\"  type=\"hidden\" th:value=\"${menu.menuName}\"/>\r\n\t<div class=\"wrapper\"><div class=\"treeShowHideButton\" onclick=\"$.tree.toggleSearch();\">\r\n\t\t<label id=\"btnShow\" title=\"显示搜索\" style=\"display:none;\">︾</label>\r\n\t\t<label id=\"btnHide\" title=\"隐藏搜索\">︽</label>\r\n\t</div>\r\n\t<div class=\"treeSearchInput\" id=\"search\">\r\n\t\t<label for=\"keyword\">关键字：</label><input type=\"text\" class=\"empty\" id=\"keyword\" maxlength=\"50\">\r\n\t\t<button class=\"btn\" id=\"btn\" onclick=\"$.tree.searchNode()\"> 搜索 </button>\r\n\t</div>\r\n\t<div class=\"treeExpandCollapse\">\r\n\t\t<a href=\"javascript:;\" onclick=\"$.tree.expand()\">展开</a> /\r\n\t\t<a href=\"javascript:;\" onclick=\"$.tree.collapse()\">折叠</a>\r\n\t</div>\r\n\t<div id=\"tree\" class=\"ztree treeselect\"></div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: ztree-js\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\t$(function() {\r\n\t\t\tvar url = ctx + \"system/menu/menuTreeData\";\r\n\t\t\tvar options = {\r\n\t\t        url: url,\r\n\t\t        expandLevel: 1,\r\n\t\t        onClick : zOnClick\r\n\t\t    };\r\n\t\t\t$.tree.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction zOnClick(event, treeId, treeNode) {\r\n\t\t    var treeId = treeNode.id;\r\n\t\t    var treeName = treeNode.name;\r\n\t\t    $(\"#treeId\").val(treeId);\r\n\t\t    $(\"#treeName\").val(treeName);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/notice/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增通知公告')\" />\r\n\t<th:block th:include=\"include :: summernote-css\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n        <form class=\"form-horizontal m\" id=\"form-notice-add\">\r\n\t\t\t<div class=\"form-group\">\t\r\n\t\t\t\t<label class=\"col-sm-2 control-label is-required\">公告标题：</label>\r\n\t\t\t\t<div class=\"col-sm-10\">\r\n\t\t\t\t\t<input id=\"noticeTitle\" name=\"noticeTitle\" class=\"form-control\" type=\"text\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-2 control-label\">公告类型：</label>\r\n\t\t\t\t<div class=\"col-sm-10\">\r\n\t\t\t\t\t<select name=\"noticeType\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_notice_type')}\">\r\n\t                    <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t                </select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\t\r\n\t\t\t\t<label class=\"col-sm-2 control-label\">公告内容：</label>\r\n\t\t\t\t<div class=\"col-sm-10\">\r\n\t\t\t\t    <input id=\"noticeContent\" name=\"noticeContent\" type=\"hidden\">\r\n\t\t\t\t    <div class=\"summernote\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-2 control-label\">公告状态：</label>\r\n\t\t\t\t<div class=\"col-sm-10\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_notice_status')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: summernote-js\" />\r\n    <script type=\"text/javascript\">\r\n        var prefix = ctx + \"system/notice\";\r\n\r\n\t    $('.summernote').summernote({\r\n\t    \tplaceholder: '请输入公告内容',\r\n\t\t\theight : 192,\r\n\t\t\tlang : 'zh-CN',\r\n\t\t\tfollowingToolbar: false,\r\n\t\t\tdialogsInBody: true,\r\n\t\t\tcallbacks: {\r\n                onImageUpload: function (files) {\r\n                    sendFile(files[0], this);\r\n                }\r\n            }\r\n\t\t});\r\n\t    \r\n\t    // 上传文件\r\n\t    function sendFile(file, obj) {\r\n\t        var data = new FormData();\r\n\t        data.append(\"file\", file);\r\n\t        $.ajax({\r\n\t            type: \"POST\",\r\n\t            url: ctx + \"common/upload\",\r\n\t            data: data,\r\n\t            cache: false,\r\n\t            contentType: false,\r\n\t            processData: false,\r\n\t            dataType: 'json',\r\n\t            success: function(result) {\r\n\t                if (result.code == web_status.SUCCESS) {\r\n\t                \t$(obj).summernote('editor.insertImage', result.url, result.fileName);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t$.modal.alertError(result.msg);\r\n\t\t\t\t\t}\r\n\t            },\r\n\t            error: function(error) {\r\n\t                $.modal.alertWarning(\"图片上传失败。\");\r\n\t            }\r\n\t        });\r\n\t    }\r\n\t\t\r\n\t\t$(\"#form-notice-add\").validate({\r\n\t\t\tfocusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \tvar sHTML = $('.summernote').summernote('code');\r\n\t\t\t\t$(\"#noticeContent\").val(sHTML);\r\n\t\t\t\t$.operate.save(prefix + \"/add\", $('#form-notice-add').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/notice/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改通知公告')\" />\r\n\t<th:block th:include=\"include :: summernote-css\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n        <form class=\"form-horizontal m\" id=\"form-notice-edit\" th:object=\"${notice}\">\r\n            <input id=\"noticeId\" name=\"noticeId\" th:field=\"*{noticeId}\"  type=\"hidden\">\r\n            <div class=\"form-group\">\t\r\n                <label class=\"col-sm-2 control-label is-required\">公告标题：</label>\r\n                <div class=\"col-sm-10\">\r\n                    <input id=\"noticeTitle\" name=\"noticeTitle\" th:field=\"*{noticeTitle}\" class=\"form-control\" type=\"text\" required>\r\n                </div>\r\n            </div>\r\n            <div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-2 control-label\">公告类型：</label>\r\n\t\t\t\t<div class=\"col-sm-10\">\r\n\t\t\t\t\t<select name=\"noticeType\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_notice_type')}\">\r\n\t                    <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\" th:field=\"*{noticeType}\"></option>\r\n\t                </select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n            <div class=\"form-group\">\t\r\n                <label class=\"col-sm-2 control-label\">公告内容：</label>\r\n                <div class=\"col-sm-10\">\r\n                    <input id=\"noticeContent\" name=\"noticeContent\" th:field=\"*{noticeContent}\" type=\"hidden\">\r\n                    <div id=\"editor\" class=\"summernote\"></div>\r\n                </div>\r\n            </div>\r\n            <div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-2 control-label\">公告状态：</label>\r\n\t\t\t\t<div class=\"col-sm-10\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_notice_status')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:field=\"*{status}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: summernote-js\" />\r\n    <script type=\"text/javascript\">\r\n        var prefix = ctx + \"system/notice\";\r\n    \r\n\t    $(function() {\r\n\t\t    $('.summernote').summernote({\r\n\t\t    \tplaceholder: '请输入公告内容',\r\n\t\t    \theight : 192,\r\n\t\t\t\tlang : 'zh-CN',\r\n\t\t\t\tfollowingToolbar: false,\r\n\t\t\t\tdialogsInBody: true,\r\n\t\t\t\tcallbacks: {\r\n\t                onImageUpload: function (files) {\r\n\t                    sendFile(files[0], this);\r\n\t                }\r\n\t            }\r\n\t\t    });\r\n\t\t\tvar content = $(\"#noticeContent\").val();\r\n\t\t    $('#editor').summernote('code', content);\r\n\t    });\r\n\t    \r\n\t    // 上传文件\r\n\t    function sendFile(file, obj) {\r\n\t        var data = new FormData();\r\n\t        data.append(\"file\", file);\r\n\t        $.ajax({\r\n\t            type: \"POST\",\r\n\t            url: ctx + \"common/upload\",\r\n\t            data: data,\r\n\t            cache: false,\r\n\t            contentType: false,\r\n\t            processData: false,\r\n\t            dataType: 'json',\r\n\t            success: function(result) {\r\n\t                if (result.code == web_status.SUCCESS) {\r\n\t                \t$(obj).summernote('editor.insertImage', result.url, result.fileName);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t$.modal.alertError(result.msg);\r\n\t\t\t\t\t}\r\n\t            },\r\n\t            error: function(error) {\r\n\t                $.modal.alertWarning(\"图片上传失败。\");\r\n\t            }\r\n\t        });\r\n\t    }\r\n\t    \r\n\t\t$(\"#form-notice-edit\").validate({\r\n\t\t\tfocusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \tvar sHTML = $('.summernote').summernote('code');\r\n\t\t\t\t$(\"#noticeContent\").val(sHTML);\r\n\t\t\t\t$.operate.save(prefix + \"/edit\", $('#form-notice-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/notice/notice.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('通知公告列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"notice-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t公告标题：<input type=\"text\" name=\"noticeTitle\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t操作人员：<input type=\"text\" name=\"createBy\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t公告类型：<select name=\"noticeType\" th:with=\"type=${@dict.getType('sys_notice_type')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t        <a class=\"btn btn-success\" onclick=\"$.operate.addFull()\" shiro:hasPermission=\"system:notice:add\">\r\n\t\t            <i class=\"fa fa-plus\"></i> 新增\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.editFull()\" shiro:hasPermission=\"system:notice:edit\">\r\n\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"system:notice:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t            <table id=\"bootstrap-table\"></table>\r\n\t        </div>\r\n    \t</div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script th:inline=\"javascript\">\r\n        var editFlag = [[${@permission.hasPermi('system:notice:edit')}]];\r\n        var removeFlag = [[${@permission.hasPermi('system:notice:remove')}]];\r\n        var types = [[${@dict.getType('sys_notice_type')}]];\r\n        var datas = [[${@dict.getType('sys_notice_status')}]];\r\n        var prefix = ctx + \"system/notice\";\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n                viewUrl: prefix + \"/view/{id}\",\r\n                createUrl: prefix + \"/add\",\r\n                updateUrl: prefix + \"/edit/{id}\",\r\n                removeUrl: prefix + \"/remove\",\r\n                modalName: \"公告\",\r\n                columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'noticeId', \r\n\t\t\t\t\ttitle : '序号' \r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t            field: 'noticeTitle',\r\n\t\t            title: '公告标题',\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t                return '<a href=\"javascript:void(0)\" onclick=\"$.operate.view(\\'' + row.noticeId + '\\')\">' + value + '</a>';\r\n\t\t            }\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t            field: 'noticeType',\r\n\t\t            title: '公告类型',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \treturn $.table.selectDictLabel(types, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t            field: 'status',\r\n\t\t            title: '状态',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \treturn $.table.selectDictLabel(datas, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t\t\t{\r\n\t\t\t\t\tfield : 'createBy', \r\n\t\t\t\t\ttitle : '创建者' \r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \tvar actions = [];\r\n\t\t            \tactions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.editFull(\\'' + row.noticeId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.noticeId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t\t\t\t\treturn actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/notice/view.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <th:block th:include=\"include :: header('公告详情')\" />\n    <style>body.white-bg{background:#f5f6f8;font-family:'PingFang SC','Microsoft YaHei','Helvetica Neue',sans-serif}.notice-page{max-width:760px;margin:0 auto;padding:32px 24px 60px;animation:fadeUp .35s ease both}@keyframes fadeUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}.notice-type-tag{display:inline-flex;align-items:center;gap:5px;padding:3px 12px;border-radius:2px;font-size:11px;font-weight:700;letter-spacing:1px;text-transform:uppercase;margin-bottom:14px}.type-notify{background:#fff8e6;color:#b7791f;border-left:3px solid #d97706}.type-announce{background:#e8f5e9;color:#276749;border-left:3px solid #38a169}.notice-title{font-size:22px;font-weight:700;color:#1a202c;line-height:1.45;margin:0 0 16px;letter-spacing:-0.2px}.notice-meta{display:flex;align-items:center;flex-wrap:wrap;gap:16px;padding:12px 0;border-top:1px solid #e9ecef;border-bottom:1px solid #e9ecef;margin-bottom:28px}.meta-item{display:flex;align-items:center;gap:5px;font-size:12px;color:#718096}.meta-item i{font-size:12px;color:#a0aec0}.status-dot{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:4px}.status-ok{background:#38a169}.status-off{background:#e53e3e}.notice-divider{display:flex;align-items:center;gap:12px;margin-bottom:24px}.notice-divider::before,.notice-divider::after{content:'';flex:1;height:1px;background:linear-gradient(to right,transparent,#dee2e6,transparent)}.notice-divider-dot{width:6px;height:6px;border-radius:50%;background:#cbd5e0}.notice-body{background:#fff;border-radius:6px;padding:28px 32px;box-shadow:0 1px 4px rgba(0,0,0,0.06),0 0 0 1px rgba(0,0,0,0.04);min-height:160px}.notice-content{font-size:14px;line-height:1.85;color:#2d3748;word-break:break-word}.notice-content p{margin:0 0 1em}.notice-content h1,.notice-content h2,.notice-content h3{font-weight:700;color:#1a202c;margin:1.4em 0 .6em}.notice-content h1{font-size:18px}.notice-content h2{font-size:16px}.notice-content h3{font-size:14px}.notice-content a{color:#3182ce;text-decoration:underline}.notice-content a:hover{color:#2b6cb0}.notice-content img{max-width:100%;border-radius:4px;margin:8px 0}.notice-content ul,.notice-content ol{padding-left:20px;margin:0 0 1em}.notice-content li{margin-bottom:4px}.notice-content blockquote{border-left:3px solid #cbd5e0;margin:1em 0;padding:6px 16px;color:#718096;background:#f7fafc}.notice-content table{border-collapse:collapse;width:100%;margin:1em 0;font-size:13px}.notice-content table th,.notice-content table td{border:1px solid #e2e8f0;padding:7px 12px}.notice-content table th{background:#f7fafc;font-weight:600}.notice-empty{text-align:center;padding:40px 0;color:#a0aec0;font-size:13px}.notice-empty i{font-size:28px;display:block;margin-bottom:10px}</style>\n</head>\n<body class=\"white-bg\">\n<div class=\"notice-page\">\n\n    <div th:switch=\"${notice.noticeType}\">\n        <span th:case=\"'1'\" class=\"notice-type-tag type-notify\">\n            <i class=\"fa fa-bell-o\"></i> 通知\n        </span>\n        <span th:case=\"'2'\" class=\"notice-type-tag type-announce\">\n            <i class=\"fa fa-bullhorn\"></i> 公告\n        </span>\n        <span th:case=\"*\" class=\"notice-type-tag type-notify\">\n            <i class=\"fa fa-file-text-o\"></i> 消息\n        </span>\n    </div>\n\n    <h1 class=\"notice-title\" th:text=\"${notice.noticeTitle}\">公告标题</h1>\n\n    <div class=\"notice-meta\">\n        <span class=\"meta-item\">\n            <i class=\"fa fa-user-o\"></i>\n            <span th:text=\"${notice.createBy}\">发布人</span>\n        </span>\n        <span class=\"meta-item\">\n            <i class=\"fa fa-clock-o\"></i>\n            <span th:text=\"${#dates.format(notice.createTime, 'yyyy-MM-dd HH:mm:ss')}\">发布时间</span>\n        </span>\n        <span class=\"meta-item\">\n            <span th:class=\"${notice.status == '0'} ? 'status-dot status-ok' : 'status-dot status-off'\"></span>\n            <span th:text=\"${notice.status == '0'} ? '正常' : '已关闭'\">状态</span>\n        </span>\n    </div>\n\n    <div class=\"notice-divider\">\n        <span class=\"notice-divider-dot\"></span>\n        <span class=\"notice-divider-dot\"></span>\n        <span class=\"notice-divider-dot\"></span>\n    </div>\n\n    <div class=\"notice-body\">\n        <div class=\"notice-content\"\n             th:if=\"${not #strings.isEmpty(notice.noticeContent)}\"\n             th:utext=\"${notice.noticeContent}\">\n        </div>\n        <div class=\"notice-empty\" th:if=\"${#strings.isEmpty(notice.noticeContent)}\">\n            <i class=\"fa fa-file-o\"></i>暂无内容\n        </div>\n    </div>\n\n</div>\n<th:block th:include=\"include :: footer\" />\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/post/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增岗位')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-post-add\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">岗位名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"postName\" id=\"postName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">岗位编码：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"postCode\" id=\"postCode\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">显示顺序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"postSort\" id=\"postSort\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">岗位状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\"></textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/post\";\r\n\t    \r\n\t\t$(\"#form-post-add\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tpostName:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/post/checkPostNameUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"postName\" : function() {\r\n\t\t                        return $.common.trim($(\"#postName\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\tpostCode:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/post/checkPostCodeUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"postCode\" : function() {\r\n\t\t                        return $.common.trim($(\"#postCode\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\tpostSort:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"postCode\": {\r\n\t\t            remote: \"岗位编码已经存在\"\r\n\t\t        },\r\n\t\t        \"postName\": {\r\n\t\t            remote: \"岗位名称已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/add\", $('#form-post-add').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/post/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改岗位')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-post-edit\" th:object=\"${post}\">\r\n\t\t\t<input id=\"postId\" name=\"postId\" type=\"hidden\" th:field=\"*{postId}\"/>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">岗位名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"postName\" id=\"postName\" th:field=\"*{postName}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">岗位编码：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"postCode\" id=\"postCode\" th:field=\"*{postCode}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">显示顺序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"postSort\" id=\"postSort\" th:field=\"*{postSort}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">岗位状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:field=\"*{status}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\">[[*{remark}]]</textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"system/post\";\r\n\t\t\r\n\t\t$(\"#form-post-edit\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tpostName:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/post/checkPostNameUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"postId\": function() {\r\n\t\t\t\t\t\t\t    return $(\"input[name='postId']\").val();\r\n\t\t\t\t\t\t\t},\r\n\t\t                \t\"postName\" : function() {\r\n\t\t                        return $.common.trim($(\"#postName\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\tpostCode:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/post/checkPostCodeUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"postId\": function() {\r\n\t\t\t\t\t\t\t    return $(\"input[name='postId']\").val();\r\n\t\t\t\t\t\t\t},\r\n\t\t                \t\"postCode\" : function() {\r\n\t\t                \t\treturn $.common.trim($(\"#postCode\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\tpostSort:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"postCode\": {\r\n\t\t            remote: \"岗位编码已经存在\"\r\n\t\t        },\r\n\t\t        \"postName\": {\r\n\t\t            remote: \"岗位名称已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-post-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/post/post.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('岗位列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"post-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t岗位编码：<input type=\"text\" name=\"postCode\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t岗位名称：<input type=\"text\" name=\"postName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t岗位状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t\t\t<a class=\"btn btn-success\" onclick=\"$.operate.add()\" shiro:hasPermission=\"system:post:add\">\r\n\t                <i class=\"fa fa-plus\"></i> 新增\r\n\t            </a>\r\n\t\t\t\t<a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"system:post:edit\">\r\n\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t        </a>\r\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"system:post:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t\t\t\t<a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"system:post:export\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar editFlag = [[${@permission.hasPermi('system:post:edit')}]];\r\n\t\tvar removeFlag = [[${@permission.hasPermi('system:post:remove')}]];\r\n\t\tvar datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\t\tvar prefix = ctx + \"system/post\";\r\n\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        createUrl: prefix + \"/add\",\r\n\t\t        updateUrl: prefix + \"/edit/{id}\",\r\n\t\t        removeUrl: prefix + \"/remove\",\r\n\t\t        exportUrl: prefix + \"/export\",\r\n\t\t        sortName: \"postSort\",\r\n\t\t        modalName: \"岗位\",\r\n\t\t        columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'postId',\r\n\t\t            title: '岗位编号'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'postCode',\r\n\t\t            title: '岗位编码',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'postName',\r\n\t\t            title: '岗位名称',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'postSort',\r\n\t\t            title: '显示顺序',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'status',\r\n\t\t            title: '状态',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \treturn $.table.selectDictLabel(datas, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                var actions = [];\r\n\t\t                actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.postId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n\t\t                actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.postId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n\t\t                return actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/role/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增角色')\" />\r\n\t<th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-role-add\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">角色名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleName\" id=\"roleName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">权限字符：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleKey\" id=\"roleKey\" required>\r\n\t\t\t\t\t<span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 控制器中定义的权限字符，如：@RequiresRoles(\"\")</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">显示顺序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleSort\" id=\"roleSort\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t        <label class=\"toggle-switch switch-solid\">\r\n                        <input type=\"checkbox\" id=\"status\" checked>\r\n                        <span></span>\r\n                    </label>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"remark\" name=\"remark\" class=\"form-control\" type=\"text\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">菜单权限：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"1\">展开/折叠</label>\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"2\">全选/全不选</label>\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"3\" checked>父子联动</label>\r\n\t\t\t\t    <div id=\"menuTrees\" class=\"ztree ztree-border\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: ztree-js\" />\r\n\t<script type=\"text/javascript\">\r\n\t    $(function() {\r\n\t\t\tvar url = ctx + \"system/menu/roleMenuTreeData\";\r\n\t\t\tvar options = {\r\n\t\t\t\tid: \"menuTrees\",\r\n\t\t        url: url,\r\n\t\t        check: { enable: true },\r\n\t\t        expandLevel: 0\r\n\t\t    };\r\n\t\t\t$.tree.init(options);\r\n\t\t});\r\n\t\t\r\n\t\t$(\"#form-role-add\").validate({\r\n\t\t\trules:{\r\n\t\t\t\tonkeyup: false,\r\n\t\t\t\troleName:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/role/checkRoleNameUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"roleName\" : function() {\r\n\t\t                \t\treturn $.common.trim($(\"#roleName\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\troleKey:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/role/checkRoleKeyUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"roleKey\" : function() {\r\n\t\t                        return $.common.trim($(\"#roleKey\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\troleSort:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"roleName\": {\r\n\t\t            remote: \"角色名称已经存在\"\r\n\t\t        },\r\n\t\t        \"roleKey\": {\r\n\t\t            remote: \"角色权限已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\t$('input').on('ifChanged', function(obj){\r\n\t\t\tvar type = $(this).val();\r\n\t\t\tvar checked = obj.currentTarget.checked;\r\n\t\t\tif (type == 1) {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.expandAll(true);\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.expandAll(false);\r\n\t\t\t    }\r\n\t\t\t} else if (type == \"2\") {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.checkAllNodes(true);\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.checkAllNodes(false);\r\n\t\t\t    }\r\n\t\t\t} else if (type == \"3\") {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.setting.check.chkboxType = { \"Y\": \"ps\", \"N\": \"ps\" };\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.setting.check.chkboxType = { \"Y\": \"\", \"N\": \"\" };\r\n\t\t\t    }\r\n\t\t\t}\r\n\t\t})\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \tadd();\r\n\t        }\r\n\t    }\r\n\t\r\n\t\tfunction add() {\r\n\t\t\tvar roleName = $(\"input[name='roleName']\").val();\r\n\t\t\tvar roleKey = $(\"input[name='roleKey']\").val();\r\n\t\t\tvar roleSort = $(\"input[name='roleSort']\").val();\r\n\t\t\tvar status = $(\"input[id='status']\").is(':checked') == true ? 0 : 1;\r\n\t\t\tvar remark = $(\"input[name='remark']\").val();\r\n\t\t\tvar menuIds = $.tree.getCheckedNodes();\r\n\t\t\t$.ajax({\r\n\t\t\t\tcache : true,\r\n\t\t\t\ttype : \"POST\",\r\n\t\t\t\turl : ctx + \"system/role/add\",\r\n\t\t\t\tdata : {\r\n\t\t\t\t\t\"roleName\": roleName,\r\n\t\t\t\t\t\"roleKey\": roleKey,\r\n\t\t\t\t\t\"roleSort\": roleSort,\r\n\t\t\t\t\t\"status\": status,\r\n\t\t\t\t\t\"remark\": remark,\r\n\t\t\t\t\t\"menuIds\": menuIds\r\n\t\t\t\t},\r\n\t\t\t\tasync : false,\r\n\t\t\t\terror : function(request) {\r\n\t\t\t\t\t$.modal.alertError(\"系统错误\");\r\n\t\t\t\t},\r\n\t\t\t\tsuccess : function(data) {\r\n\t\t\t\t\t$.operate.successCallback(data);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/role/authUser.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('角色分配用户')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"role-form\">\r\n\t\t\t\t    <input type=\"hidden\" id=\"roleId\" name=\"roleId\" th:value=\"${role.roleId}\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t登录名称：<input type=\"text\" name=\"loginName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t手机号码：<input type=\"text\" name=\"phonenumber\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t        \r\n\t        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t\t\t<a class=\"btn btn-success\" onclick=\"selectUser()\" shiro:hasPermission=\"system:role:add\">\r\n\t                <i class=\"fa fa-plus\"></i> 添加用户\r\n\t            </a>\r\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"cancelAuthUserAll()\" shiro:hasPermission=\"system:role:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 批量取消授权\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-warning\" onclick=\"closeItem()\">\r\n\t\t            <i class=\"fa fa-reply-all\"></i> 关闭\r\n\t\t        </a>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar removeFlag = [[${@permission.hasPermi('system:role:remove')}]];\r\n\t\tvar datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\t\tvar prefix = ctx + \"system/role/authUser\";\r\n\r\n\t\t$(function() {\r\n\t\t\tvar options = {\r\n\t\t        url: prefix + \"/allocatedList\",\r\n\t\t        queryParams: queryParams,\r\n\t\t        sortName: \"createTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'userId',\r\n\t\t            title: '用户ID',\r\n\t\t            visible: false\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginName',\r\n\t\t            title: '登录名称',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'userName',\r\n\t\t            title: '用户名称'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'email',\r\n\t\t            title: '邮箱'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'phonenumber',\r\n\t\t            title: '手机'\r\n\t\t        },\r\n\t\t        {\r\n\t\t        \tfield: 'status',\r\n\t\t        \ttitle: '用户状态',\r\n\t\t        \talign: 'center',\r\n\t\t        \tformatter: function (value, row, index) {\r\n\t\t        \t\treturn $.table.selectDictLabel(datas, value);\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                var actions = [];\r\n\t\t                actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"cancelAuthUser(\\'' + row.userId + '\\')\"><i class=\"fa fa-remove\"></i>取消授权</a> ');\r\n\t\t                return actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction queryParams(params) {\r\n\t\t\tvar search = $.table.queryParams(params);\r\n\t\t\tsearch.roleId = $(\"#roleId\").val();\r\n\t\t\treturn search;\r\n\t\t}\r\n\t\t\r\n\t\t/* 分配用户-选择用户 */\r\n\t\tfunction selectUser() {\r\n\t\t\tvar url = prefix + '/selectUser/' + $(\"#roleId\").val();\r\n\t\t    $.modal.open(\"选择用户\", url);\r\n\t\t}\r\n\t\t\r\n\t\t/* 分配用户-批量取消授权 */\r\n\t\tfunction cancelAuthUserAll(userId) {\r\n\t\t    var rows = $.table.selectFirstColumns();\r\n       \t\tif (rows.length == 0) {\r\n       \t\t\t$.modal.alertWarning(\"请至少选择一条记录\");\r\n       \t\t\treturn;\r\n       \t\t}\r\n       \t\t$.modal.confirm(\"确认要删除选中的\" + rows.length + \"条数据吗?\", function() {\r\n    \t\t\tvar data = { \"roleId\": $(\"#roleId\").val(), \"userIds\": rows.join() };\r\n    \t\t\t$.operate.submit(prefix + \"/cancelAll\", \"post\", \"json\", data);\r\n    \t\t});\r\n\t\t}\r\n\t\t\r\n\t\t/* 分配用户-取消授权 */\r\n\t\tfunction cancelAuthUser(userId) {\r\n\t\t\t$.modal.confirm(\"确认要取消该用户角色吗？\", function() {\r\n\t\t\t\t$.operate.post(prefix + \"/cancel\", { \"roleId\": $(\"#roleId\").val(), \"userId\": userId });\r\n\t\t    })\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/role/dataScope.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('角色数据权限')\" />\r\n\t<th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-role-edit\" th:object=\"${role}\">\r\n\t\t\t<input id=\"roleId\" name=\"roleId\" type=\"hidden\" th:field=\"*{roleId}\"/>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">角色名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleName\" id=\"roleName\" th:field=\"*{roleName}\" readonly=\"true\"/>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">权限字符：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleKey\" id=\"roleKey\" th:field=\"*{roleKey}\" readonly=\"true\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">数据范围：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<select id=\"dataScope\" name=\"dataScope\" class=\"form-control m-b\">\r\n\t\t\t\t\t\t<option value=\"1\" th:field=\"*{dataScope}\">全部数据权限</option>\r\n\t\t\t\t\t\t<option value=\"2\" th:field=\"*{dataScope}\">自定义数据权限</option>\r\n\t\t\t\t\t\t<option value=\"3\" th:field=\"*{dataScope}\">本部门数据权限</option>\r\n\t\t\t\t\t\t<option value=\"4\" th:field=\"*{dataScope}\">本部门及以下数据权限</option>\r\n\t\t\t\t\t\t<option value=\"5\" th:field=\"*{dataScope}\">仅本人数据权限</option>\r\n\t\t\t\t\t</select>\r\n\t\t\t\t\t<span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 特殊情况下，设置为“自定数据权限”</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\" id=\"authDataScope\" th:style=\"'display:' + @{(*{dataScope=='2'} ? 'block' : 'none')} + ''\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">数据权限：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"1\" checked>展开/折叠</label>\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"2\">全选/全不选</label>\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"3\" checked>父子联动</label>\r\n\t\t\t\t    <div id=\"deptTrees\" class=\"ztree ztree-border\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: ztree-js\" />\r\n\t<script type=\"text/javascript\">\r\n\t\r\n\t    $(function() {\r\n\t\t\tvar url = ctx + \"system/role/deptTreeData?roleId=\" + $(\"#roleId\").val();\r\n\t\t\tvar options = {\r\n\t\t\t\tid: \"deptTrees\",\r\n\t\t        url: url,\r\n\t\t        check: { enable: true, nocheckInherit: true, chkboxType: { \"Y\": \"ps\", \"N\": \"ps\" } },\r\n\t\t        expandLevel: 2\r\n\t\t    };\r\n\t\t\t$.tree.init(options);\r\n\t    });\r\n\t    \r\n\t    $('input').on('ifChanged', function(obj){\r\n\t\t\tvar type = $(this).val();\r\n\t\t\tvar checked = obj.currentTarget.checked;\r\n\t\t\tif (type == 1) {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.expandAll(true);\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.expandAll(false);\r\n\t\t\t    }\r\n\t\t\t} else if (type == \"2\") {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.checkAllNodes(true);\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.checkAllNodes(false);\r\n\t\t\t    }\r\n\t\t\t} else if (type == \"3\") {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.setting.check.chkboxType = { \"Y\": \"ps\", \"N\": \"ps\" };\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.setting.check.chkboxType = { \"Y\": \"\", \"N\": \"\" };\r\n\t\t\t    }\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \tedit();\r\n\t        }\r\n\t    }\r\n\t\t\r\n\t\tfunction edit() {\r\n\t\t\tvar roleId = $(\"input[name='roleId']\").val();\r\n\t\t\tvar roleName = $(\"input[name='roleName']\").val();\r\n\t\t\tvar roleKey = $(\"input[name='roleKey']\").val();\r\n\t\t\tvar dataScope = $(\"#dataScope\").val();\r\n            var deptIds = $.tree.getCheckedNodes();\r\n\t\t\t$.ajax({\r\n\t\t\t\tcache : true,\r\n\t\t\t\ttype : \"POST\",\r\n\t\t\t\turl : ctx + \"system/role/authDataScope\",\r\n\t\t\t\tdata : {\r\n\t\t\t\t\t\"roleId\": roleId,\r\n\t\t\t\t\t\"roleName\": roleName,\r\n\t\t\t\t\t\"roleKey\": roleKey,\r\n\t\t\t\t\t\"dataScope\": dataScope,\r\n\t\t\t        \"deptIds\": deptIds\r\n\t\t\t\t},\r\n\t\t\t\tasync : false,\r\n\t\t\t\terror : function(request) {\r\n\t\t\t\t\t$.modal.alertError(\"系统错误\");\r\n\t\t\t\t},\r\n\t\t\t\tsuccess : function(data) {\r\n\t\t\t\t\t$.operate.successCallback(data);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\t\r\n\t\t$(\"#dataScope\").change(function(event){\r\n        \tvar dataScope = $(event.target).val();\r\n        \tdataScopeVisible(dataScope);\r\n        });\r\n\t\t\r\n\t\tfunction dataScopeVisible(dataScope) {\r\n\t\t\tif (dataScope == 2) {\r\n\t    \t\t$(\"#authDataScope\").show();\r\n\t    \t} else {\r\n\t    \t\t$._tree.checkAllNodes(false);\r\n\t    \t\t$(\"#authDataScope\").hide();\r\n\t    \t}\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/role/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改角色')\" />\r\n\t<th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-role-edit\" th:object=\"${role}\">\r\n\t\t\t<input id=\"roleId\" name=\"roleId\" type=\"hidden\" th:field=\"*{roleId}\"/>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">角色名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleName\" id=\"roleName\" th:field=\"*{roleName}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">权限字符：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleKey\" id=\"roleKey\" th:field=\"*{roleKey}\" required>\r\n\t\t\t\t\t<span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 控制器中定义的权限字符，如：@RequiresRoles(\"\")</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">显示顺序：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"roleSort\" id=\"roleSort\" th:field=\"*{roleSort}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<label class=\"toggle-switch switch-solid\">\r\n                        <input type=\"checkbox\" id=\"status\" th:checked=\"${role.status == '0' ? true : false}\">\r\n                        <span></span>\r\n                    </label>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input id=\"remark\" name=\"remark\" class=\"form-control\" type=\"text\" th:field=\"*{remark}\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">菜单权限：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"1\">展开/折叠</label>\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"2\">全选/全不选</label>\r\n\t\t\t\t    <label class=\"check-box\">\r\n\t\t\t\t        <input type=\"checkbox\" value=\"3\" checked>父子联动</label>\r\n\t\t\t\t    <div id=\"menuTrees\" class=\"ztree ztree-border\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: ztree-js\" />\r\n\t<script type=\"text/javascript\">\r\n\t     $(function() {\r\n\t\t\tvar url = ctx + \"system/menu/roleMenuTreeData?roleId=\" + $(\"#roleId\").val();\r\n\t\t\tvar options = {\r\n\t\t\t\tid: \"menuTrees\",\r\n\t\t        url: url,\r\n\t\t        check: { enable: true },\r\n\t\t        expandLevel: 0\r\n\t\t    };\r\n\t\t\t$.tree.init(options);\r\n\t\t});\r\n\t\r\n\t\t$(\"#form-role-edit\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\troleName:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/role/checkRoleNameUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t\t\t\t\t\t\"roleId\": function() {\r\n\t\t\t\t\t\t\t    return $(\"#roleId\").val();\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\"roleName\": function() {\r\n\t\t\t\t\t\t\t    return $.common.trim($(\"#roleName\").val());\r\n\t\t\t\t\t\t\t}\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\troleKey:{\r\n\t\t\t\t\tremote: {\r\n\t\t                url: ctx + \"system/role/checkRoleKeyUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t\t\t\t\t\t\"roleId\": function() {\r\n\t\t\t\t\t\t\t\treturn $(\"#roleId\").val();\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\"roleKey\": function() {\r\n\t\t\t\t\t\t\t    return $.common.trim($(\"#roleKey\").val());\r\n\t\t\t\t\t\t\t}\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\troleSort:{\r\n\t\t\t\t\tdigits:true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t        \"roleName\": {\r\n\t\t            remote: \"角色名称已经存在\"\r\n\t\t        },\r\n\t\t        \"roleKey\": {\r\n\t\t            remote: \"角色权限已经存在\"\r\n\t\t        }\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\t$('input').on('ifChanged', function(obj){\r\n\t\t\tvar type = $(this).val();\r\n\t\t\tvar checked = obj.currentTarget.checked;\r\n\t\t\tif (type == 1) {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.expandAll(true);\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.expandAll(false);\r\n\t\t\t    }\r\n\t\t\t} else if (type == \"2\") {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.checkAllNodes(true);\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.checkAllNodes(false);\r\n\t\t\t    }\r\n\t\t\t} else if (type == \"3\") {\r\n\t\t\t    if (checked) {\r\n\t\t\t        $._tree.setting.check.chkboxType = { \"Y\": \"ps\", \"N\": \"ps\" };\r\n\t\t\t    } else {\r\n\t\t\t        $._tree.setting.check.chkboxType = { \"Y\": \"\", \"N\": \"\" };\r\n\t\t\t    }\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tfunction edit() {\r\n\t\t\tvar roleId = $(\"input[name='roleId']\").val();\r\n\t\t\tvar roleName = $(\"input[name='roleName']\").val();\r\n\t\t\tvar roleKey = $(\"input[name='roleKey']\").val();\r\n\t\t\tvar roleSort = $(\"input[name='roleSort']\").val();\r\n\t\t\tvar status = $(\"input[id='status']\").is(':checked') == true ? 0 : 1;\r\n\t\t\tvar remark = $(\"input[name='remark']\").val();\r\n\t\t\tvar menuIds = $.tree.getCheckedNodes();\r\n\t\t\t$.ajax({\r\n\t\t\t\tcache : true,\r\n\t\t\t\ttype : \"POST\",\r\n\t\t\t\turl : ctx + \"system/role/edit\",\r\n\t\t\t\tdata : {\r\n\t\t\t\t\t\"roleId\": roleId,\r\n\t\t\t\t\t\"roleName\": roleName,\r\n\t\t\t\t\t\"roleKey\": roleKey,\r\n\t\t\t\t\t\"roleSort\": roleSort,\r\n\t\t\t\t\t\"status\": status,\r\n\t\t\t\t\t\"remark\": remark,\r\n\t\t\t\t\t\"menuIds\": menuIds\r\n\t\t\t\t},\r\n\t\t\t\tasync : false,\r\n\t\t\t\terror : function(request) {\r\n\t\t\t\t\t$.modal.alertError(\"系统错误\");\r\n\t\t\t\t},\r\n\t\t\t\tsuccess : function(data) {\r\n\t\t\t\t\t$.operate.successCallback(data);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \tedit();\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/role/role.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('角色列表')\" />\n</head>\n<body class=\"gray-bg\">\n\t<div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 search-collapse\">\n\t\t\t\t<form id=\"role-form\">\n\t\t\t\t\t<div class=\"select-list\">\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t角色名称：<input type=\"text\" name=\"roleName\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t权限字符：<input type=\"text\" name=\"roleKey\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t角色状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_normal_disable')}\">\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\n\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li class=\"select-time\">\n\t\t\t\t\t\t\t\t<label>创建时间： </label>\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[beginTime]\"/>\n\t\t\t\t\t\t\t\t<span>-</span>\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[endTime]\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\n\t\t\t\t<a class=\"btn btn-success\" onclick=\"$.operate.add()\" shiro:hasPermission=\"system:role:add\">\n\t                <i class=\"fa fa-plus\"></i> 新增\n\t            </a>\n\t            <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"system:role:edit\">\n\t\t            <i class=\"fa fa-edit\"></i> 修改\n\t\t        </a>\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"system:role:remove\">\n\t\t            <i class=\"fa fa-remove\"></i> 删除\n\t\t        </a>\n\t\t        <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"system:role:export\">\n\t\t            <i class=\"fa fa-download\"></i> 导出\n\t\t        </a>\n\t        </div>\n\t        \n\t        <div class=\"col-sm-12 select-table table-striped\">\n\t\t\t    <table id=\"bootstrap-table\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<th:block th:include=\"include :: footer\" />\n\t<script th:inline=\"javascript\">\n\t\tvar editFlag = [[${@permission.hasPermi('system:role:edit')}]];\n\t\tvar removeFlag = [[${@permission.hasPermi('system:role:remove')}]];\n\t\tvar prefix = ctx + \"system/role\";\n\t\t\n\n\t\t$(function() {\n\t\t    var options = {\n\t\t        url: prefix + \"/list\",\n\t\t        createUrl: prefix + \"/add\",\n\t\t        updateUrl: prefix + \"/edit/{id}\",\n\t\t        removeUrl: prefix + \"/remove\",\n\t\t        exportUrl: prefix + \"/export\",\n\t\t        viewUrl: prefix + \"/view/{id}\",\n\t\t        sortName: \"roleSort\",\n\t\t        modalName: \"角色\",\n\t\t        columns: [{\n\t\t            checkbox: true\n\t\t        },\n\t\t        {\n\t\t            field: 'roleId',\n\t\t            title: '角色编号'\n\t\t        },\n\t\t        {\n\t\t            field: 'roleName',\n\t\t            title: '角色名称',\n\t\t            sortable: true,\n\t\t            formatter: function(value, row, index) {\n\t\t                return '<a href=\"javascript:void(0)\" onclick=\"$.operate.view(\\'' + row.roleId + '\\')\">' + value + '</a>';\n\t\t            }\n\t\t        },\n\t\t        {\n\t\t            field: 'roleKey',\n\t\t            title: '权限字符',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t            field: 'dataScope',\n\t\t            title: '数据权限',\n\t\t            formatter: function(value, item, index) {\n\t\t                if (item.dataScope == '1') {\n\t\t                    return '<span class=\"badge badge-primary\">全部数据权限</span>';\n\t\t                }\n\t\t                else if (item.dataScope == '2') {\n\t\t                    return '<span class=\"badge badge-success\">自定义数据权限</span>';\n\t\t                }\n\t\t                else if (item.dataScope == '3') {\n\t\t                    return '<span class=\"badge badge-info\">本部门数据权限</span>';\n\t\t                }\n\t\t                else if (item.dataScope == '4') {\n\t\t                    return '<span class=\"badge badge-warning\">本部门及以下数据权限</span>';\n\t\t                }\n\t\t                else if (item.dataScope == '5') {\n\t\t                    return '<span class=\"badge badge-danger\">仅本人数据权限</span>';\n\t\t                }\n\t\t            }\n\t\t        },\n\t\t        {\n\t\t            field: 'roleSort',\n\t\t            title: '显示顺序',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t        \tvisible: editFlag == 'hidden' ? false : true,\n\t\t        \ttitle: '角色状态',\n\t\t        \talign: 'center',\n\t\t        \tformatter: function (value, row, index) {\n\t\t        \t\treturn statusTools(row);\n\t\t        \t}\n\t\t        },\n\t\t        {\n\t\t            field: 'createTime',\n\t\t            title: '创建时间',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'center',\n\t\t            formatter: function(value, row, index) {\n\t\t            \tif (row.roleId != 1) {\n\t\t                    var actions = [];\n\t\t                    actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.roleId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\n\t\t                    actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.roleId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a> ');\n\t\t                    var more = [];\n\t\t                    more.push(\"<a class='btn btn-default btn-xs \" + editFlag + \"' href='javascript:void(0)' onclick='authDataScope(\" + row.roleId + \")'><i class='fa fa-check-square-o'></i>数据权限</a> \");\n\t\t                    more.push(\"<a class='btn btn-default btn-xs \" + editFlag + \"' href='javascript:void(0)' onclick='authUser(\" + row.roleId + \")'><i class='fa fa-user'></i>分配用户</a>\");\n\t\t                    actions.push('<a tabindex=\"0\" class=\"btn btn-info btn-xs\" role=\"button\" data-container=\"body\" data-placement=\"left\" data-toggle=\"popover\" data-html=\"true\" data-trigger=\"hover\" data-content=\"' + more.join('') + '\"><i class=\"fa fa-chevron-circle-right\"></i>更多操作</a>');\n\t\t                    return actions.join('');\n\t\t            \t} else {\n\t\t                    return \"\";\n\t\t                }\n\t\t            }\n\t\t        }]\n\t\t    };\n\t\t    $.table.init(options);\n\t\t});\n\t\t\n\t\t/* 角色管理-分配数据权限 */\n\t\tfunction authDataScope(roleId) {\n\t\t    var url = prefix + '/authDataScope/' + roleId;\n\t\t    $.modal.open(\"分配数据权限\", url);\n\t\t}\n\t\t\n\t\t/* 角色管理-分配用户 */\n\t\tfunction authUser(roleId) {\n\t\t    var url = prefix + '/authUser/' + roleId;\n\t\t    $.modal.openTab(\"分配用户\", url);\n\t\t}\n\t\t\n\t\t/* 角色状态显示 */\n\t\tfunction statusTools(row) {\n\t\t    if (row.status == 1) {\n    \t\t\treturn '<i class=\\\"fa fa-toggle-off text-info fa-2x\\\" onclick=\"enable(\\'' + row.roleId + '\\')\"></i> ';\n    \t\t} else {\n    \t\t\treturn '<i class=\\\"fa fa-toggle-on text-info fa-2x\\\" onclick=\"disable(\\'' + row.roleId + '\\')\"></i> ';\n    \t\t}\n\t\t}\n\t\t\n\t\t/* 角色管理-停用 */\n\t\tfunction disable(roleId) {\n\t\t\t$.modal.confirm(\"确认要停用角色吗？\", function() {\n\t\t\t\t$.operate.post(prefix + \"/changeStatus\", { \"roleId\": roleId, \"status\": 1 });\n\t\t    })\n\t\t}\n\n\t\t/* 角色管理启用 */\n\t\tfunction enable(roleId) {\n\t\t\t$.modal.confirm(\"确认要启用角色吗？\", function() {\n\t\t\t\t$.operate.post(prefix + \"/changeStatus\", { \"roleId\": roleId, \"status\": 0 });\n\t\t    })\n\t\t}\n\t</script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/role/selectUser.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('分配角色选择用户')\" />\r\n</head>\r\n\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"role-form\">\r\n\t\t\t\t    <input type=\"hidden\" id=\"roleId\" name=\"roleId\" th:value=\"${role.roleId}\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t登录名称：<input type=\"text\" name=\"loginName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t手机号码：<input type=\"text\" name=\"phonenumber\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar datas = [[${@dict.getType('sys_normal_disable')}]];\r\n\t\tvar prefix = ctx + \"system/role/authUser\";\r\n\r\n\t\t$(function() {\r\n\t\t\tvar options = {\r\n\t\t        url: prefix + \"/unallocatedList\",\r\n\t\t        queryParams: queryParams,\r\n\t\t        sortName: \"createTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        clickToSelect: true,\r\n\t\t        rememberSelected: true,\r\n\t\t        columns: [{\r\n\t\t        \tfield: 'state',\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'userId',\r\n\t\t            title: '用户ID',\r\n\t\t            visible: false\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginName',\r\n\t\t            title: '登录名称',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'userName',\r\n\t\t            title: '用户名称'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'email',\r\n\t\t            title: '邮箱'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'phonenumber',\r\n\t\t            title: '手机'\r\n\t\t        },\r\n\t\t        {\r\n\t\t        \tfield: 'status',\r\n\t\t        \ttitle: '用户状态',\r\n\t\t        \talign: 'center',\r\n\t\t        \tformatter: function (value, row, index) {\r\n\t\t        \t\treturn $.table.selectDictLabel(datas, value);\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t\t\r\n\t\tfunction queryParams(params) {\r\n\t\t\tvar search = $.table.queryParams(params);\r\n\t\t\tsearch.roleId = $(\"#roleId\").val();\r\n\t\t\treturn search;\r\n\t\t}\r\n\t\t\r\n\t\t/* 添加用户-选择用户-提交 */\r\n\t\tfunction submitHandler() {\r\n\t\t\tvar rows = $.table.selectFirstColumns();\r\n\t\t\tif (rows.length == 0) {\r\n       \t\t\t$.modal.alertWarning(\"请至少选择一条记录\");\r\n       \t\t\treturn;\r\n       \t\t}\r\n\t\t\tvar data = { \"roleId\": $(\"#roleId\").val(), \"userIds\": rows.join() };\r\n\t\t\t$.operate.save(prefix + \"/selectAll\", data);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/role/view.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <th:block th:include=\"include :: header('角色详情')\" />\n    <style>.perm-tree{margin:0;padding:0;list-style:none;font-size:13px;display:flex;flex-wrap:wrap;gap:0}.tree-group{display:inline-block;vertical-align:top;margin:0 10px 12px 0;min-width:130px}.tree-group-title{font-weight:600;color:#fff;padding:4px 10px;background:#337ab7;border-radius:3px 3px 0 0;white-space:nowrap;font-size:12px}.tree-group-title i{margin-right:4px}.tree-group-body{border:1px solid #d0e4f5;border-top:0;border-radius:0 0 3px 3px;padding:4px 8px;background:#f7fbff}.tree-children{margin:0;padding:0;list-style:none}.tree-item{line-height:22px;color:#444;white-space:nowrap;font-size:12px}.tree-sub-group{margin-top:4px}.tree-sub-title{font-weight:600;color:#555;font-size:12px;line-height:22px;border-bottom:1px dashed #ddd;margin-bottom:1px}.tree-sub-title i{color:#f0ad4e;margin-right:3px}.tree-sub-children{padding-left:10px}.tree-item .icon-check{color:#5cb85c;margin-right:3px}.tree-item .icon-perm{color:#aaa;margin-right:3px;font-size:10px}.user-search-bar{margin:10px 0 14px 0}.user-search-inner{position:relative;display:flex;align-items:center;max-width:420px;border:1px solid #c8dff5;border-radius:20px;background:#fff;padding:0 12px;transition:border-color .2s,box-shadow .2s}.user-search-inner:focus-within{border-color:#337ab7;box-shadow:0 0 0 2px rgba(51,122,183,.12)}.user-search-icon{color:#aaa;font-size:13px;margin-right:8px;flex-shrink:0}.user-search-inner input{flex:1;border:0;outline:0;font-size:13px;line-height:34px;background:transparent;color:#333}.user-search-inner input::placeholder{color:#bbb}.user-search-clear{cursor:pointer;color:#bbb;font-size:14px;margin-left:6px;flex-shrink:0;line-height:1}.user-search-clear:hover{color:#888}.user-search-count{font-size:12px;color:#888;margin-left:10px;white-space:nowrap;flex-shrink:0}.user-card.hidden{display:none}.user-card mark{background:#fff3cd;color:#333;padding:0;border-radius:2px}#userTableWrap{margin-top:4px}.user-card-grid{display:flex;flex-wrap:wrap;gap:14px;margin-top:10px}.user-card{width:240px;border:1px solid #dce8f5;border-radius:5px;padding:14px 16px;background:#f7fbff;font-size:13px;line-height:24px;position:relative}.user-card .user-avatar{width:42px;height:42px;border-radius:50%;background:#337ab7;color:#fff;font-size:18px;font-weight:bold;text-align:center;line-height:42px;display:inline-block;margin-right:10px;vertical-align:middle;flex-shrink:0}.user-card .user-name{font-weight:600;font-size:14px;vertical-align:middle}.user-card .user-meta{color:#555;margin-top:8px}.user-card .user-meta span{display:block}.user-card .user-status{position:absolute;top:10px;right:10px;font-size:11px;padding:1px 7px;border-radius:10px}.user-card .user-status.normal{background:#dff0d8;color:#3c763d}.user-card .user-status.disable{background:#f2dede;color:#a94442}.dept-tree{margin:0;padding:0;list-style:none;font-size:13px}.dept-tree li{line-height:26px}.dept-tag{display:inline-block;padding:2px 10px;border-radius:3px;font-size:12px;background:#dff0d8;color:#3c763d;border:1px solid #d6e9c6;margin:2px 0}.dept-tag i{margin-right:3px}.dept-ancestor{color:#999;font-size:12px}.dept-ancestor i{margin-right:2px}.dept-children{padding-left:16px;border-left:1px dashed #d6e9c6;margin-left:8px}.perm-empty{color:#999;font-style:italic;font-size:13px}#menuTableWrap{background-color:#f9f9f9;border-radius:4px;border:1px solid #eee;margin-top:10px}#menuTableWrap .form-group{margin-bottom:0}#menuTableWrap .perm-tree{max-height:300px;overflow-y:auto;padding:10px;background-color:#fff;border:1px solid #ddd;border-radius:3px}#loadMoreBtn{padding:6px 20px;border:1px solid #dcdcdc;background:#f8f9fa;color:#666;border-radius:4px;transition:all .3s}#loadMoreBtn:hover{background:#e9ecef;border-color:#c8d0d7}#loadMoreBtn:disabled{opacity:.6;cursor:not-allowed}#loadingMore{color:#888}</style>\n</head>\n<body>\n    <div class=\"main-content\">\n        <form class=\"form-horizontal\" th:object=\"${role}\">\n            <h4 class=\"form-header h4\">基本信息</h4>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">角色名称：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{roleName}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">权限字符：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{roleKey}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">角色状态：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\">\n                                <span th:if=\"*{status == '0'}\" class=\"badge badge-success\">正常</span>\n                                <span th:if=\"*{status != '0'}\" class=\"badge badge-danger\">停用</span>\n                            </p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">数据范围：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\">\n                                <span th:if=\"*{dataScope == '1'}\" class=\"badge badge-primary\">全部数据权限</span>\n                                <span th:if=\"*{dataScope == '2'}\" class=\"badge badge-success\">自定义数据权限</span>\n                                <span th:if=\"*{dataScope == '3'}\" class=\"badge badge-info\">本部门数据权限</span>\n                                <span th:if=\"*{dataScope == '4'}\" class=\"badge badge-warning\">本部门及以下数据权限</span>\n                                <span th:if=\"*{dataScope == '5'}\" class=\"badge badge-danger\">仅本人数据权限</span>\n                            </p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">创建者：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{#strings.defaultString(createBy,'-')}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">创建时间：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\"\n                               th:text=\"*{createTime != null ? #dates.format(createTime,'yyyy-MM-dd HH:mm:ss') : '-'}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">更新者：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{#strings.defaultString(updateBy,'-')}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">更新时间：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\"\n                               th:text=\"*{updateTime != null ? #dates.format(updateTime,'yyyy-MM-dd HH:mm:ss') : '-'}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-12\">\n                    <div class=\"form-group\">\n                        <label class=\"col-xs-2 control-label\">备注：</label>\n                        <div class=\"col-xs-10\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{#strings.defaultString(remark,'-')}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <h4 class=\"form-header h4\">数据权限</h4>\n            <div class=\"row\">\n                <div class=\"col-sm-12\">\n                    <div class=\"form-group\">\n                        <label class=\"col-xs-2 control-label\">数据范围：</label>\n                        <div class=\"col-xs-10\">\n                            <p class=\"form-control-plaintext\">\n                                <span th:if=\"*{dataScope == '1'}\">全部数据权限 &mdash; 可查看系统内所有数据</span>\n                                <span th:if=\"*{dataScope == '2'}\">自定义数据权限 &mdash; 仅可查看下方勾选部门的数据</span>\n                                <span th:if=\"*{dataScope == '3'}\">本部门数据权限 &mdash; 仅可查看本部门数据</span>\n                                <span th:if=\"*{dataScope == '4'}\">本部门及以下数据权限 &mdash; 可查看本部门及其下级部门数据</span>\n                                <span th:if=\"*{dataScope == '5'}\">仅本人数据权限 &mdash; 仅可查看本人数据</span>\n                            </p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\" th:if=\"*{dataScope == '2'}\">\n                <div class=\"col-sm-12\">\n                    <div class=\"form-group\">\n                        <label class=\"col-xs-2 control-label\">自定义部门：</label>\n                        <div class=\"col-xs-10\" style=\"padding-top:6px;\">\n                            <div id=\"deptPermArea\"><span class=\"perm-empty\">加载中...</span></div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <h4 class=\"form-header h4\">菜单权限</h4>\n            <div class=\"row\">\n                <div class=\"col-sm-12\">\n                    <div class=\"form-group\">\n                        <label class=\"col-xs-2 control-label\">已分配菜单：</label>\n                        <div class=\"col-xs-10\" style=\"padding-top:6px;\">\n                            <strong id=\"menuCountBadge\">0</strong> 个菜单权限\n                            &nbsp;\n                            <a href=\"javascript:void(0);\"\n                               class=\"btn btn-info btn-xs\"\n                               id=\"btnToggleMenus\"\n                               onclick=\"toggleMenuList()\">\n                                <i class=\"fa fa-list\"></i> 查看已分配菜单\n                            </a>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <!-- 内嵌菜单权限树（展开/收起） -->\n            <div id=\"menuTableWrap\" style=\"display:none; padding: 0 15px 10px 15px;\">\n                <div class=\"row\">\n                    <div class=\"col-sm-12\">\n                        <div class=\"form-group\">\n                            <div style=\"padding-top:6px;\">\n                                <ul class=\"perm-tree\" id=\"menuPermTree\">\n                                    <li class=\"perm-empty\">加载中...</li>\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <h4 class=\"form-header h4\">关联用户</h4>\n            <div class=\"row\">\n                <div class=\"col-sm-12\">\n                    <div class=\"form-group\">\n                        <label class=\"col-xs-2 control-label\">已分配用户数：</label>\n                        <div class=\"col-xs-10\" style=\"padding-top:6px;\">\n                            <strong id=\"userCountBadge\" th:text=\"${userCount}\">0</strong> 个关联用户 \n                            &nbsp;\n                            <a href=\"javascript:void(0);\"\n                               class=\"btn btn-info btn-xs\"\n                               id=\"btnToggleUsers\"\n                               onclick=\"toggleUserList()\">\n                                <i class=\"fa fa-users\"></i> 查看已分配用户\n                            </a>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <!-- 内嵌用户列表（展开/收起） -->\n            <div id=\"userTableWrap\" style=\"display:none; padding: 0 15px 10px 15px;\">\n                <!-- 搜索栏 -->\n                <div class=\"user-search-bar\" id=\"userSearchBar\" style=\"display:none;\">\n                    <div class=\"user-search-inner\">\n                        <i class=\"fa fa-search user-search-icon\"></i>\n                        <input type=\"text\" id=\"userSearchInput\"\n                               placeholder=\"搜索用户名、登录名、手机号...\"\n                               oninput=\"filterUserCards(this.value)\"\n                               autocomplete=\"off\"/>\n                        <span class=\"user-search-clear\" id=\"userSearchClear\"\n                              onclick=\"clearUserSearch()\" style=\"display:none;\">\n                            <i class=\"fa fa-times-circle\"></i>\n                        </span>\n                        <span class=\"user-search-count\" id=\"userSearchCount\"></span>\n                    </div>\n                </div>\n\n                <span id=\"userLoadingTip\" style=\"display:none; color:#999; font-size:13px;\">\n                    <i class=\"fa fa-spinner fa-spin\"></i> 加载中...\n                </span>\n                <span id=\"userEmptyTip\" style=\"display:none; color:#999; font-style:italic; font-size:13px;\">\n                    该角色暂无分配用户\n                </span>\n                <div class=\"user-card-grid\" id=\"userCardGrid\"></div>\n                <!-- 加载更多按钮 -->\n                <div id=\"loadMoreWrap\" style=\"display:none; text-align:center; padding:20px 0;\">\n                    <button id=\"loadMoreBtn\" class=\"btn btn-default btn-sm\" onclick=\"loadMoreUsers()\">\n                        <i class=\"fa fa-refresh\"></i> 加载更多\n                    </button>\n                    <div id=\"loadingMore\" style=\"display:none; color:#888; font-size:13px; margin-top:5px;\">\n                        <i class=\"fa fa-spinner fa-spin\"></i> 正在加载...\n                    </div>\n                </div>\n                <div id=\"userNoMatchTip\" style=\"display:none; padding:20px 0; text-align:center; color:#999; font-size:13px;\">\n                    <i class=\"fa fa-search\" style=\"font-size:24px; display:block; margin-bottom:6px; color:#ccc;\"></i>\n                    未找到匹配的用户\n                </div>\n            </div>\n        </form>\n    </div>\n\n    <th:block th:include=\"include :: footer\" />\n    <script th:inline=\"javascript\">\n        var ctx       = [[@{/}]];\n        var roleId    = [[${role.roleId}]];\n        var menuNodes = [[${menuTree}]];\n        var deptNodes = [[${deptTree != null ? deptTree : '[]'}]];\n        var pageNum = 1;        // 当前页码\n        var pageSize = 100;     // 每页显示数量\n        var totalUsers = 0;     // 用户总数\n        var isLoading = false;  // 防止重复加载\n        var hasMore = true;     // 是否还有更多数据\n        var allUsers = [];      // 存储所有已加载的用户数据（用于搜索筛选）\n\n        function buildTree(nodes) {\n            var map = {}, roots = [];\n            nodes.forEach(function(n) {\n                map[n.id] = {\n                    id: n.id, pId: n.pId,\n                    title: n.title || n.name,\n                    checked: n.checked,\n                    children: []\n                };\n            });\n            nodes.forEach(function(n) {\n                var node = map[n.id];\n                if (n.pId && map[n.pId]) {\n                    map[n.pId].children.push(node);\n                } else {\n                    roots.push(node);\n                }\n            });\n            return roots;\n        }\n\n        /* 判断节点或其后代中是否存在任意 checked 节点 */\n        function hasChecked(node) {\n            if (node.checked) return true;\n            return node.children.some(function(c) { return hasChecked(c); });\n        }\n\n        /* 菜单权限树渲染 */\n        function renderMenuTree(nodes) {\n            var roots = buildTree(nodes).filter(function(r) { return hasChecked(r); });\n            if (roots.length === 0) {\n                return '<li class=\"perm-empty\">暂无菜单权限</li>';\n            }\n            var html = '';\n            roots.forEach(function(root) {\n                html += '<li class=\"tree-group\">';\n                html += '<div class=\"tree-group-title\"><i class=\"fa fa-th-list\"></i>' + root.title + '</div>';\n                html += '<div class=\"tree-group-body\">';\n                html += renderMenuLevel(root.children);\n                html += '</div></li>';\n            });\n            return html;\n        }\n\n        function renderMenuLevel(children) {\n            if (!children || children.length === 0) return '';\n            var visible = children.filter(function(c) { return hasChecked(c); });\n            if (visible.length === 0) return '';\n\n            var html = '<ul class=\"tree-children\">';\n            visible.forEach(function(node) {\n                var hasKids = node.children && node.children.length > 0;\n                var kidChecked = hasKids && node.children.some(function(c) { return hasChecked(c); });\n\n                if (hasKids && kidChecked) {\n                    // 中间层：子分组标题 + 递归渲染子节点\n                    html += '<li class=\"tree-item tree-sub-group\">';\n                    html += '<div class=\"tree-sub-title\"><i class=\"fa fa-folder-open\"></i>' + node.title + '</div>';\n                    html += '<div class=\"tree-sub-children\">' + renderMenuLevel(node.children) + '</div>';\n                    html += '</li>';\n                } else {\n                    // 叶子节点（按钮权限、无下级菜单页面等）\n                    var icon = node.checked\n                        ? '<i class=\"fa fa-check icon-check\"></i>'\n                        : '<i class=\"fa fa-minus icon-perm\"></i>';\n                    html += '<li class=\"tree-item\">' + icon + node.title + '</li>';\n                }\n            });\n            html += '</ul>';\n            return html;\n        }\n\n        /* 部门权限树渲染 */\n        function renderDeptTree(nodes) {\n            if (!nodes || nodes.length === 0) {\n                return '<span class=\"perm-empty\">暂无自定义部门权限</span>';\n            }\n            var roots = buildTree(nodes);\n            var anyChecked = nodes.some(function(n) { return n.checked; });\n            if (!anyChecked) {\n                return '<span class=\"perm-empty\">暂无自定义部门权限</span>';\n            }\n            return '<ul class=\"dept-tree\">' + renderDeptLevel(roots) + '</ul>';\n        }\n\n        function renderDeptLevel(nodes) {\n            var html = '';\n            nodes.forEach(function(node) {\n                if (!hasChecked(node)) return;\n                html += '<li>';\n                if (node.checked) {\n                    html += '<span class=\"dept-tag\"><i class=\"fa fa-building-o\"></i>' + node.title + '</span>';\n                } else {\n                    // 未勾选的祖先节点，淡色展示作为路径提示\n                    html += '<span class=\"dept-ancestor\"><i class=\"fa fa-angle-right\"></i>' + node.title + '</span>';\n                }\n                if (node.children && node.children.length > 0) {\n                    var inner = renderDeptLevel(node.children);\n                    if (inner) {\n                        html += '<div class=\"dept-children\"><ul class=\"dept-tree\">' + inner + '</ul></div>';\n                    }\n                }\n                html += '</li>';\n            });\n            return html;\n        }\n\n        /* 初始化 */\n        $(function() {\n            // 渲染菜单树\n            var menuTreeHtml = renderMenuTree(menuNodes);\n            $('#menuPermTree').html(menuTreeHtml);\n            \n            // 初始化菜单数量\n            updateMenuCount();\n            \n            // 渲染部门树\n            if ($('#deptPermArea').length) {\n                $('#deptPermArea').html(renderDeptTree(deptNodes));\n            }\n        });\n        \n        /* 菜单权限：展开 / 收起内嵌菜单树 */\n        var menuLoaded = false;\n        var menuListVisible = false;\n        \n        function toggleMenuList() {\n            var $wrap = $('#menuTableWrap');\n            var $btn  = $('#btnToggleMenus');\n            if (menuListVisible) {\n                $wrap.slideUp(150);\n                $btn.html('<i class=\"fa fa-list\"></i> 查看已分配菜单');\n                menuListVisible = false;\n            } else {\n                $wrap.slideDown(150);\n                $btn.html('<i class=\"fa fa-list\"></i> 收起菜单列表');\n                menuListVisible = true;\n                if (!menuLoaded) { \n                    // 菜单树已经在页面加载时渲染，这里只需要标记为已加载\n                    menuLoaded = true;\n                    // 计算并更新菜单数量\n                    updateMenuCount();\n                }\n            }\n        }\n        \n        /* 计算并更新菜单权限数量 */\n        function updateMenuCount() {\n            var $menuTree = $('#menuPermTree');\n            var menuCount = 0;\n            \n            // 计算已分配的菜单数量\n            if (menuNodes && Array.isArray(menuNodes)) {\n                // 只计算被选中的节点\n                menuCount = menuNodes.filter(function(node) {\n                    return node.checked === true;\n                }).length;\n            }\n            \n            // 更新显示\n            $('#menuCountBadge').text(menuCount);\n        }\n\n        /* 关联用户：展开 / 收起内嵌用户卡片列表 */\n        var userLoaded = false;\n        var userListVisible = false;\n\n        function toggleUserList() {\n            var $wrap = $('#userTableWrap');\n            var $btn  = $('#btnToggleUsers');\n            if (userListVisible) {\n                $wrap.slideUp(150);\n                $btn.html('<i class=\"fa fa-users\"></i> 查看已分配用户');\n                userListVisible = false;\n            } else {\n                $wrap.slideDown(150);\n                $btn.html('<i class=\"fa fa-users\"></i> 收起用户列表');\n                userListVisible = true;\n                if (!userLoaded) { loadUserCards(); }\n            }\n        }\n\n        function loadUserCards() {\n            var $grid    = $('#userCardGrid');\n            var $loading = $('#userLoadingTip');\n            var $empty   = $('#userEmptyTip');\n            var $loadMoreWrap = $('#loadMoreWrap');\n        \n            // 重置状态\n            $grid.empty();\n            allUsers = [];\n            pageNum = 1;\n            hasMore = true;\n            $loadMoreWrap.hide();\n            \n            $loading.show();\n            $empty.hide();\n            $('#userSearchBar').hide();\n            $('#userNoMatchTip').hide();\n        \n            // 获取用户总数\n            totalUsers = parseInt($('#userCountBadge').text()) || 0;\n            \n            if (totalUsers === 0) {\n                $loading.hide();\n                $empty.show();\n                return;\n            }\n        \n            // 第一次加载\n            loadUsersAjax();\n        }\n\n        /* 用户搜索 / 筛选 */\n        function filterUserCards(keyword) {\n            var kw = $.trim(keyword).toLowerCase();\n            var $cards = $('#userCardGrid .user-card');\n            var totalLoaded = $cards.length;\n            var $clear = $('#userSearchClear');\n        \n            $clear.toggle(kw.length > 0);\n        \n            if (kw === '') {\n                $cards.removeClass('hidden');\n                updateSearchCount(totalLoaded, allUsers.length);\n                $('#userNoMatchTip').hide();\n                return;\n            }\n        \n            var matched = 0;\n            $cards.each(function() {\n                var search = $(this).data('search') || '';\n                if (search.indexOf(kw) !== -1) {\n                    $(this).removeClass('hidden');\n                    matched++;\n                } else {\n                    $(this).addClass('hidden');\n                }\n            });\n        \n            updateSearchCount(matched, totalLoaded);\n            $('#userNoMatchTip').toggle(matched === 0);\n        }\n\n        function updateSearchCount(matched, total) {\n            var kw = $.trim($('#userSearchInput').val());\n            var totalAllUsers = allUsers.length;\n            \n            if (kw) {\n                $('#userSearchCount').text('找到 ' + matched + ' 人 (已加载 ' + totalAllUsers + '/' + totalUsers + ' 人)');\n            } else {\n                $('#userSearchCount').text('已加载 ' + totalAllUsers + '/' + totalUsers + ' 人');\n            }\n        }\n\n        function clearUserSearch() {\n            $('#userSearchInput').val('').focus();\n            filterUserCards('');\n        }\n        \n        \n        /* 加载用户的AJAX请求 */\n        function loadUsersAjax() {\n            if (isLoading || !hasMore) return;\n            \n            isLoading = true;\n            $('#loadingMore').show();\n            $('#loadMoreBtn').prop('disabled', true);\n            \n            $.ajax({\n                url  : ctx + 'system/role/authUser/allocatedList',\n                type : 'POST',\n                data : { \n                    roleId: roleId, \n                    pageNum: pageNum,\n                    pageSize: pageSize\n                },\n                success: function(res) {\n                    isLoading = false;\n                    $('#loadingMore').hide();\n                    $('#loadMoreBtn').prop('disabled', false);\n                    \n                    var rows = (res && res.rows) ? res.rows : [];\n                    var total = res.total || 0;\n                    \n                    // 更新用户总数\n                    if (total > 0 && total !== totalUsers) {\n                        totalUsers = total;\n                        $('#userCountBadge').text(total);\n                    }\n                    \n                    if (rows.length === 0 && pageNum === 1) {\n                        // 第一页就没有数据\n                        $('#userLoadingTip').hide();\n                        $('#userEmptyTip').show();\n                        return;\n                    }\n                    \n                    // 渲染用户卡片\n                    renderUserCards(rows);\n                    \n                    // 添加到所有用户列表（用于搜索）\n                    allUsers = allUsers.concat(rows);\n                    \n                    // 判断是否还有更多数据\n                    var loadedCount = (pageNum - 1) * pageSize + rows.length;\n                    hasMore = loadedCount < totalUsers;\n                    \n                    if (hasMore) {\n                        $('#loadMoreWrap').show();\n                    } else {\n                        $('#loadMoreWrap').hide();\n                    }\n                    \n                    // 更新页面状态\n                    pageNum++;\n                    \n                    // 第一次加载完成时显示搜索栏\n                    if (pageNum === 2) {\n                        $('#userLoadingTip').hide();\n                        $('#userSearchBar').show();\n                        updateSearchCount(rows.length, loadedCount);\n                    } else {\n                        updateSearchCount(rows.length, loadedCount);\n                    }\n                    \n                    userLoaded = true;\n                },\n                error: function() {\n                    isLoading = false;\n                    $('#loadingMore').hide();\n                    $('#loadMoreBtn').prop('disabled', false);\n                    \n                    if (pageNum === 1) {\n                        $('#userLoadingTip').hide();\n                        $('#userEmptyTip').text('加载失败，请重试').show();\n                    } else {\n                        alert('加载失败，请重试');\n                    }\n                }\n            });\n        }\n        \n        /* 渲染用户卡片 */\n        function renderUserCards(users) {\n            var $grid = $('#userCardGrid');\n            \n            users.forEach(function(u) {\n                var initial  = (u.userName || u.loginName || '?').charAt(0).toUpperCase();\n                var statusHtml = u.status === '0'\n                    ? '<span class=\"user-status normal\">正常</span>'\n                    : '<span class=\"user-status disable\">停用</span>';\n                \n                // 搜索关键词\n                var searchKey = [u.userName || '', u.loginName || '', u.phonenumber || ''].join('|').toLowerCase();\n                \n                var card = [\n                    '<div class=\"user-card\" data-search=\"' + searchKey + '\">',\n                    statusHtml,\n                    '<div style=\"display:flex;align-items:center;margin-bottom:4px;\">',\n                    '  <span class=\"user-avatar\">' + initial + '</span>',\n                    '  <span class=\"user-name\">' + (u.userName || '-') + '</span>',\n                    '</div>',\n                    '<div class=\"user-meta\">',\n                    '  <span><i class=\"fa fa-user-o\" style=\"width:14px;color:#888\"></i> ' + (u.loginName || '-') + '</span>',\n                    '  <span><i class=\"fa fa-phone\"  style=\"width:14px;color:#888\"></i> ' + (u.phonenumber || '-') + '</span>',\n                    '  <span><i class=\"fa fa-envelope-o\" style=\"width:14px;color:#888\"></i> ' + (u.email || '-') + '</span>',\n                    '</div>',\n                    '</div>'\n                ].join('');\n                \n                $grid.append(card);\n            });\n        }\n        \n        /* 加载更多用户 */\n        function loadMoreUsers() {\n            if (!isLoading && hasMore) {\n                loadUsersAjax();\n            }\n        }\n        \n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增用户')\" />\r\n\t<th:block th:include=\"include :: select2-css\" />\r\n</head>\r\n<body>\r\n    <div class=\"main-content\">\r\n        <form id=\"form-user-add\" class=\"form-horizontal\">\r\n            <input name=\"deptId\" type=\"hidden\" id=\"treeId\"/>\r\n            <h4 class=\"form-header h4\">基本信息</h4>\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">用户名称：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"userName\" placeholder=\"请输入用户名称\" class=\"form-control\" type=\"text\" maxlength=\"30\" required>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">归属部门：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                            \t<input name=\"deptName\" onclick=\"selectDeptTree()\" id=\"treeName\" type=\"text\" placeholder=\"请选择归属部门\" class=\"form-control\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">手机号码：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                                <input id=\"phonenumber\" name=\"phonenumber\" placeholder=\"请输入手机号码\" class=\"form-control\" type=\"text\" maxlength=\"11\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-mobile\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">邮箱：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                                <input id=\"email\" name=\"email\" class=\"form-control email\" type=\"text\" maxlength=\"50\" placeholder=\"请输入邮箱\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-envelope\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">登录账号：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input id=\"loginName\" name=\"loginName\" placeholder=\"请输入登录账号\" class=\"form-control\" type=\"text\" maxlength=\"30\" required>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">登录密码：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                                <input id=\"password\" name=\"password\" placeholder=\"请输入登录密码\" class=\"form-control\" type=\"password\" th:value=\"${@config.getKey('sys.user.initPassword')}\" required>\r\n                                <span class=\"input-group-addon\" title=\"登录密码,鼠标按下显示密码\"\r\n                                    onmousedown=\"$('#password').attr('type','text')\"\r\n                                    onmouseup=\"$('#password').attr('type','password')\"><i class=\"fa fa-key\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">用户性别：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <select name=\"sex\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_user_sex')}\">\r\n\t\t\t\t                <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t            </select>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">用户状态：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <label class=\"toggle-switch switch-solid\">\r\n\t                            <input type=\"checkbox\" id=\"status\" checked>\r\n\t                            <span></span>\r\n\t                        </label>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-12\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-xs-2 control-label\">岗位：</label>\r\n                        <div class=\"col-xs-4\">\r\n                            <select id=\"post\" class=\"form-control select2-multiple\" multiple>\r\n\t\t\t\t\t\t\t\t<option th:each=\"post:${posts}\" th:value=\"${post.postId}\" th:text=\"${post.postName}\" th:disabled=\"${post.status == '1'}\"></option>\r\n\t\t\t\t\t\t\t</select>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-12\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-xs-2 control-label\">角色：</label>\r\n                        <div class=\"col-xs-10\">\r\n                            <label th:each=\"role:${roles}\" class=\"check-box\">\r\n\t\t\t\t\t\t\t\t<input name=\"role\" type=\"checkbox\" th:value=\"${role.roleId}\" th:text=\"${role.roleName}\" th:disabled=\"${role.status == '1'}\">\r\n\t\t\t\t\t\t\t</label>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <h4 class=\"form-header h4\">其他信息</h4>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-xs-2 control-label\">备注：</label>\r\n                        <div class=\"col-xs-10\">\r\n                            <textarea name=\"remark\" maxlength=\"500\" class=\"form-control\" rows=\"3\"></textarea>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n      \r\n    <div class=\"row\">\r\n        <div class=\"col-sm-offset-5 col-sm-10\">\r\n            <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submitHandler()\"><i class=\"fa fa-check\"></i>保 存</button>&nbsp;\r\n            <button type=\"button\" class=\"btn btn-sm btn-danger\" onclick=\"closeItem()\"><i class=\"fa fa-reply-all\"></i>关 闭 </button>\r\n        </div>\r\n    </div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: select2-js\" />\r\n\t<script>\r\n\t    var prefix = ctx + \"system/user\";\r\n\t\r\n        $(\"#form-user-add\").validate({\r\n        \tonkeyup: false,\r\n        \trules:{\r\n        \t\tloginName:{\r\n        \t\t\tminlength: 2,\r\n        \t\t\tmaxlength: 20,\r\n        \t\t\tremote: {\r\n                        url: prefix + \"/checkLoginNameUnique\",\r\n                        type: \"post\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                        \t\"loginName\": function() {\r\n                                return $.common.trim($(\"#loginName\").val());\r\n                            }\r\n                        }\r\n                    }\r\n        \t\t},\r\n        \t\tpassword:{\r\n        \t\t\tminlength: 5,\r\n        \t\t\tmaxlength: 20,\r\n        \t\t\tspecialSign: true\r\n        \t\t},\r\n        \t\temail:{\r\n                    email:true,\r\n                    remote: {\r\n                        url: prefix + \"/checkEmailUnique\",\r\n                        type: \"post\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                            \"email\": function () {\r\n                                return $.common.trim($(\"#email\").val());\r\n                            }\r\n                        }\r\n                    }\r\n        \t\t},\r\n        \t\tphonenumber:{\r\n        \t\t\tisPhone:true,\r\n                    remote: {\r\n                        url: prefix + \"/checkPhoneUnique\",\r\n                        type: \"post\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                            \"phonenumber\": function () {\r\n                                return $.common.trim($(\"#phonenumber\").val());\r\n                            }\r\n                        }\r\n                    }\r\n        \t\t},\r\n        \t},\r\n        \tmessages: {\r\n                \"loginName\": {\r\n                    remote: \"用户已经存在\"\r\n                },\r\n        \t\t\"email\": {\r\n                    remote: \"Email已经存在\"\r\n                },\r\n        \t\t\"phonenumber\":{\r\n                \tremote: \"手机号码已经存在\"\r\n        \t\t}\r\n            },\r\n            focusCleanup: true\r\n        });\r\n        \r\n        function submitHandler() {\r\n        \tvar chrtype = [[${#strings.defaultString(@config.getKey('sys.account.chrtype'), 0)}]];\r\n\t\t\tvar password = $(\"#password\").val();\r\n\t        if ($.validate.form() && checkpwd(chrtype, password)) {\r\n\t        \tvar data = $(\"#form-user-add\").serializeArray();\r\n\t        \tvar status = $(\"input[id='status']\").is(':checked') == true ? 0 : 1;\r\n\t        \tvar roleIds = $.form.selectCheckeds(\"role\");\r\n\t        \tvar postIds = $.form.selectSelects(\"post\");\r\n\t        \tdata.push({\"name\": \"status\", \"value\": status});\r\n\t        \tdata.push({\"name\": \"roleIds\", \"value\": roleIds});\r\n\t        \tdata.push({\"name\": \"postIds\", \"value\": postIds});\r\n\t        \t$.operate.saveTab(prefix + \"/add\", data);\r\n\t        }\r\n\t    }\r\n         \r\n        /* 用户管理-新增-选择部门树 */\r\n        function selectDeptTree() {\r\n        \tvar treeId = $(\"#treeId\").val();\r\n        \tvar deptId = $.common.isEmpty(treeId) ? \"100\" : $(\"#treeId\").val();\r\n        \tvar url = ctx + \"system/user/selectDeptTree/\" + deptId;\r\n            var btn = ['<i class=\"fa fa-check\"></i> 确认', '<i class=\"fa fa-trash-o\"></i> 清除', '<i class=\"fa fa-close\"></i> 关闭'];\r\n\t\t\tvar options = {\r\n\t\t\t\ttitle: '选择部门',\r\n\t\t\t\twidth: \"380\",\r\n\t\t\t\turl: url,\r\n\t\t\t\tbtn: btn,\r\n\t\t\t\tbtn2: function(index, layero) {\r\n\t\t\t\t    $(\"#treeId\").val(\"\");\r\n\t\t\t\t    $(\"#treeName\").val(\"\");\r\n\t\t\t\t    $.modal.close(index);\r\n\t\t\t\t},\r\n\t\t\t\tcallBack: doSubmit\r\n\t\t\t};\r\n\t\t\t$.modal.openOptions(options);\r\n\t\t}\r\n\t\t\r\n\t\tfunction doSubmit(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#treeId\").val(body.find('#treeId').val());\r\n   \t\t\t$(\"#treeName\").val(body.find('#treeName').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n\r\n\t\t$(function() {\r\n            $('#post').select2({\r\n                placeholder: \"请选择岗位\",\r\n                allowClear: true\r\n            });\r\n        })\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/authRole.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('用户分配角色')\" />\r\n</head>\r\n<body>\r\n    <div class=\"main-content\">\r\n        <form id=\"form-user-add\" class=\"form-horizontal\">\r\n            <input type=\"hidden\" id=\"userId\" name=\"userId\" th:value=\"${user.userId}\">\r\n            <h4 class=\"form-header h4\">基本信息</h4>\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">用户名称：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"userName\" class=\"form-control\" type=\"text\" disabled th:value=\"${user.userName}\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">登录账号：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"loginName\" class=\"form-control\" type=\"text\" disabled th:value=\"${user.loginName}\">\r\n                        </div>\r\n                    </div>\r\n                </div> \r\n            </div>\r\n           \r\n            <h4 class=\"form-header h4\">分配角色</h4>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t\t\t</div>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n      \r\n    <div class=\"row\">\r\n        <div class=\"col-sm-offset-5 col-sm-10\">\r\n            <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submitHandler()\"><i class=\"fa fa-check\"></i>保 存</button>&nbsp;\r\n            <button type=\"button\" class=\"btn btn-sm btn-danger\" onclick=\"closeItem()\"><i class=\"fa fa-reply-all\"></i>关 闭 </button>\r\n        </div>\r\n    </div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n\t    var prefix = ctx + \"system/user/authRole\";\r\n\t    var roles = [[${roles}]]\r\n\t    \r\n\t    $(function() {\r\n\t\t    var options = {\r\n\t\t        data: roles,\r\n\t\t        sidePagination: \"client\",\r\n\t\t        sortName: \"roleSort\",\r\n\t\t        showSearch: false,\r\n                showRefresh: false,\r\n                showToggle: false,\r\n                showColumns: false,\r\n                clickToSelect: true,\r\n                maintainSelected: true,\r\n\t\t        columns: [{\r\n\t\t            checkbox: true,\r\n\t\t            formatter:function (value, row, index) {\r\n\t\t                var state = row.status == '1' ? true : false;\r\n\t\t                if ($.common.isEmpty(value)) {\r\n\t\t                    return { checked: row.flag, disabled: state };\r\n\t\t                } else {\r\n\t\t                    return { checked: value, disabled: state };\r\n\t\t                }\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'roleId',\r\n\t\t            title: '角色编号'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'roleSort',\r\n\t\t            title: '排序',\r\n\t\t            sortable: true,\r\n\t\t            visible: false\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'roleName',\r\n\t\t            title: '角色名称'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'roleKey',\r\n\t\t            title: '权限字符',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t    \r\n\t    /* 添加角色-提交 */\r\n        function submitHandler(index, layero){\r\n            var roleIds = [];\r\n        \tvar data = $('#bootstrap-table').bootstrapTable('getData');\r\n        \tfor (var i = 0; i < data.length; i++) {\r\n        \t\tif (data[i][0] || ($.common.isEmpty(data[i][0]) && data[i].flag)) {\r\n        \t\t    roleIds.push(data[i].roleId)\r\n        \t\t}\r\n\t\t\t}\r\n        \t$.operate.saveTab(prefix + \"/insertAuthRole\", { \"userId\": $(\"#userId\").val(), \"roleIds\": roleIds.join() });\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/deptTree.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\n<head>\n\t<th:block th:include=\"include :: header('部门树选择')\" />\n\t<th:block th:include=\"include :: ztree-css\" />\n</head>\n<style>\n\tbody{height:auto;font-family: \"Microsoft YaHei\";}\n\tbutton{font-family: \"SimSun\",\"Helvetica Neue\",Helvetica,Arial;}\n</style>\n<body class=\"hold-transition box box-main\">\n\t<input id=\"treeId\"   name=\"treeId\"    type=\"hidden\" th:value=\"${dept.deptId}\"/>\n\t<input id=\"treeName\" name=\"treeName\"  type=\"hidden\" th:value=\"${dept.deptName}\"/>\n\t<div class=\"wrapper\"><div class=\"treeShowHideButton\" onclick=\"$.tree.toggleSearch();\">\n\t\t<label id=\"btnShow\" title=\"显示搜索\" style=\"display:none;\">︾</label>\n\t\t<label id=\"btnHide\" title=\"隐藏搜索\">︽</label>\n\t</div>\n\t<div class=\"treeSearchInput\" id=\"search\">\n\t\t<label for=\"keyword\">关键字：</label><input type=\"text\" class=\"empty\" id=\"keyword\" maxlength=\"50\">\n\t\t<button class=\"btn\" id=\"btn\" onclick=\"$.tree.searchNode()\"> 搜索 </button>\n\t</div>\n\t<div class=\"treeExpandCollapse\">\n\t\t<a href=\"javascript:;\" onclick=\"$.tree.expand()\">展开</a> /\n\t\t<a href=\"javascript:;\" onclick=\"$.tree.collapse()\">折叠</a>\n\t</div>\n\t<div id=\"tree\" class=\"ztree treeselect\"></div>\n\t</div>\n\t<th:block th:include=\"include :: footer\" />\n\t<th:block th:include=\"include :: ztree-js\" />\n\t<script th:inline=\"javascript\">\n\t    var prefix = ctx + \"system/user\"\n\t    var deptId = [[${deptId}]];\n\t\t$(function() {\n\t\t\tvar url = prefix + \"/deptTreeData\";\n\t\t\tvar options = {\n\t\t        url: url,\n\t\t        expandLevel: 2,\n\t\t        onClick : zOnClick\n\t\t    };\n\t\t\t$.tree.init(options);\n\t\t});\n\t\t\n\t\tfunction zOnClick(event, treeId, treeNode) {\n\t\t    var treeId = treeNode.id;\n\t\t    var treeName = treeNode.name;\n\t\t    $(\"#treeId\").val(treeId);\n\t\t    $(\"#treeName\").val(treeName);\n\t\t}\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改用户')\" />\r\n\t<th:block th:include=\"include :: select2-css\" />\r\n</head>\r\n<body>\r\n    <div class=\"main-content\">\r\n        <form class=\"form-horizontal\" id=\"form-user-edit\" th:object=\"${user}\">\r\n            <input name=\"userId\"  type=\"hidden\"  th:field=\"*{userId}\" />\r\n\t\t\t<input name=\"deptId\"  type=\"hidden\"  th:field=\"*{deptId}\" id=\"treeId\"/>\r\n            <h4 class=\"form-header h4\">基本信息</h4>\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">用户名称：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input name=\"userName\" placeholder=\"请输入用户名称\" class=\"form-control\" type=\"text\" maxlength=\"30\" th:field=\"*{userName}\" required>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">归属部门：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                                <input class=\"form-control\" type=\"text\" name=\"deptName\" onclick=\"selectDeptTree()\" id=\"treeName\" th:field=\"*{dept.deptName}\">\r\n                            \t<span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">手机号码：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                                <input name=\"phonenumber\" placeholder=\"请输入手机号码\" class=\"form-control\" type=\"text\" maxlength=\"11\" th:field=\"*{phonenumber}\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-mobile\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">邮箱：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <div class=\"input-group\">\r\n                                <input name=\"email\" class=\"form-control email\" type=\"text\" maxlength=\"50\" placeholder=\"请输入邮箱\" th:field=\"*{email}\">\r\n                                <span class=\"input-group-addon\"><i class=\"fa fa-envelope\"></i></span>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label is-required\">登录账号：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <input class=\"form-control\" type=\"text\" readonly=\"true\" th:field=\"*{loginName}\"/>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">用户状态：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <label class=\"toggle-switch switch-solid\">\r\n\t                            <input type=\"checkbox\" id=\"status\" th:checked=\"${user.status == '0' ? true : false}\">\r\n\t                            <span></span>\r\n\t                        </label>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">岗位：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <select id=\"post\" class=\"form-control select2-multiple\" multiple>\r\n\t\t\t\t\t\t\t\t<option th:each=\"post:${posts}\" th:value=\"${post.postId}\" th:text=\"${post.postName}\" th:selected=\"${post.flag}\" th:disabled=\"${post.status == '1'}\"></option>\r\n\t\t\t\t\t\t\t</select>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n                <div class=\"col-sm-6\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-sm-4 control-label\">用户性别：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <select name=\"sex\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_user_sex')}\">\r\n\t\t\t\t                <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\" th:field=\"*{sex}\"></option>\r\n\t\t\t\t            </select>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"row\">\r\n            \t<div class=\"col-sm-12\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-xs-2 control-label\">角色：</label>\r\n                        <div class=\"col-xs-10\">\r\n                            <label th:each=\"role:${roles}\" class=\"check-box\">\r\n\t\t\t\t\t\t\t\t<input name=\"role\" type=\"checkbox\" th:value=\"${role.roleId}\" th:text=\"${role.roleName}\" th:checked=\"${role.flag}\" th:disabled=\"${role.status == '1'}\">\r\n\t\t\t\t\t\t\t</label>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <h4 class=\"form-header h4\">其他信息</h4>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <div class=\"form-group\">\r\n                        <label class=\"col-xs-2 control-label\">备注：</label>\r\n                        <div class=\"col-xs-10\">\r\n                            <textarea name=\"remark\" maxlength=\"500\" class=\"form-control\" rows=\"3\">[[*{remark}]]</textarea>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n    <div class=\"row\">\r\n        <div class=\"col-sm-offset-5 col-sm-10\">\r\n            <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submitHandler()\"><i class=\"fa fa-check\"></i>保 存</button>&nbsp;\r\n            <button type=\"button\" class=\"btn btn-sm btn-danger\" onclick=\"closeItem()\"><i class=\"fa fa-reply-all\"></i>关 闭 </button>\r\n        </div>\r\n    </div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: select2-js\" />\r\n\t<script type=\"text/javascript\">\r\n        var prefix = ctx + \"system/user\";\r\n        \r\n        $(\"#form-user-edit\").validate({\r\n        \tonkeyup: false,\r\n        \trules:{\r\n        \t\temail:{\r\n                    email:true,\r\n                    remote: {\r\n                        url: prefix + \"/checkEmailUnique\",\r\n                        type: \"post\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                        \t\"userId\": function() {\r\n                                return $(\"#userId\").val();\r\n                            },\r\n                \t\t\t\"email\": function() {\r\n                                return $.common.trim($(\"#email\").val());\r\n                            }\r\n                        }\r\n                    }\r\n        \t\t},\r\n        \t\tphonenumber:{\r\n        \t\t\tisPhone:true,\r\n                    remote: {\r\n                        url: prefix + \"/checkPhoneUnique\",\r\n                        type: \"post\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                        \t\"userId\": function() {\r\n                        \t\treturn $(\"#userId\").val();\r\n                            },\r\n                \t\t\t\"phonenumber\": function() {\r\n                                return $.common.trim($(\"#phonenumber\").val());\r\n                            }\r\n                        }\r\n                    }\r\n        \t\t},\r\n        \t},\r\n        \tmessages: {\r\n        \t\t\"email\": {\r\n                    remote: \"Email已经存在\"\r\n                },\r\n        \t\t\"phonenumber\":{\r\n                \tremote: \"手机号码已经存在\"\r\n        \t\t}\r\n            },\r\n            focusCleanup: true\r\n        });\r\n        \r\n        function submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \tvar data = $(\"#form-user-edit\").serializeArray();\r\n\t        \tvar status = $(\"input[id='status']\").is(':checked') == true ? 0 : 1;\r\n\t        \tvar roleIds = $.form.selectCheckeds(\"role\");\r\n\t        \tvar postIds = $.form.selectSelects(\"post\");\r\n\t        \tdata.push({\"name\": \"status\", \"value\": status});\r\n\t        \tdata.push({\"name\": \"roleIds\", \"value\": roleIds});\r\n\t        \tdata.push({\"name\": \"postIds\", \"value\": postIds});\r\n\t        \t$.operate.saveTab(prefix + \"/edit\", data);\r\n\t        }\r\n\t    }\r\n\r\n        /* 用户管理-修改-选择部门树 */\r\n        function selectDeptTree() {\r\n        \tvar deptId = $.common.isEmpty($(\"#treeId\").val()) ? \"100\" : $(\"#treeId\").val();\r\n            var url = ctx + \"system/user/selectDeptTree/\" + deptId;\r\n            var btn = ['<i class=\"fa fa-check\"></i> 确认', '<i class=\"fa fa-trash-o\"></i> 清除', '<i class=\"fa fa-close\"></i> 关闭'];\r\n\t\t    var options = {\r\n\t\t\t\ttitle: '选择部门',\r\n\t\t\t\twidth: \"380\",\r\n\t\t\t\turl: url,\r\n\t\t\t\tbtn: btn,\r\n\t\t\t\tbtn2: function(index, layero) {\r\n\t\t\t\t    $(\"#treeId\").val(\"\");\r\n\t\t\t\t    $(\"#treeName\").val(\"\");\r\n\t\t\t\t    $.modal.close(index);\r\n\t\t\t\t},\r\n\t\t\t\tcallBack: doSubmit\r\n\t\t\t};\r\n\t\t\t$.modal.openOptions(options);\r\n\t\t}\r\n\t\t\r\n\t\tfunction doSubmit(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#treeId\").val(body.find('#treeId').val());\r\n   \t\t\t$(\"#treeName\").val(body.find('#treeName').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n\r\n\t\t$(function() {\r\n            $('#post').select2({\r\n                placeholder: \"请选择岗位\",\r\n                allowClear: true\r\n            });\r\n        })\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/profile/avatar.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改用户头像')\" />\r\n\t<th:block th:include=\"include :: cropper-css\" />\r\n\t<style type='text/css'>\r\n\t/* avator css start */\r\n\t.container {\r\n\t\tmargin: 10px 5px 5px 5px;\r\n\t}\r\n\t\r\n\t.action {\r\n\t\tpadding: 5px 0px;\r\n\t}\r\n\t\r\n\t.cropped {\r\n\t\twidth: 200px;\r\n\t\tborder: 1px #ddd solid;\r\n\t\tbox-shadow: 0px 0px 12px #ddd;\r\n\t}\r\n\t\r\n\t.img-preview {\r\n\t\tborder-radius: 50%;\r\n\t\tbox-shadow: 0px 0px 12px #7e7e7e;\r\n\t\tdisplay: inline-block;\r\n\t}\r\n\t\r\n\t.preview-box {\r\n\t\ttext-align: center;\r\n\t\tmargin: 0px auto;\r\n\t\tmargin-top: 10px;\r\n\t\tcolor: #bbb;\r\n\t}\r\n\t\r\n\t.preview-md {\r\n\t\twidth: 128px;\r\n\t\theight: 128px;\r\n\t}\r\n\t\r\n\t.preview-sm {\r\n\t\twidth: 96px;\r\n\t\theight: 96px;\r\n\t}\r\n\t\r\n\t.preview-xs {\r\n\t\twidth: 64px;\r\n\t\theight: 64px;\r\n\t}\r\n\t\r\n\t.imageBox {\r\n\t\tborder: 1px solid #aaa;\r\n\t\toverflow: hidden;\r\n\t\tcursor: move;\r\n\t\tbox-shadow: 4px 4px 12px #B0B0B0;\r\n\t\tmargin: 0px auto;\r\n\t}\r\n\t\r\n\t.btn-custom {\r\n\t\tfloat: right;\r\n\t\twidth: 46px;\r\n\t\tdisplay: inline-block;\r\n\t\tmargin-bottom: 10px;\r\n\t\theight: 37px;\r\n\t\tline-height: 37px;\r\n\t\tfont-size: 14px;\r\n\t\tcolor: #FFFFFF;\r\n\t\tmargin: 0px 2px;\r\n\t\tbackground-color: #f38e81;\r\n\t\tborder-radius: 3px;\r\n\t\ttext-decoration: none;\r\n\t\tcursor: pointer;\r\n\t\tbox-shadow: 0px 0px 5px #B0B0B0;\r\n\t\tborder: 0px #fff solid;\r\n\t}\r\n    /*选择文件上传*/\r\n\t.new-contentarea {\r\n\t\twidth: 165px;\r\n\t\toverflow: hidden;\r\n\t\tmargin: 0 auto;\r\n\t\tposition: relative;\r\n\t\tfloat: left;\r\n\t}\r\n\t\r\n\t.new-contentarea label {\r\n\t\twidth: 100%;\r\n\t\theight: 100%;\r\n\t\tdisplay: block;\r\n\t}\r\n\t\r\n\t.new-contentarea input[type=file] {\r\n\t\twidth: 188px;\r\n\t\theight: 60px;\r\n\t\tbackground: #333;\r\n\t\tmargin: 0 auto;\r\n\t\tposition: absolute;\r\n\t\tright: 50%;\r\n\t\tmargin-right: -94px;\r\n\t\ttop: 0;\r\n\t\tright/*\\**/: 0px\\9;\r\n\t\tmargin-right/*\\**/: 0px\\9;\r\n\t\twidth/*\\**/: 10px\\9;\r\n\t\topacity: 0;\r\n\t\tfilter: alpha(opacity=0);\r\n\t\tz-index: 2;\r\n\t}\r\n\t\r\n\ta.upload-img {\r\n\t\twidth: 165px;\r\n\t\tdisplay: inline-block;\r\n\t\tmargin-bottom: 10px;\r\n\t\theight: 37px;\r\n\t\tline-height: 37px;\r\n\t\tfont-size: 14px;\r\n\t\tcolor: #FFFFFF;\r\n\t\tbackground-color: #f38e81;\r\n\t\tborder-radius: 3px;\r\n\t\ttext-decoration: none;\r\n\t\tcursor: pointer;\r\n\t\tborder: 0px #fff solid;\r\n\t\tbox-shadow: 0px 0px 5px #B0B0B0;\r\n\t}\r\n\t\r\n\ta.upload-img:hover {\r\n\t\tbackground-color: #ec7e70;\r\n\t}\r\n\t\r\n\t.tc {\r\n\t\ttext-align: center;\r\n\t}\r\n    /* avator css end */\r\n\t</style>\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"row container\">\r\n\t\t<div class=\"col-md-10\">\r\n\t\t\t<div class=\"imageBox\">\r\n\t\t\t\t<img id=\"avatar\" th:src=\"(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}\" th:onerror=\"'this.src=\\'' + @{'/img/profile.jpg'} + '\\''\">\r\n\t\t\t</div>\r\n\t\t\t<div class=\"action\">\r\n\t\t\t\t<div class=\"new-contentarea tc\">\r\n\t\t\t\t\t<a href=\"javascript:void(0)\" class=\"upload-img\"><label for=\"inputImage\">上传图像</label> </a>\r\n\t\t\t\t\t<input type=\"file\" name=\"avatar\" id=\"inputImage\" accept=\"image/*\"/>\r\n\t\t\t\t</div>\r\n\t\t\t\t<button type=\"button\" class=\"btn-custom\" data-method=\"zoom\" data-option=\"0.1\"><i class=\"fa fa-search-plus\"></i></button>\r\n\t\t\t\t<button type=\"button\" class=\"btn-custom\" data-method=\"zoom\" data-option=\"-0.1\"><i class=\"fa fa-search-minus\"></i></button>\r\n\t\t\t\t<button type=\"button\" class=\"btn-custom\" data-method=\"rotate\" data-option=\"-45\"><i class=\"fa fa-rotate-left\"></i></button>\r\n\t\t\t\t<button type=\"button\" class=\"btn-custom\" data-method=\"rotate\" data-option=\"45\"><i class=\"fa fa-rotate-right\"></i></button>\r\n\t\t\t\t<button type=\"button\" class=\"btn-custom\" data-method=\"scaleX\" data-option=\"-1\"><i class=\"fa fa-arrows-h\"></i></button>\r\n\t\t\t\t<button type=\"button\" class=\"btn-custom\" data-method=\"scaleY\" data-option=\"-1\"><i class=\"fa fa-arrows-v\"></i></button>\r\n\t\t\t\t<button type=\"button\" class=\"btn-custom\" data-method=\"reset\"><i class=\"fa fa-refresh\"></i></button>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t\t<div class=\"col-md-2\">\r\n\t\t\t<div class=\"cropped\">\r\n\t\t\t\t<div class=\"preview-box\">\r\n\t\t\t\t\t<div class=\"img-preview preview-xs\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"preview-box\">\r\n\t\t\t\t\t<div class=\"img-preview preview-sm\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"preview-box\">\r\n\t\t\t\t\t<div class=\"img-preview preview-md\"></div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n<th:block th:include=\"include :: footer\" />\r\n<th:block th:include=\"include :: cropper-js\" />\r\n<script type=\"text/javascript\">\r\nvar cropper;\r\nvar croppable = false;\r\n$(window).on('load', function() {\r\n\tvar image = document.getElementById('avatar');\r\n\tcropper = new Cropper(image, {\r\n\t\taspectRatio: 1,\r\n\t\tviewMode: 1,\r\n\t\tautoCropArea: 0.9,\r\n\t\tpreview: '.img-preview',\r\n\t\tready: function () {\r\n\t\t\tcroppable = true;\r\n\t\t}\r\n\t})\r\n\r\n\t$('#inputImage').on('change', function() {\r\n\t\tvar reader = new FileReader();\r\n\t\tvar file = $('#inputImage')[0].files[0];\r\n\t\tif (/^image\\/\\w+$/.test(file.type)) {\r\n\t\t\treader.onload = function(e) {\r\n\t\t\t\tif(croppable){\r\n\t\t\t\t\tcropper.replace(e.target.result)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treader.readAsDataURL(this.files[0]);\r\n\t\t} else {\r\n\t\t\t$.modal.alertWarning('请选择一个图片文件。');\r\n\t\t}\r\n\t});\r\n\r\n\t$('.btn-custom').on('click',function (e) {\r\n\t\tif (!croppable) {\r\n\t\t\t$.modal.alertWarning(\"裁剪框加载中,请稍候...\");\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tvar data = {\r\n\t\t\tmethod: $(this).data('method'),\r\n\t\t\toption: $(this).data('option') || undefined,\r\n\t\t};\r\n\t\tvar result = cropper[data.method](data.option, data.secondOption);\r\n\t\tif(['scaleX','scaleY'].indexOf(data.method) !== -1){\r\n\t\t\t$(this).data('option', -data.option)\r\n\t\t}\r\n\t})\r\n});\r\n\r\nfunction submitHandler() {\r\n    if (!croppable) {\r\n        $.modal.alertWarning(\"裁剪框加载中,请稍候...\");\r\n        return\r\n    }\r\n    cropper.getCroppedCanvas().toBlob(function(img) {\r\n        var formdata = new FormData();\r\n        formdata.append(\"avatarfile\", img);\r\n        $.ajax({\r\n            url: ctx + \"system/user/profile/updateAvatar\",\r\n            data: formdata,\r\n            type: \"post\",\r\n            processData: false,\r\n            contentType: false,\r\n            success: function(result) {\r\n                $.operate.saveReload(result);\r\n            }\r\n        })\r\n    });\r\n}\r\n\r\n$(window).resize(function() {\r\n    $('.imageBox').height($(window).height() - 80);\r\n    $('.cropped').height($(window).height() - 40);\r\n}).resize();\r\n\r\nif (!HTMLCanvasElement.prototype.toBlob) {\r\n    Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {\r\n        value: function(callback, type, quality) {\r\n            var canvas = this;\r\n            setTimeout(function() {\r\n                var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]);\r\n                var len = binStr.length;\r\n                var arr = new Uint8Array(len);\r\n                for (var i = 0; i < len; i++) {\r\n                    arr[i] = binStr.charCodeAt(i);\r\n                }\r\n                callback(new Blob([arr], {\r\n                    type: type || 'image/png'\r\n                }));\r\n            });\r\n        }\r\n    });\r\n}\r\n</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/profile/profile.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('用户个人信息')\" />\r\n    <style type=\"text/css\">.user-info-head{position:relative;display:inline-block;}.user-info-head:hover:after{content:'\\f030';position:absolute;left:0;right:0;top:0;bottom:0;color:#eee;background:rgba(0,0,0,0.5);font-family:FontAwesome;font-size:24px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;cursor:pointer;line-height:110px;border-radius:50%;}</style>\r\n</head>\r\n\r\n<body class=\"gray-bg\" style=\"font: 14px Helvetica Neue, Helvetica, PingFang SC, 微软雅黑, Tahoma, Arial, sans-serif !important;\">\r\n    <input id=\"userId\" name=\"userId\" type=\"hidden\" th:value=\"${user.userId}\" />\r\n    <section class=\"section-content\">\r\n    <div class=\"row\">\r\n        <div class=\"col-sm-3 pr5\">\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title ibox-title-gray dashboard-header gray-bg\">\r\n                    <h5>个人资料</h5>\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <div class=\"text-center\">\r\n                        <p class=\"user-info-head\" onclick=\"avatar()\"><img class=\"img-circle img-lg\" th:src=\"(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}\" th:onerror=\"'this.src=\\'' + @{'/img/profile.jpg'} + '\\''\"></p>\r\n                        <p><a href=\"javascript:avatar()\">修改头像</a></p>\r\n                    </div>\r\n                    <ul class=\"list-group list-group-striped\">\r\n                        <li class=\"list-group-item\"><i class=\"fa fa-user\"></i>\r\n                            <b class=\"font-noraml\">登录名称：</b>\r\n                            <p class=\"pull-right\">[[${user.loginName}]]</p>\r\n                        </li>\r\n                        <li class=\"list-group-item\"><i class=\"fa fa-phone\"></i>\r\n                            <b  class=\"font-noraml\">手机号码：</b>\r\n                            <p class=\"pull-right\">[[${user.phonenumber}]]</p>\r\n                        </li>\r\n                        <li class=\"list-group-item\" th:if=\"${user.dept?.deptName != null}\"><i class=\"fa fa-group\"></i>\r\n                            <b  class=\"font-noraml\">所属部门：</b>\r\n                            <p class=\"pull-right\" style=\"overflow: hidden; white-space: nowrap; text-overflow: ellipsis;width:120px;\">[[${user.dept?.deptName}]] / [[${#strings.defaultString(postGroup,'无岗位')}]]</p>\r\n                        </li>\r\n                        <li class=\"list-group-item\"><i class=\"fa fa-envelope-o\"></i>\r\n                            <b  class=\"font-noraml\">邮箱地址：</b>\r\n                            <p class=\"pull-right\" th:title=\"${user.email}\">[[${#strings.abbreviate(user.email, 16)}]]</p>\r\n                        </li>\r\n                        <li class=\"list-group-item\"><i class=\"fa fa-calendar\"></i>\r\n                            <b  class=\"font-noraml\">创建时间：</b>\r\n                            <p class=\"pull-right\">[[${#dates.format(user.createTime, 'yyyy-MM-dd')}]]</p>\r\n                        </li>\r\n                    </ul>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        \r\n        <div class=\"col-sm-9 about\">\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-title ibox-title-gray dashboard-header\">\r\n                    <h5>基本资料</h5>\r\n                </div>\r\n                <div class=\"ibox-content\">\r\n                    <div class=\"nav-tabs-custom\">\r\n                        <ul class=\"nav nav-tabs\">\r\n                            <li class=\"active\"><a href=\"#user_info\" data-toggle=\"tab\" aria-expanded=\"true\">基本资料</a></li>\r\n                            <li><a href=\"#modify_password\" data-toggle=\"tab\" aria-expanded=\"false\">修改密码</a></li>\r\n                        </ul>\r\n                        <div class=\"tab-content\">\r\n                            <!--用户信息-->\r\n                            <div class=\"tab-pane active\" id=\"user_info\" th:object=\"${user}\">\r\n                                <form class=\"form-horizontal\" id=\"form-user-edit\">\r\n                                    <!--隐藏ID-->\r\n                                    <input name=\"id\" id=\"id\" type=\"hidden\">\r\n                                    <div class=\"form-group\">\r\n                                        <label class=\"col-sm-2 control-label\">用户名称：</label>\r\n                                        <div class=\"col-sm-10\">\r\n                                            <input type=\"text\" class=\"form-control\" name=\"userName\" th:field=\"*{userName}\" placeholder=\"请输入用户名称\">\r\n                                        </div>\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <label class=\"col-sm-2 control-label\">手机号码：</label>\r\n                                        <div class=\"col-sm-10\">\r\n                                            <input type=\"text\" class=\"form-control\" name=\"phonenumber\" maxlength=\"11\" th:field=\"*{phonenumber}\" placeholder=\"请输入手机号码\">\r\n                                        </div>\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <label class=\"col-sm-2 control-label\">邮箱：</label>\r\n                                        <div class=\"col-sm-10\">\r\n                                            <input type=\"text\" maxlength=\"50\" class=\"form-control\" name=\"email\" th:field=\"*{email}\" placeholder=\"请输入邮箱\">\r\n                                        </div>\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <label class=\"col-sm-2 control-label\">性别：</label>\r\n                                        <div class=\"col-sm-10\">\r\n                                            <div class=\"radio-box\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<input type=\"radio\" id=\"radio1\" th:field=\"*{sex}\" name=\"sex\" value=\"0\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"radio1\">男</label>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"radio-box\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<input type=\"radio\" id=\"radio2\" th:field=\"*{sex}\" name=\"sex\" value=\"1\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"radio2\">女</label>\r\n\t\t\t\t\t\t\t\t\t\t\t</div>\r\n                                        </div>\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <div class=\"col-sm-offset-2 col-sm-10\">\r\n                                            <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submitUserInfo()\"><i class=\"fa fa-check\"></i>保 存</button>&nbsp;\r\n                                            <button type=\"button\" class=\"btn btn-sm btn-danger\" onclick=\"closeItem()\"><i class=\"fa fa-reply-all\"></i>关 闭 </button>\r\n                                        </div>\r\n                                    </div>\r\n                                </form>\r\n                            </div>\r\n                            \r\n                            <!--修改密码-->\r\n                            <div class=\"tab-pane\" id=\"modify_password\">\r\n                                <form class=\"form-horizontal\" id=\"form-user-resetPwd\">\r\n                                    <div class=\"form-group\">\r\n                                        <label class=\"col-sm-2 control-label\">旧密码：</label>\r\n                                        <div class=\"col-sm-10\">\r\n                                            <input type=\"password\" class=\"form-control\" name=\"oldPassword\" placeholder=\"请输入旧密码\">\r\n                                        </div>\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <label class=\"col-sm-2 control-label\">新密码：</label>\r\n                                        <div class=\"col-sm-10\">\r\n                                            <input type=\"password\" class=\"form-control\" name=\"newPassword\" id=\"newPassword\" placeholder=\"请输入新密码\">\r\n                                            <th:block th:with=\"chrtype=${@config.getKey('sys.account.chrtype')}\"> \r\n\t\t\t\t\t\t                        <th:block th:if=\"${chrtype != '0'}\">\r\n\t\t\t\t\t\t                            <span class=\"help-block m-b-none\">\r\n\t\t\t\t\t\t\t\t                        <th:block th:if=\"${chrtype == '1'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码只能为0-9数字 </th:block>\r\n\t\t\t\t\t\t\t\t                        <th:block th:if=\"${chrtype == '2'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码只能为a-z和A-Z字母</th:block>\r\n\t\t\t\t\t\t\t\t                        <th:block th:if=\"${chrtype == '3'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码必须包含（字母，数字）</th:block>\r\n\t\t\t\t\t\t\t\t                        <th:block th:if=\"${chrtype == '4'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码必须包含（字母，数字，特殊字符!@#$%^&*()-=_+）</th:block>\r\n\t\t\t\t\t\t                            </span>\r\n                                                </th:block>\r\n\t\t\t\t\t\t                    </th:block>\r\n                                        </div>\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <label class=\"col-sm-2 control-label\">确认密码：</label>\r\n                                        <div class=\"col-sm-10\">\r\n                                            <input type=\"password\" class=\"form-control\" name=\"confirmPassword\" placeholder=\"请确认密码\">\r\n                                        </div>\r\n                                    </div>\r\n                                    <div class=\"form-group\">\r\n                                        <div class=\"col-sm-offset-2 col-sm-10\">\r\n                                            <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submitChangPassword()\"><i class=\"fa fa-check\"></i>保 存</button>&nbsp;\r\n                                            <button type=\"button\" class=\"btn btn-sm btn-danger\" onclick=\"closeItem()\"><i class=\"fa fa-reply-all\"></i>关 闭 </button>\r\n                                        </div>\r\n                                    </div>\r\n                                </form>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n\t</section>\r\n    \r\n    <th:block th:include=\"include :: footer\" />\r\n    <script>\r\n\t    /*用户管理-头像*/\r\n\t    function avatar() {\r\n\t        var url = ctx + 'system/user/profile/avatar';\r\n\t        top.layer.open({\r\n        \t\ttype: 2,\r\n        \t\tarea: [$(window).width() + 'px', $(window).height() + 'px'],\r\n        \t\tfix: false,\r\n        \t\t//不固定\r\n        \t\tmaxmin: true,\r\n        \t\tshade: 0.3,\r\n        \t\ttitle: \"修改头像\",\r\n        \t\tcontent: url,\r\n        \t\tbtn: ['确定', '关闭'],\r\n        \t    // 弹层外区域关闭\r\n        \t\tshadeClose: true,\r\n        \t\tyes: function(index, layero) {\r\n                    var iframeWin = layero.find('iframe')[0];\r\n                    iframeWin.contentWindow.submitHandler(index, layero);\r\n                },\r\n        \t    cancel: function(index) {\r\n        \t        return true;\r\n        \t    }\r\n        \t});\r\n\t    }\r\n\r\n\t    /*用户信息-修改*/\r\n\t    $(\"#form-user-edit\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tuserName:{\r\n\t\t\t\t\trequired:true,\r\n\t\t\t\t},\r\n\t\t\t\temail:{\r\n\t\t\t\t\trequired:true,\r\n\t\t            email:true,\r\n\t\t            remote: {\r\n\t\t                url: ctx + \"system/user/checkEmailUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"userId\": function() {\r\n\t\t                        return $(\"#userId\").val();\r\n\t\t                    },\r\n\t\t        \t\t\t\"email\": function() {\r\n\t\t                        return $.common.trim($(\"#email\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t\tphonenumber:{\r\n\t\t\t\t\trequired:true,\r\n\t\t\t\t\tisPhone:true,\r\n\t\t            remote: {\r\n\t\t                url: ctx + \"system/user/checkPhoneUnique\",\r\n\t\t                type: \"post\",\r\n\t\t                dataType: \"json\",\r\n\t\t                data: {\r\n\t\t                \t\"userId\": function() {\r\n\t\t                \t\treturn $(\"#userId\").val();\r\n\t\t                    },\r\n\t\t        \t\t\t\"phonenumber\": function() {\r\n\t\t                        return $.common.trim($(\"#phonenumber\").val());\r\n\t\t                    }\r\n\t\t                }\r\n\t\t            }\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t\t\t\t\"userName\": {\r\n\t                required: \"请输入用户名称\",\r\n\t            },\r\n\t\t\t\t\"email\": {\r\n\t\t\t\t\trequired: \"请输入邮箱\",\r\n\t\t            remote: \"Email已经存在\"\r\n\t\t        },\r\n\t\t\t\t\"phonenumber\":{\r\n\t\t\t\t\trequired: \"请输入手机号码\",\r\n\t\t        \tremote: \"手机号码已经存在\"\r\n\t\t\t\t}\r\n\t\t    },\r\n\t\t    focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitUserInfo() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.saveModal(ctx + \"system/user/profile/update\", $('#form-user-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t    \r\n\t    /*用户管理-修改密码*/\r\n\t    $(\"#form-user-resetPwd\").validate({\r\n\t    \tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\toldPassword:{\r\n\t\t\t\t\trequired:true,\r\n\t\t\t\t\tremote: {\r\n\t                    url: ctx + \"system/user/profile/checkPassword\",\r\n\t                    type: \"get\",\r\n\t                    dataType: \"json\",\r\n\t                    data: {\r\n\t                        password: function() {\r\n\t                            return $(\"input[name='oldPassword']\").val();\r\n\t                        }\r\n\t                    }\r\n\t                }\r\n\t\t\t\t},\r\n\t\t\t\tnewPassword: {\r\n\t                required: true,\r\n\t                minlength: 6,\r\n\t                maxlength: 20,\r\n\t                specialSign: true\r\n\t            },\r\n\t            confirmPassword: {\r\n\t                required: true,\r\n\t                equalTo: \"#newPassword\"\r\n\t            }\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t            oldPassword: {\r\n\t                required: \"请输入原密码\",\r\n\t                remote: \"原密码错误\"\r\n\t            },\r\n\t            newPassword: {\r\n\t                required: \"请输入新密码\",\r\n\t                minlength: \"密码不能小于6个字符\",\r\n\t                maxlength: \"密码不能大于20个字符\"\r\n\t            },\r\n\t            confirmPassword: {\r\n\t                required: \"请再次输入新密码\",\r\n\t                equalTo: \"两次密码输入不一致\"\r\n\t            }\r\n\r\n\t        },\r\n\t        focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitChangPassword () {\r\n\t\t\tvar chrtype = [[${#strings.defaultString(@config.getKey('sys.account.chrtype'), 0)}]];\r\n\t\t\tvar password = $(\"#newPassword\").val();\r\n\t        if ($.validate.form(\"form-user-resetPwd\") && checkpwd(chrtype, password)) {\r\n\t        \t$.operate.saveModal(ctx + \"system/user/profile/resetPwd\", $('#form-user-resetPwd').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/profile/resetPwd.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n    <th:block th:include=\"include :: header('修改用户密码')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n        <form class=\"form-horizontal m\" id=\"form-user-resetPwd\">\r\n            <input name=\"userId\"  type=\"hidden\"  th:value=\"${user.userId}\" />\r\n            <div class=\"form-group\">\r\n                <label class=\"col-sm-3 control-label\">登录名称：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <input class=\"form-control\" type=\"text\" readonly=\"true\" name=\"loginName\" th:value=\"${user.loginName}\"/>\r\n                </div>\r\n            </div>\r\n            <div class=\"form-group\">\r\n                <label class=\"col-sm-3 control-label\">旧密码：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <input class=\"form-control\" type=\"password\" name=\"oldPassword\" id=\"oldPassword\">\r\n                </div>\r\n            </div>\r\n            <div class=\"form-group\">\r\n                <label class=\"col-sm-3 control-label\">新密码：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <input class=\"form-control\" type=\"password\" name=\"newPassword\" id=\"newPassword\">\r\n                    <th:block th:with=\"chrtype=${@config.getKey('sys.account.chrtype')}\"> \r\n                        <th:block th:if=\"${chrtype != '0'}\">\r\n                            <span class=\"help-block m-b-none\">\r\n                                <th:block th:if=\"${chrtype == '1'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码只能为0-9数字 </th:block>\r\n                                <th:block th:if=\"${chrtype == '2'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码只能为a-z和A-Z字母</th:block>\r\n                                <th:block th:if=\"${chrtype == '3'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码必须包含（字母，数字）</th:block>\r\n                                <th:block th:if=\"${chrtype == '4'}\"><i class=\"fa fa-info-circle\" style=\"color: red;\"></i>  密码必须包含（字母，数字，特殊字符!@#$%^&*()-=_+）</th:block>\r\n                            </span>\r\n                        </th:block>\r\n                    </th:block>\r\n                </div>\r\n            </div>\r\n            <div class=\"form-group\">\r\n                <label class=\"col-sm-3 control-label\">再次确认：</label>\r\n                <div class=\"col-sm-8\">\r\n                    <input class=\"form-control\" type=\"password\" name=\"confirmPassword\" id=\"confirmPassword\">\r\n                    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 请再次输入您的密码</span>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n\r\n    <script>\r\n        $(\"#form-user-resetPwd\").validate({\r\n            rules:{\r\n                oldPassword:{\r\n                    required:true,\r\n                    remote: {\r\n                        url: ctx + \"system/user/profile/checkPassword\",\r\n                        type: \"get\",\r\n                        dataType: \"json\",\r\n                        data: {\r\n                            password: function() {\r\n                                return $(\"input[name='oldPassword']\").val();\r\n                            }\r\n                        }\r\n                    }\r\n                },\r\n                newPassword: {\r\n                    required: true,\r\n                    minlength: 5,\r\n                    maxlength: 20,\r\n                    specialSign: true\r\n                },\r\n                confirmPassword: {\r\n                    required: true,\r\n                    equalTo: \"#newPassword\"\r\n                }\r\n            },\r\n            messages: {\r\n                oldPassword: {\r\n                    required: \"请输入原密码\",\r\n                    remote: \"原密码错误\"\r\n                },\r\n                newPassword: {\r\n                    required: \"请输入新密码\",\r\n                    minlength: \"密码不能小于5个字符\",\r\n                    maxlength: \"密码不能大于20个字符\"\r\n                },\r\n                confirmPassword: {\r\n                    required: \"请再次输入新密码\",\r\n                    equalTo: \"两次密码输入不一致\"\r\n                }\r\n\r\n            },\r\n            focusCleanup: true\r\n        });\r\n        \r\n        function submitHandler() {\r\n            var chrtype = [[${#strings.defaultString(@config.getKey('sys.account.chrtype'), 0)}]];\r\n            var password = $(\"#newPassword\").val();\r\n            if ($.validate.form() && checkpwd(chrtype, password)) {\r\n                $.operate.save(ctx + \"system/user/profile/resetPwd\", $('#form-user-resetPwd').serialize());\r\n            }\r\n        }\r\n    </script>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/resetPwd.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改密码')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-user-resetPwd\">\r\n\t\t\t<input name=\"userId\"  type=\"hidden\"  th:value=\"${user.userId}\" />\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">登录名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" readonly=\"true\" name=\"loginName\" th:value=\"${user.loginName}\"/>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">输入密码：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"input-group\">\r\n                        <input class=\"form-control\" type=\"password\" name=\"password\" id=\"password\" placeholder=\"请输入重置密码\" th:value=\"${@config.getKey('sys.user.initPassword')}\">\r\n                        <span class=\"input-group-addon\" title=\"重置密码,鼠标按下显示密码\"\r\n                            onmousedown=\"$('#password').attr('type','text')\"\r\n                            onmouseup=\"$('#password').attr('type','password')\"><i class=\"fa fa-key\"></i></span>\r\n                    </div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\t$(\"#form-user-resetPwd\").validate({\r\n\t\t\trules:{\r\n\t\t\t\tpassword:{\r\n\t\t\t\t\trequired: true,\r\n\t\t\t\t\tminlength: 5,\r\n\t\t\t\t\tmaxlength: 20,\r\n\t\t\t\t\tspecialSign: true\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tfocusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(ctx + \"system/user/resetPwd\", $('#form-user-resetPwd').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/user.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('用户列表')\" />\r\n\t<th:block th:include=\"include :: layout-latest-css\" />\r\n\t<th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"ui-layout-west\">\r\n\t\t<div class=\"box box-main\">\r\n\t\t\t<div class=\"box-header\">\r\n\t\t\t\t<div class=\"box-title\">\r\n\t\t\t\t\t<i class=\"fa fa-sitemap\"></i> 组织机构\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"box-tools pull-right\">\r\n\t\t\t\t    <a type=\"button\" class=\"btn btn-box-tool\" href=\"javascript:void(0)\" onclick=\"dept()\" title=\"管理部门\"><i class=\"fa fa-edit\"></i></a>\r\n\t\t\t\t\t<button type=\"button\" class=\"btn btn-box-tool\" id=\"btnExpand\" title=\"展开\" style=\"display:none;\"><i class=\"fa fa-chevron-up\"></i></button>\r\n\t\t\t\t\t<button type=\"button\" class=\"btn btn-box-tool\" id=\"btnCollapse\" title=\"折叠\"><i class=\"fa fa-chevron-down\"></i></button>\r\n\t\t\t\t\t<button type=\"button\" class=\"btn btn-box-tool\" id=\"btnRefresh\" title=\"刷新部门\"><i class=\"fa fa-refresh\"></i></button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"ui-layout-content\">\r\n\t\t\t\t<div id=\"tree\" class=\"ztree\"></div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t\r\n\t<div class=\"ui-layout-center\">\r\n\t\t<div class=\"container-div\">\r\n\t\t\t<div class=\"row\">\r\n\t\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t\t<form id=\"user-form\">\r\n\t\t\t\t\t\t<input type=\"hidden\" id=\"deptId\" name=\"deptId\">\r\n\t\t                <input type=\"hidden\" id=\"parentId\" name=\"parentId\">\r\n\t\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t\t登录名称：<input type=\"text\" name=\"loginName\"/>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t\t手机号码：<input type=\"text\" name=\"phonenumber\"/>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t\t用户状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_normal_disable')}\">\r\n\t\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<li class=\"select-time\">\r\n\t\t\t\t\t\t\t\t\t<label>创建时间： </label>\r\n\t\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[beginTime]\"/>\r\n\t\t\t\t\t\t\t\t\t<span>-</span>\r\n\t\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[endTime]\"/>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t    <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"resetPre()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</form>\r\n\t\t\t\t</div>\r\n\t\t\t\t\r\n\t\t        <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t        \t<a class=\"btn btn-success\" onclick=\"$.operate.addTab()\" shiro:hasPermission=\"system:user:add\">\r\n\t\t                <i class=\"fa fa-plus\"></i> 新增\r\n\t\t            </a>\r\n\t\t             <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.editTab()\" shiro:hasPermission=\"system:user:edit\">\r\n\t\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t\t        </a>\r\n\t\t            <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"system:user:remove\">\r\n\t\t                <i class=\"fa fa-remove\"></i> 删除\r\n\t\t            </a>\r\n\t\t            <a class=\"btn btn-info\" onclick=\"$.table.importExcel()\" shiro:hasPermission=\"system:user:import\">\r\n\t\t\t            <i class=\"fa fa-upload\"></i> 导入\r\n\t\t\t        </a>\r\n\t\t            <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"system:user:export\">\r\n\t\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t\t        </a>\r\n\t\t        </div>\r\n\t\t        \r\n\t\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<th:block th:include=\"include :: layout-latest-js\" />\r\n\t<th:block th:include=\"include :: ztree-js\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar editFlag = [[${@permission.hasPermi('system:user:edit')}]];\r\n\t\tvar removeFlag = [[${@permission.hasPermi('system:user:remove')}]];\r\n\t\tvar resetPwdFlag = [[${@permission.hasPermi('system:user:resetPwd')}]];\r\n\t\tvar prefix = ctx + \"system/user\";\r\n\r\n\t\t$(function() {\r\n\t\t    var panehHidden = false;\r\n\t\t    if ($(this).width() < 769) {\r\n\t\t        panehHidden = true;\r\n\t\t    }\r\n\t\t    $('body').layout({ initClosed: panehHidden, west__size: 185, resizeWithWindow: false });\r\n\t     \t// 回到顶部绑定\r\n\t    \tif ($.fn.toTop !== undefined) {\r\n\t    \t\tvar opt = {\r\n\t    \t\t\twin:$('.ui-layout-center'),\r\n\t    \t\t\tdoc:$('.ui-layout-center')\r\n\t    \t\t};\r\n\t    \t\t$('#scroll-up').toTop(opt);\r\n\t    \t}\r\n\t\t    queryUserList();\r\n\t\t    queryDeptTree();\r\n\t\t});\r\n\r\n\t\tfunction queryUserList() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        viewUrl: prefix + \"/view/{id}\",\r\n\t\t        createUrl: prefix + \"/add\",\r\n\t\t        updateUrl: prefix + \"/edit/{id}\",\r\n\t\t        removeUrl: prefix + \"/remove\",\r\n\t\t        exportUrl: prefix + \"/export\",\r\n\t\t        importUrl: prefix + \"/importData\",\r\n\t\t        importTemplateUrl: prefix + \"/importTemplate\",\r\n\t\t        sortName: \"createTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        modalName: \"用户\",\r\n\t\t        columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'userId',\r\n\t\t            title: '用户ID'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'loginName',\r\n\t\t            title: '登录名称',\r\n\t\t            sortable: true,\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t                return '<a href=\"javascript:void(0)\" onclick=\"$.operate.view(\\'' + row.userId + '\\')\">' + value + '</a>';\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'userName',\r\n\t\t            title: '用户名称'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'dept.deptName',\r\n\t\t            title: '部门'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'email',\r\n\t\t            title: '邮箱',\r\n\t\t            visible: false\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'phonenumber',\r\n\t\t            title: '手机'\r\n\t\t        },\r\n\t\t        {\r\n\t\t        \tvisible: editFlag == 'hidden' ? false : true,\r\n\t\t        \ttitle: '用户状态',\r\n\t\t        \talign: 'center',\r\n\t\t        \tformatter: function (value, row, index) {\r\n\t\t        \t\treturn statusTools(row);\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                if (row.userId != 1) {\r\n\t\t                \tvar actions = [];\r\n\t\t\t                actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.editTab(\\'' + row.userId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n\t\t\t                actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.userId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a> ');\r\n\t\t\t                var more = [];\r\n\t\t\t                more.push(\"<a class='btn btn-default btn-xs \" + resetPwdFlag + \"' href='javascript:void(0)' onclick='resetPwd(\" + row.userId + \")'><i class='fa fa-key'></i>重置密码</a> \");\r\n\t\t\t                more.push(\"<a class='btn btn-default btn-xs \" + editFlag + \"' href='javascript:void(0)' onclick='authRole(\" + row.userId + \")'><i class='fa fa-check-square-o'></i>分配角色</a>\");\r\n\t\t\t                actions.push('<a tabindex=\"0\" class=\"btn btn-info btn-xs\" role=\"button\" data-container=\"body\" data-placement=\"left\" data-toggle=\"popover\" data-html=\"true\" data-trigger=\"hover\" data-content=\"' + more.join('') + '\"><i class=\"fa fa-chevron-circle-right\"></i>更多操作</a>');\r\n\t\t\t                return actions.join('');\r\n\t\t            \t} else {\r\n\t\t                    return \"\";\r\n\t\t                }\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t}\r\n\t\t\r\n\t\tfunction queryDeptTree()\r\n\t\t{\r\n\t\t\tvar url = ctx + \"system/user/deptTreeData\";\r\n\t\t\tvar options = {\r\n\t\t        url: url,\r\n\t\t        expandLevel: 2,\r\n\t\t        onClick : zOnClick\r\n\t\t    };\r\n\t\t\t$.tree.init(options);\r\n\t\t\t\r\n\t\t\tfunction zOnClick(event, treeId, treeNode) {\r\n\t\t\t\t$(\"#deptId\").val(treeNode.id);\r\n\t\t\t\t$(\"#parentId\").val(treeNode.pId);\r\n\t\t\t\t$.table.search();\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t$('#btnExpand').click(function() {\r\n\t\t\t$._tree.expandAll(true);\r\n\t\t    $(this).hide();\r\n\t\t    $('#btnCollapse').show();\r\n\t\t});\r\n\t\t\r\n\t\t$('#btnCollapse').click(function() {\r\n\t\t\t$._tree.expandAll(false);\r\n\t\t    $(this).hide();\r\n\t\t    $('#btnExpand').show();\r\n\t\t});\r\n\t\t\r\n\t\t$('#btnRefresh').click(function() {\r\n\t\t\tqueryDeptTree();\r\n\t\t});\r\n\t\t\r\n\t\t/* 自定义重置-表单重置/隐藏框/树节点选择色/搜索 */\r\n\t\tfunction resetPre() {\r\n\t\t\tresetDate();\r\n\t\t\t$(\"#user-form\")[0].reset();\r\n\t\t\t$(\"#deptId\").val(\"\");\r\n\t\t\t$(\"#parentId\").val(\"\");\r\n\t\t\t$(\".curSelectedNode\").removeClass(\"curSelectedNode\");\r\n\t\t\t$.table.search();\r\n\t\t}\r\n\r\n\t\t/* 用户管理-部门 */\r\n\t\tfunction dept() {\r\n\t\t\tvar url = ctx + \"system/dept\";\r\n\t\t\t$.modal.openTab(\"部门管理\", url);\r\n\t\t}\r\n\r\n\t\t/* 用户管理-重置密码 */\r\n\t\tfunction resetPwd(userId) {\r\n\t\t    var url = prefix + '/resetPwd/' + userId;\r\n\t\t    $.modal.open(\"重置密码\", url, '800', '300');\r\n\t\t}\r\n\t\t\r\n\t\t/* 用户管理-分配角色 */\r\n\t\tfunction authRole(userId) {\r\n\t\t    var url = prefix + '/authRole/' + userId;\r\n\t\t    $.modal.openTab(\"用户分配角色\", url);\r\n\t\t}\r\n\t\t\r\n\t\t/* 用户状态显示 */\r\n\t\tfunction statusTools(row) {\r\n\t\t    if (row.status == 1) {\r\n    \t\t\treturn '<i class=\\\"fa fa-toggle-off text-info fa-2x\\\" onclick=\"enable(\\'' + row.userId + '\\')\"></i> ';\r\n    \t\t} else {\r\n    \t\t\treturn '<i class=\\\"fa fa-toggle-on text-info fa-2x\\\" onclick=\"disable(\\'' + row.userId + '\\')\"></i> ';\r\n    \t\t}\r\n\t\t}\r\n\t\t\r\n\t\t/* 用户管理-停用 */\r\n\t\tfunction disable(userId) {\r\n\t\t\t$.modal.confirm(\"确认要停用用户吗？\", function() {\r\n\t\t\t\t$.operate.post(prefix + \"/changeStatus\", { \"userId\": userId, \"status\": 1 });\r\n\t\t    })\r\n\t\t}\r\n\r\n\t\t/* 用户管理启用 */\r\n\t\tfunction enable(userId) {\r\n\t\t\t$.modal.confirm(\"确认要启用用户吗？\", function() {\r\n\t\t\t\t$.operate.post(prefix + \"/changeStatus\", { \"userId\": userId, \"status\": 0 });\r\n\t\t    })\r\n\t\t}\r\n\t</script>\r\n</body>\r\n<!-- 导入区域 -->\r\n<script id=\"importTpl\" type=\"text/template\">\r\n<form enctype=\"multipart/form-data\" class=\"mt20 mb10\">\r\n\t<div class=\"col-xs-offset-1\">\r\n\t\t<input type=\"file\" id=\"file\" name=\"file\"/>\r\n\t\t<div class=\"mt10 pt5\">\r\n\t\t\t<input type=\"checkbox\" id=\"updateSupport\" name=\"updateSupport\" title=\"如果登录账户已经存在，更新这条数据。\"> 是否更新已经存在的用户数据\r\n\t\t\t &nbsp;\t<a onclick=\"$.table.importTemplate()\" class=\"btn btn-default btn-xs\"><i class=\"fa fa-file-excel-o\"></i> 下载模板</a>\r\n\t\t</div>\r\n\t\t<font color=\"red\" class=\"pull-left mt10\">\r\n\t\t\t提示：仅允许导入“xls”或“xlsx”格式文件！\r\n\t\t</font>\r\n\t</div>\r\n</form>\r\n</script>\r\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/system/user/view.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\n<head>\n    <th:block th:include=\"include :: header('用户详细')\" />\n</head>\n<body>\n    <div class=\"main-content\">\n        <form class=\"form-horizontal\" th:object=\"${user}\">\n            <h4 class=\"form-header h4\">基本信息</h4>\n            <div class=\"row\">\n            \t<div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">用户名称：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{userName}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">归属部门：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{dept.deptName}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">手机号码：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{phonenumber}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">邮箱：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{email}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">登录账号：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{loginName}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">用户状态：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{status == '0' ? '正常' : '停用'}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">岗位：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\">[[${#strings.defaultString(postGroup, '无岗位')}]]</p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">用户性别：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{@dict.getLabel('sys_user_sex', sex)}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n            \t<div class=\"col-sm-12\">\n                    <div class=\"form-group\">\n                        <label class=\"col-xs-2 control-label\">角色：</label>\n                        <div class=\"col-xs-10\">\n                            <p class=\"form-control-plaintext\">[[${#strings.defaultString(roleGroup, '无角色')}]]</p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <h4 class=\"form-header h4\">其他信息</h4>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">创建者：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{createBy}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">创建时间：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{#dates.format(createTime, 'yyyy-MM-dd HH:mm:ss')}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">更新者：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{updateBy}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">更新时间：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{#dates.format(updateTime, 'yyyy-MM-dd HH:mm:ss')}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">最后登录IP：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{loginIp}\"></p>\n                        </div>\n                    </div>\n                </div>\n                <div class=\"col-sm-6\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-4 control-label\">最后登录时间：</label>\n                        <div class=\"col-sm-8\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{#dates.format(loginDate, 'yyyy-MM-dd HH:mm:ss')}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\t        <div class=\"row\">\n                <div class=\"col-sm-12\">\n                    <div class=\"form-group\">\n                        <label class=\"col-xs-2 control-label\">备注：</label>\n                        <div class=\"col-xs-10\">\n                            <p class=\"form-control-plaintext\" th:text=\"*{remark}\"></p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </form>\n    </div>\n\t<th:block th:include=\"include :: footer\" />\n</body>\n</html>"
  },
  {
    "path": "ruoyi-admin/src/main/resources/templates/tool/build/build.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('表单构建器')\" />\r\n\t<th:block th:include=\"include :: datetimepicker-css\" />\r\n</head>\r\n<style>\r\n    .droppable-active{background-color:#ffe!important}.tools a{cursor:pointer;font-size:80%}.form-body .col-md-6,.form-body .col-md-12{min-height:400px}.draggable{cursor:move}\r\n</style>\r\n<body class=\"gray-bg\">\r\n    <div class=\"wrapper wrapper-content\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-5\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>元素</h5>\r\n                        <div class=\"ibox-tools\">\r\n                            <a class=\"collapse-link\">\r\n                                <i class=\"fa fa-chevron-up\"></i>\r\n                            </a>\r\n                            <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"javascript:;\">\r\n                                <i class=\"fa fa-wrench\"></i>\r\n                            </a>\r\n                            <ul class=\"dropdown-menu dropdown-user\">\r\n                                <li><a href=\"javascript:;\">基本</a>\r\n                                </li>\r\n                                <li><a href=\"javascript:;\">其他</a>\r\n                                </li>\r\n                            </ul>\r\n                            <a class=\"close-link\">\r\n                                <i class=\"fa fa-times\"></i>\r\n                            </a>\r\n                        </div>\r\n                    </div>\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"alert alert-info\">\r\n                           \t 拖拽左侧的表单元素到右侧区域，即可生成相应的HTML代码，表单代码，轻松搞定！\r\n                        </div>\r\n                        <form role=\"form\" class=\"form-horizontal m-t\">\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">文本框：</label>\r\n                                <div class=\"col-sm-9\">\r\n                                    <input type=\"text\" name=\"\" class=\"form-control\" placeholder=\"请输入文本\">\r\n                                </div>\r\n                            </div>\r\n\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">多行文本框：</label>\r\n                                <div class=\"col-sm-9\">\r\n                                    <textarea type=\"text\" name=\"\" class=\"form-control\" placeholder=\"请输入文本\"></textarea>\r\n                                </div>\r\n                            </div>\r\n\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">密码框：</label>\r\n                                <div class=\"col-sm-9\">\r\n                                    <input type=\"password\" class=\"form-control\" name=\"password\" placeholder=\"请输入密码\">\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">下拉框：</label>\r\n                                <div class=\"col-sm-9\">\r\n                                    <select class=\"form-control\" name=\"\">\r\n                                        <option>选项 1</option>\r\n                                        <option>选项 2</option>\r\n                                        <option>选项 3</option>\r\n                                        <option>选项 4</option>\r\n                                    </select>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">纯文本：</label>\r\n\r\n                                <div class=\"col-sm-9\">\r\n                                    <p class=\"form-control-static\">这里是纯文字信息</p>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">单选框：\r\n                                </label>\r\n\r\n                                <div class=\"col-sm-9\">\r\n                                    <label class=\"radio-box\"><input type=\"radio\" checked=\"\" value=\"option1\" id=\"optionsRadios1\" name=\"optionsRadios\">选项1</label>\r\n                                    <label class=\"radio-box\"><input type=\"radio\" value=\"option2\" id=\"optionsRadios2\" name=\"optionsRadios\">选项2</label>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">复选框：</label>\r\n\r\n                                <div class=\"col-sm-9\">\r\n                                    <label class=\"check-box\">\r\n                                        <input type=\"checkbox\" value=\"option1\" id=\"inlineCheckbox1\">选项1</label>\r\n                                    <label class=\"check-box\">\r\n                                        <input type=\"checkbox\" value=\"option2\" id=\"inlineCheckbox2\">选项2</label>\r\n                                    <label class=\"check-box\">\r\n                                        <input type=\"checkbox\" value=\"option3\" id=\"inlineCheckbox3\">选项3</label>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">切换按钮：\r\n                                </label>\r\n\r\n                                <div class=\"col-sm-9\">\r\n                                    <label class=\"toggle-switch switch-solid\">\r\n\t\t\t                            <input type=\"checkbox\" id=\"status\" checked>\r\n\t\t\t                            <span></span>\r\n\t\t\t                        </label>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"form-group draggable\">\r\n                                <label class=\"col-sm-3 control-label\">日期选择：</label>\r\n\r\n                                <div class=\"col-sm-9\">\r\n\t\t                            <div class=\"input-group date\">\r\n\t\t                                <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n\t\t                                <input type=\"text\" class=\"form-control\" value=\"2018-04-20\">\r\n\t\t                            </div>\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"hr-line-dashed\"></div>\r\n                            <div class=\"form-group draggable\">\r\n                                <div class=\"col-sm-12 col-sm-offset-3\">\r\n\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\">提交</button>\r\n\t\t\t\t\t\t\t\t\t<button onclick=\"$.modal.close()\" class=\"btn btn-danger\" type=\"button\">关闭</button>\r\n                                </div>\r\n                            </div>\r\n                        </form>\r\n                        <div class=\"clearfix\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n            <div class=\"col-sm-7\">\r\n                <div class=\"ibox float-e-margins\">\r\n                    <div class=\"ibox-title\">\r\n                        <h5>拖拽左侧表单元素到此区域</h5>\r\n                        <div class=\"ibox-tools\">\r\n                           \t 请选择显示的列数：\r\n                            <select id=\"n-columns\">\r\n                                <option value=\"1\">显示1列</option>\r\n                                <option value=\"2\">显示2列</option>\r\n                            </select>\r\n                        </div>\r\n                    </div>\r\n\r\n                    <div class=\"ibox-content\">\r\n                        <div class=\"row form-body form-horizontal m-t\">\r\n                            <div class=\"col-md-12 droppable sortable\">\r\n                            </div>\r\n                            <div class=\"col-md-6 droppable sortable\" style=\"display: none;\">\r\n                            </div>\r\n                            <div class=\"col-md-6 droppable sortable\" style=\"display: none;\">\r\n                            </div>\r\n                        </div>\r\n                        <button type=\"submit\" class=\"btn btn-warning\" data-clipboard-text=\"testing\" id=\"copy-to-clipboard\">复制代码</button>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n   <th:block th:include=\"include :: footer\" />\r\n   <script th:src=\"@{/js/jquery-ui-1.10.4.min.js}\"></script>\r\n   <th:block th:include=\"include :: datetimepicker-js\" />\r\n   <script th:src=\"@{/ajax/libs/beautifyhtml/beautifyhtml.js}\"></script>\r\n   <script type=\"text/javascript\">\r\n       $(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('<label class=\"col-sm-3 control-label\">单选框：</label>'+'<div class=\"col-sm-9\">'+'<label class=\"radio-box\"><input type=\"radio\" checked=\"\" value=\"option1\" id=\"optionsRadios1\" name=\"optionsRadios\">选项1</label>'+'<label class=\"radio-box\"><input type=\"radio\" value=\"option2\" id=\"optionsRadios2\" name=\"optionsRadios\">选项2</label>'+\"</div>\")}else{if($el.find(\"label\").hasClass(\"check-box\")){$el=$el.html('<label class=\"col-sm-3 control-label\">复选框：</label>'+'<div class=\"col-sm-9\">'+'<label class=\"check-box\">'+'<input type=\"checkbox\" value=\"option1\" id=\"inlineCheckbox1\">选项1</label>'+'<label class=\"check-box\">'+'<input type=\"checkbox\" value=\"option2\" id=\"inlineCheckbox2\">选项2</label>'+'<label class=\"check-box\">'+'<input type=\"checkbox\" value=\"option3\" id=\"inlineCheckbox3\">选项3</label>'+\"</div>\")}}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)}$('<p class=\"tools col-sm-12 col-sm-offset-3\">\t\t\t\t\t\t<a class=\"edit-link\">编辑HTML<a> | \t\t\t\t\t\t<a class=\"remove-link\">移除</a></p>').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=$('<div class=\"modal\" style=\"overflow: auto;\" tabindex=\"-1\">\t<div class=\"modal-dialog\"><div class=\"modal-content\"><div class=\"modal-header\"><a type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">&times;</a><h4 class=\"modal-title\">编辑HTML</h4></div><div class=\"modal-body ui-front\">\t<textarea class=\"form-control textarea-show-src\"  style=\"min-height: 200px; margin-bottom: 10px;font-family: Monaco, Fixed\"></textarea><button class=\"btn btn-success\">更新HTML</button></div></div></div></div>').appendTo(document.body);var doms=document.getElementsByClassName(\"textarea-show-src\");for(var i=0;i<doms.length;i++){doms.item(i).innerHTML=content}return modal};$(document).on(\"click\",\".edit-link\",function(ev){var $el=$(this).parent().parent();var $el_copy=$el.clone();var $edit_btn=$el_copy.find(\".edit-link\").parent().remove();var $modal=get_modal(html_beautify($el_copy.html())).modal(\"show\");$modal.find(\":input:first\").focus();$modal.find(\".btn-success\").click(function(ev2){var html=$modal.find(\"textarea\").val();if(!html){$el.remove()}else{$el.html(html);$edit_btn.appendTo($el)}$modal.modal(\"hide\");return false})});$(document).on(\"click\",\".remove-link\",function(ev){$(this).parent().parent().remove()});$(\".input-group.date\").datetimepicker({format:\"yyyy-mm-dd\",minView:\"month\",autoclose:true});\r\n    </script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-common/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\r\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\r\n    <parent>\r\n        <artifactId>ruoyi</artifactId>\r\n        <groupId>com.ruoyi</groupId>\r\n        <version>4.8.2</version>\r\n    </parent>\r\n    <modelVersion>4.0.0</modelVersion>\r\n\r\n    <artifactId>ruoyi-common</artifactId>\r\n\r\n    <description>\r\n        common通用工具\r\n    </description>\r\n\r\n    <dependencies>\r\n\r\n        <!-- Spring框架基本的核心工具 -->\r\n        <dependency>\r\n            <groupId>org.springframework</groupId>\r\n            <artifactId>spring-context-support</artifactId>\r\n        </dependency>\r\n\r\n        <!-- SpringWeb模块 -->\r\n        <dependency>\r\n            <groupId>org.springframework</groupId>\r\n            <artifactId>spring-web</artifactId>\r\n        </dependency>\r\n\r\n        <!--Shiro核心框架 -->\r\n        <dependency>\r\n            <groupId>org.apache.shiro</groupId>\r\n            <artifactId>shiro-core</artifactId>\r\n            <classifier>jakarta</classifier>\r\n        </dependency>\r\n        \r\n        <!-- Shiro使用EhCache缓存框架 -->\r\n        <dependency>\r\n            <groupId>org.apache.shiro</groupId>\r\n            <artifactId>shiro-ehcache</artifactId>\r\n        </dependency>\r\n\r\n        <!-- pagehelper 分页插件 -->\r\n        <dependency>\r\n            <groupId>com.github.pagehelper</groupId>\r\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\r\n        </dependency>\r\n\r\n        <!-- 自定义验证注解 -->\r\n        <dependency>\r\n            <groupId>org.springframework.boot</groupId>\r\n            <artifactId>spring-boot-starter-validation</artifactId>\r\n        </dependency>\r\n\r\n        <!--常用工具类 -->\r\n        <dependency>\r\n            <groupId>org.apache.commons</groupId>\r\n            <artifactId>commons-lang3</artifactId>\r\n        </dependency>\r\n\r\n        <!-- JSON工具类 -->\r\n        <dependency>\r\n            <groupId>com.fasterxml.jackson.core</groupId>\r\n            <artifactId>jackson-databind</artifactId>\r\n        </dependency>\r\n\r\n        <!-- 阿里JSON解析器 -->\r\n        <dependency>\r\n            <groupId>com.alibaba</groupId>\r\n            <artifactId>fastjson</artifactId>\r\n        </dependency>\r\n\r\n        <!-- io常用工具类 -->\r\n        <dependency>\r\n            <groupId>commons-io</groupId>\r\n            <artifactId>commons-io</artifactId>\r\n        </dependency>\r\n\r\n        <!-- excel工具 -->\r\n        <dependency>\r\n            <groupId>org.apache.poi</groupId>\r\n            <artifactId>poi-ooxml</artifactId>\r\n        </dependency>\r\n\r\n        <!-- 解析客户端操作系统、浏览器等 -->\r\n        <dependency>\r\n            <groupId>nl.basjes.parse.useragent</groupId>\r\n            <artifactId>yauaa</artifactId>\r\n        </dependency>\r\n\r\n        <!-- servlet包 -->\r\n        <dependency>\r\n            <groupId>jakarta.servlet</groupId>\r\n            <artifactId>jakarta.servlet-api</artifactId>\r\n        </dependency>\r\n\r\n    </dependencies>\r\n\r\n</project>"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java",
    "content": "package com.ruoyi.common.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 匿名访问不鉴权注解\n * \n * @author ruoyi\n */\n@Target({ ElementType.METHOD, ElementType.TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface Anonymous\n{\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java",
    "content": "package com.ruoyi.common.annotation;\r\n\r\nimport java.lang.annotation.Documented;\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n/**\r\n * 数据权限过滤注解\r\n * \r\n * @author ruoyi\r\n */\r\n@Target(ElementType.METHOD)\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Documented\r\npublic @interface DataScope\r\n{\r\n    /**\r\n     * 部门表的别名\r\n     */\r\n    public String deptAlias() default \"\";\r\n\r\n    /**\r\n     * 用户表的别名\r\n     */\r\n    public String userAlias() default \"\";\r\n\r\n    /**\r\n     * 权限字符（用于多个角色匹配符合要求的权限）默认根据权限注解@RequiresPermissions获取，多个权限用逗号分隔开来\r\n     */\r\n    public String permission() default \"\";\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java",
    "content": "package com.ruoyi.common.annotation;\r\n\r\nimport java.lang.annotation.Documented;\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Inherited;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\nimport com.ruoyi.common.enums.DataSourceType;\r\n\r\n/**\r\n * 自定义多数据源切换注解\r\n *\r\n * 优先级：先方法，后类，如果方法覆盖了类上的数据源类型，以方法的为准，否则以类上的为准\r\n *\r\n * @author ruoyi\r\n */\r\n@Target({ ElementType.METHOD, ElementType.TYPE })\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Documented\r\n@Inherited\r\npublic @interface DataSource\r\n{\r\n    /**\r\n     * 切换数据源名称\r\n     */\r\n    public DataSourceType value() default DataSourceType.MASTER;\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java",
    "content": "package com.ruoyi.common.annotation;\r\n\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\nimport java.math.BigDecimal;\r\nimport org.apache.poi.ss.usermodel.HorizontalAlignment;\r\nimport org.apache.poi.ss.usermodel.IndexedColors;\r\nimport com.ruoyi.common.utils.poi.ExcelHandlerAdapter;\r\n\r\n/**\r\n * 自定义导出Excel数据注解\r\n * \r\n * @author ruoyi\r\n */\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Target(ElementType.FIELD)\r\npublic @interface Excel\r\n{\r\n    /**\r\n     * 导出时在excel中排序\r\n     */\r\n    public int sort() default Integer.MAX_VALUE;\r\n\r\n    /**\r\n     * 导出到Excel中的名字.\r\n     */\r\n    public String name() default \"\";\r\n\r\n    /**\r\n     * 日期格式, 如: yyyy-MM-dd\r\n     */\r\n    public String dateFormat() default \"\";\r\n\r\n    /**\r\n     * 如果是字典类型，请设置字典的type值 (如: sys_user_sex)\r\n     */\r\n    public String dictType() default \"\";\r\n\r\n    /**\r\n     * 读取内容转表达式 (如: 0=男,1=女,2=未知)\r\n     */\r\n    public String readConverterExp() default \"\";\r\n\r\n    /**\r\n     * 分隔符，读取字符串组内容\r\n     */\r\n    public String separator() default \",\";\r\n\r\n    /**\r\n     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)\r\n     */\r\n    public int scale() default -1;\r\n\r\n    /**\r\n     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN\r\n     */\r\n    @SuppressWarnings(\"deprecation\")\r\n\tpublic int roundingMode() default BigDecimal.ROUND_HALF_EVEN;\r\n\r\n    /**\r\n     * 导出时在excel中每个列的高度\r\n     */\r\n    public double height() default 14;\r\n\r\n    /**\r\n     * 导出时在excel中每个列的宽度\r\n     */\r\n    public double width() default 16;\r\n\r\n    /**\r\n     * 文字后缀,如% 90 变成90%\r\n     */\r\n    public String suffix() default \"\";\r\n\r\n    /**\r\n     * 当值为空时,字段的默认值\r\n     */\r\n    public String defaultValue() default \"\";\r\n\r\n    /**\r\n     * 提示信息\r\n     */\r\n    public String prompt() default \"\";\r\n\r\n    /**\r\n     * 是否允许内容换行 \r\n     */\r\n    public boolean wrapText() default false;\r\n\r\n    /**\r\n     * 设置只能选择不能输入的列内容.\r\n     */\r\n    public String[] combo() default {};\r\n\r\n    /**\r\n     * 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.\r\n     */\r\n    public boolean comboReadDict() default false;\r\n\r\n    /**\r\n     * 是否需要纵向合并单元格,应对需求:含有list集合单元格)\r\n     */\r\n    public boolean needMerge() default false;\r\n\r\n    /**\r\n     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.\r\n     */\r\n    public boolean isExport() default true;\r\n\r\n    /**\r\n     * 另一个类中的属性名称,支持多级获取,以小数点隔开\r\n     */\r\n    public String targetAttr() default \"\";\r\n\r\n    /**\r\n     * 是否自动统计数据,在最后追加一行统计数据总和\r\n     */\r\n    public boolean isStatistics() default false;\r\n\r\n    /**\r\n     * 导出类型（0数字 1字符串 2图片）\r\n     */\r\n    public ColumnType cellType() default ColumnType.STRING;\r\n\r\n    /**\r\n     * 导出列头背景颜色\r\n     */\r\n    public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;\r\n\r\n    /**\r\n     * 导出列头字体颜色\r\n     */\r\n    public IndexedColors headerColor() default IndexedColors.WHITE;\r\n\r\n    /**\r\n     * 导出单元格背景颜色\r\n     */\r\n    public IndexedColors backgroundColor() default IndexedColors.WHITE;\r\n\r\n    /**\r\n     * 导出单元格字体颜色\r\n     */\r\n    public IndexedColors color() default IndexedColors.BLACK;\r\n\r\n    /**\r\n     * 导出字段对齐方式\r\n     */\r\n    public HorizontalAlignment align() default HorizontalAlignment.CENTER;\r\n\r\n    /**\r\n     * 自定义数据处理器\r\n     */\r\n    public Class<?> handler() default ExcelHandlerAdapter.class;\r\n\r\n    /**\r\n     * 自定义数据处理器参数\r\n     */\r\n    public String[] args() default {};\r\n\r\n    /**\r\n     * 字段类型（0：导出导入；1：仅导出；2：仅导入）\r\n     */\r\n    Type type() default Type.ALL;\r\n\r\n    public enum Type\r\n    {\r\n        ALL(0), EXPORT(1), IMPORT(2);\r\n        private final int value;\r\n\r\n        Type(int value)\r\n        {\r\n            this.value = value;\r\n        }\r\n\r\n        public int value()\r\n        {\r\n            return this.value;\r\n        }\r\n    }\r\n\r\n    public enum ColumnType\r\n    {\r\n        NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);\r\n        private final int value;\r\n\r\n        ColumnType(int value)\r\n        {\r\n            this.value = value;\r\n        }\r\n\r\n        public int value()\r\n        {\r\n            return this.value;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java",
    "content": "package com.ruoyi.common.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Excel注解集\n * \n * @author ruoyi\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Excels\n{\n    Excel[] value();\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java",
    "content": "package com.ruoyi.common.annotation;\r\n\r\nimport java.lang.annotation.Documented;\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.enums.OperatorType;\r\n\r\n/**\r\n * 自定义操作日志记录注解\r\n * \r\n * @author ruoyi\r\n */\r\n@Target({ ElementType.PARAMETER, ElementType.METHOD })\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Documented\r\npublic @interface Log\r\n{\r\n    /**\r\n     * 模块\r\n     */\r\n    public String title() default \"\";\r\n\r\n    /**\r\n     * 功能\r\n     */\r\n    public BusinessType businessType() default BusinessType.OTHER;\r\n\r\n    /**\r\n     * 操作人类别\r\n     */\r\n    public OperatorType operatorType() default OperatorType.MANAGE;\r\n\r\n    /**\r\n     * 是否保存请求的参数\r\n     */\r\n    public boolean isSaveRequestData() default true;\r\n\r\n    /**\r\n     * 是否保存响应的参数\r\n     */\r\n    public boolean isSaveResponseData() default true;\r\n\r\n    /**\r\n     * 排除指定的请求参数\r\n     */\r\n    public String[] excludeParamNames() default {};\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java",
    "content": "package com.ruoyi.common.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 自定义注解防止表单重复提交\n * \n * @author ruoyi\n *\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface RepeatSubmit\n{\n    /**\n     * 间隔时间(ms)，小于此时间视为重复提交\n     */\n    public int interval() default 5000;\n\n    /**\n     * 提示消息\n     */\n    public String message() default \"不允许重复提交，请稍后再试\";\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java",
    "content": "package com.ruoyi.common.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport com.fasterxml.jackson.annotation.JacksonAnnotationsInside;\nimport com.fasterxml.jackson.databind.annotation.JsonSerialize;\nimport com.ruoyi.common.config.serializer.SensitiveJsonSerializer;\nimport com.ruoyi.common.enums.DesensitizedType;\n\n/**\n * 数据脱敏注解\n *\n * @author ruoyi\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\n@JacksonAnnotationsInside\n@JsonSerialize(using = SensitiveJsonSerializer.class)\npublic @interface Sensitive\n{\n    DesensitizedType desensitizedType();\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java",
    "content": "package com.ruoyi.common.config;\r\n\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\nimport org.springframework.stereotype.Component;\r\n\r\n/**\r\n * 全局配置类\r\n * \r\n * @author ruoyi\r\n */\r\n@Component\r\n@ConfigurationProperties(prefix = \"ruoyi\")\r\npublic class RuoYiConfig\r\n{\r\n    /** 项目名称 */\r\n    private static String name;\r\n\r\n    /** 版本 */\r\n    private static String version;\r\n\r\n    /** 版权年份 */\r\n    private static String copyrightYear;\r\n\r\n    /** 实例演示开关 */\r\n    private static boolean demoEnabled;\r\n\r\n    /** 上传路径 */\r\n    private static String profile;\r\n\r\n    /** 获取地址开关 */\r\n    private static boolean addressEnabled;\r\n\r\n    public static String getName()\r\n    {\r\n        return name;\r\n    }\r\n\r\n    public void setName(String name)\r\n    {\r\n        RuoYiConfig.name = name;\r\n    }\r\n\r\n    public static String getVersion()\r\n    {\r\n        return version;\r\n    }\r\n\r\n    public void setVersion(String version)\r\n    {\r\n        RuoYiConfig.version = version;\r\n    }\r\n\r\n    public static String getCopyrightYear()\r\n    {\r\n        return copyrightYear;\r\n    }\r\n\r\n    public void setCopyrightYear(String copyrightYear)\r\n    {\r\n        RuoYiConfig.copyrightYear = copyrightYear;\r\n    }\r\n\r\n    public static boolean isDemoEnabled()\r\n    {\r\n        return demoEnabled;\r\n    }\r\n\r\n    public void setDemoEnabled(boolean demoEnabled)\r\n    {\r\n        RuoYiConfig.demoEnabled = demoEnabled;\r\n    }\r\n\r\n    public static String getProfile()\r\n    {\r\n        return profile;\r\n    }\r\n\r\n    public void setProfile(String profile)\r\n    {\r\n        RuoYiConfig.profile = profile;\r\n    }\r\n\r\n    public static boolean isAddressEnabled()\r\n    {\r\n        return addressEnabled;\r\n    }\r\n\r\n    public void setAddressEnabled(boolean addressEnabled)\r\n    {\r\n        RuoYiConfig.addressEnabled = addressEnabled;\r\n    }\r\n\r\n    /**\r\n     * 获取导入上传路径\r\n     */\r\n    public static String getImportPath()\r\n    {\r\n        return getProfile() + \"/import\";\r\n    }\r\n\r\n    /**\r\n     * 获取头像上传路径\r\n     */\r\n    public static String getAvatarPath()\r\n    {\r\n        return getProfile() + \"/avatar\";\r\n    }\r\n\r\n    /**\r\n     * 获取下载路径\r\n     */\r\n    public static String getDownloadPath()\r\n    {\r\n        return getProfile() + \"/download/\";\r\n    }\r\n\r\n    /**\r\n     * 获取上传路径\r\n     */\r\n    public static String getUploadPath()\r\n    {\r\n        return getProfile() + \"/upload\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/config/ServerConfig.java",
    "content": "package com.ruoyi.common.config;\r\n\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\n\r\n/**\r\n * 服务相关配置\r\n * \r\n * @author ruoyi\r\n *\r\n */\r\n@Component\r\npublic class ServerConfig\r\n{\r\n    /**\r\n     * 获取完整的请求路径，包括：域名，端口，上下文访问路径\r\n     * \r\n     * @return 服务地址\r\n     */\r\n    public String getUrl()\r\n    {\r\n        HttpServletRequest request = ServletUtils.getRequest();\r\n        return getDomain(request);\r\n    }\r\n\r\n    public static String getDomain(HttpServletRequest request)\r\n    {\r\n        StringBuffer url = request.getRequestURL();\r\n        String contextPath = request.getServletContext().getContextPath();\r\n        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/config/datasource/DynamicDataSourceContextHolder.java",
    "content": "package com.ruoyi.common.config.datasource;\r\n\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * 数据源切换处理\r\n * \r\n * @author ruoyi\r\n */\r\npublic class DynamicDataSourceContextHolder\r\n{\r\n    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);\r\n\r\n    /**\r\n     * 使用ThreadLocal维护变量，ThreadLocal为每个使用该变量的线程提供独立的变量副本，\r\n     * 所以每一个线程都可以独立地改变自己的副本，而不会影响其它线程所对应的副本。\r\n     */\r\n    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();\r\n\r\n    /**\r\n     * 设置数据源的变量\r\n     */\r\n    public static void setDataSourceType(String dsType)\r\n    {\r\n        log.info(\"切换到{}数据源\", dsType);\r\n        CONTEXT_HOLDER.set(dsType);\r\n    }\r\n\r\n    /**\r\n     * 获得数据源的变量\r\n     */\r\n    public static String getDataSourceType()\r\n    {\r\n        return CONTEXT_HOLDER.get();\r\n    }\r\n\r\n    /**\r\n     * 清空数据源变量\r\n     */\r\n    public static void clearDataSourceType()\r\n    {\r\n        CONTEXT_HOLDER.remove();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java",
    "content": "package com.ruoyi.common.config.serializer;\n\nimport java.io.IOException;\nimport java.util.Objects;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.BeanProperty;\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.SerializerProvider;\nimport com.fasterxml.jackson.databind.ser.ContextualSerializer;\nimport com.ruoyi.common.annotation.Sensitive;\nimport com.ruoyi.common.core.domain.entity.SysUser;\nimport com.ruoyi.common.enums.DesensitizedType;\nimport com.ruoyi.common.utils.ShiroUtils;\n\n/**\n * 数据脱敏序列化过滤\n *\n * @author ruoyi\n */\npublic class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer\n{\n    private DesensitizedType desensitizedType;\n\n    @Override\n    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException\n    {\n        if (desensitization())\n        {\n            gen.writeString(desensitizedType.desensitizer().apply(value));\n        }\n        else\n        {\n            gen.writeString(value);\n        }\n    }\n\n    @Override\n    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)\n            throws JsonMappingException\n    {\n        Sensitive annotation = property.getAnnotation(Sensitive.class);\n        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))\n        {\n            this.desensitizedType = annotation.desensitizedType();\n            return this;\n        }\n        return prov.findValueSerializer(property.getType(), property);\n    }\n\n    /**\n     * 是否需要脱敏处理\n     */\n    private boolean desensitization()\n    {\n        SysUser securityUser = ShiroUtils.getSysUser();\n        if (securityUser == null)\n        {\n            return true;\n        }\n        // 管理员不脱敏\n        return !securityUser.isAdmin();\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/config/thread/ThreadPoolConfig.java",
    "content": "package com.ruoyi.common.config.thread;\r\n\r\nimport java.util.concurrent.ScheduledExecutorService;\r\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\r\nimport java.util.concurrent.ThreadPoolExecutor;\r\nimport org.apache.commons.lang3.concurrent.BasicThreadFactory;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\r\nimport com.ruoyi.common.utils.Threads;\r\n\r\n/**\r\n * 线程池配置\r\n *\r\n * @author ruoyi\r\n **/\r\n@Configuration\r\npublic class ThreadPoolConfig\r\n{\r\n    // 核心线程池大小\r\n    private int corePoolSize = 50;\r\n\r\n    // 最大可创建的线程数\r\n    private int maxPoolSize = 200;\r\n\r\n    // 队列最大长度\r\n    private int queueCapacity = 1000;\r\n\r\n    // 线程池维护线程所允许的空闲时间\r\n    private int keepAliveSeconds = 300;\r\n\r\n    @Bean(name = \"threadPoolTaskExecutor\")\r\n    public ThreadPoolTaskExecutor threadPoolTaskExecutor()\r\n    {\r\n        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();\r\n        executor.setMaxPoolSize(maxPoolSize);\r\n        executor.setCorePoolSize(corePoolSize);\r\n        executor.setQueueCapacity(queueCapacity);\r\n        executor.setKeepAliveSeconds(keepAliveSeconds);\r\n        // 线程池对拒绝任务(无线程可用)的处理策略\r\n        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());\r\n        return executor;\r\n    }\r\n    \r\n    /**\r\n     * 执行周期性或定时任务\r\n     */\r\n    @Bean(name = \"scheduledExecutorService\")\r\n    protected ScheduledExecutorService scheduledExecutorService()\r\n    {\r\n        return new ScheduledThreadPoolExecutor(corePoolSize,\r\n            BasicThreadFactory.builder().namingPattern(\"schedule-pool-%d\").daemon(true).build(),\r\n            new ThreadPoolExecutor.CallerRunsPolicy())\r\n        {\r\n            @Override\r\n            protected void afterExecute(Runnable r, Throwable t)\r\n            {\r\n                super.afterExecute(r, t);\r\n                Threads.printException(r, t);\r\n            }\r\n        };\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java",
    "content": "package com.ruoyi.common.constant;\r\n\r\nimport java.util.Locale;\r\n\r\n/**\r\n * 通用常量信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Constants\r\n{\r\n    /**\r\n     * UTF-8 字符集\r\n     */\r\n    public static final String UTF8 = \"UTF-8\";\r\n\r\n    /**\r\n     * GBK 字符集\r\n     */\r\n    public static final String GBK = \"GBK\";\r\n\r\n    /**\r\n     * 系统语言\r\n     */\r\n    public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;\r\n\r\n    /**\r\n     * http请求\r\n     */\r\n    public static final String HTTP = \"http://\";\r\n\r\n    /**\r\n     * https请求\r\n     */\r\n    public static final String HTTPS = \"https://\";\r\n\r\n    /**\r\n     * 通用成功标识\r\n     */\r\n    public static final String SUCCESS = \"0\";\r\n\r\n    /**\r\n     * 通用失败标识\r\n     */\r\n    public static final String FAIL = \"1\";\r\n\r\n    /**\r\n     * 登录成功\r\n     */\r\n    public static final String LOGIN_SUCCESS = \"Success\";\r\n\r\n    /**\r\n     * 注销\r\n     */\r\n    public static final String LOGOUT = \"Logout\";\r\n\r\n    /**\r\n     * 注册\r\n     */\r\n    public static final String REGISTER = \"Register\";\r\n\r\n    /**\r\n     * 登录失败\r\n     */\r\n    public static final String LOGIN_FAIL = \"Error\";\r\n\r\n    /**\r\n     * 系统用户授权缓存\r\n     */\r\n    public static final String SYS_AUTH_CACHE = \"sys-authCache\";\r\n\r\n    /**\r\n     * 参数管理 cache name\r\n     */\r\n    public static final String SYS_CONFIG_CACHE = \"sys-config\";\r\n\r\n    /**\r\n     * 参数管理 cache key\r\n     */\r\n    public static final String SYS_CONFIG_KEY = \"sys_config:\";\r\n\r\n    /**\r\n     * 字典管理 cache name\r\n     */\r\n    public static final String SYS_DICT_CACHE = \"sys-dict\";\r\n\r\n    /**\r\n     * 字典管理 cache key\r\n     */\r\n    public static final String SYS_DICT_KEY = \"sys_dict:\";\r\n\r\n    /**\r\n     * 资源映射路径 前缀\r\n     */\r\n    public static final String RESOURCE_PREFIX = \"/profile\";\r\n\r\n    /**\r\n     * RMI 远程方法调用\r\n     */\r\n    public static final String LOOKUP_RMI = \"rmi:\";\r\n\r\n    /**\r\n     * LDAP 远程方法调用\r\n     */\r\n    public static final String LOOKUP_LDAP = \"ldap:\";\r\n\r\n    /**\r\n     * LDAPS 远程方法调用\r\n     */\r\n    public static final String LOOKUP_LDAPS = \"ldaps:\";\r\n\r\n    /**\r\n     * 定时任务白名单配置（仅允许访问的包名，如其他需要可以自行添加）\r\n     */\r\n    public static final String[] JOB_WHITELIST_STR = { \"com.ruoyi.quartz.task\" };\r\n\r\n    /**\r\n     * 定时任务违规的字符\r\n     */\r\n    public static final String[] JOB_ERROR_STR = { \"java.net.URL\", \"javax.naming.InitialContext\", \"org.yaml.snakeyaml\",\r\n            \"org.springframework\", \"org.apache\", \"com.ruoyi.common.utils.file\", \"com.ruoyi.common.config\", \"com.ruoyi.generator\" };\r\n\r\n    /**\r\n     * 部门相关常量\r\n     */\r\n    public static class Dept\r\n    {\r\n        /**\r\n         * 全部数据权限\r\n         */\r\n        public static final String DATA_SCOPE_ALL = \"1\";\r\n\r\n        /**\r\n         * 自定数据权限\r\n         */\r\n        public static final String DATA_SCOPE_CUSTOM = \"2\";\r\n\r\n        /**\r\n         * 部门数据权限\r\n         */\r\n        public static final String DATA_SCOPE_DEPT = \"3\";\r\n\r\n        /**\r\n         * 部门及以下数据权限\r\n         */\r\n        public static final String DATA_SCOPE_DEPT_AND_CHILD = \"4\";\r\n\r\n        /**\r\n         * 仅本人数据权限\r\n         */\r\n        public static final String DATA_SCOPE_SELF = \"5\";\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java",
    "content": "package com.ruoyi.common.constant;\r\n\r\n/**\r\n * 代码生成通用常量\r\n * \r\n * @author ruoyi\r\n */\r\npublic class GenConstants\r\n{\r\n    /** 单表（增删改查） */\r\n    public static final String TPL_CRUD = \"crud\";\r\n\r\n    /** 树表（增删改查） */\r\n    public static final String TPL_TREE = \"tree\";\r\n\r\n    /** 主子表（增删改查） */\r\n    public static final String TPL_SUB = \"sub\";\r\n\r\n    /** 树编码字段 */\r\n    public static final String TREE_CODE = \"treeCode\";\r\n\r\n    /** 树父编码字段 */\r\n    public static final String TREE_PARENT_CODE = \"treeParentCode\";\r\n\r\n    /** 树名称字段 */\r\n    public static final String TREE_NAME = \"treeName\";\r\n\r\n    /** 上级菜单ID字段 */\r\n    public static final String PARENT_MENU_ID = \"parentMenuId\";\r\n\r\n    /** 上级菜单名称字段 */\r\n    public static final String PARENT_MENU_NAME = \"parentMenuName\";\r\n\r\n    /** 数据库字符串类型 */\r\n    public static final String[] COLUMNTYPE_STR = { \"char\", \"varchar\", \"nvarchar\", \"varchar2\" };\r\n\r\n    /** 数据库文本类型 */\r\n    public static final String[] COLUMNTYPE_TEXT = { \"tinytext\", \"text\", \"mediumtext\", \"longtext\" };\r\n\r\n    /** 数据库时间类型 */\r\n    public static final String[] COLUMNTYPE_TIME = { \"datetime\", \"time\", \"date\", \"timestamp\" };\r\n\r\n    /** 数据库数字类型 */\r\n    public static final String[] COLUMNTYPE_NUMBER = { \"tinyint\", \"smallint\", \"mediumint\", \"int\", \"number\", \"integer\",\r\n            \"bit\", \"bigint\", \"float\", \"double\", \"decimal\" };\r\n\r\n    /** 页面不需要编辑字段 */\r\n    public static final String[] COLUMNNAME_NOT_EDIT = { \"id\", \"create_by\", \"create_time\", \"del_flag\" };\r\n\r\n    /** 页面不需要显示的列表字段 */\r\n    public static final String[] COLUMNNAME_NOT_LIST = { \"id\", \"create_by\", \"create_time\", \"del_flag\", \"update_by\",\r\n            \"update_time\" };\r\n\r\n    /** 页面不需要查询字段 */\r\n    public static final String[] COLUMNNAME_NOT_QUERY = { \"id\", \"create_by\", \"create_time\", \"del_flag\", \"update_by\",\r\n            \"update_time\", \"remark\" };\r\n\r\n    /** Entity基类字段 */\r\n    public static final String[] BASE_ENTITY = { \"createBy\", \"createTime\", \"updateBy\", \"updateTime\", \"remark\" };\r\n\r\n    /** Tree基类字段 */\r\n    public static final String[] TREE_ENTITY = { \"parentName\", \"parentId\", \"orderNum\", \"ancestors\" };\r\n\r\n    /** 文本框 */\r\n    public static final String HTML_INPUT = \"input\";\r\n\r\n    /** 文本域 */\r\n    public static final String HTML_TEXTAREA = \"textarea\";\r\n\r\n    /** 下拉框 */\r\n    public static final String HTML_SELECT = \"select\";\r\n\r\n    /** 单选框 */\r\n    public static final String HTML_RADIO = \"radio\";\r\n\r\n    /** 复选框 */\r\n    public static final String HTML_CHECKBOX = \"checkbox\";\r\n\r\n    /** 日期控件 */\r\n    public static final String HTML_DATETIME = \"datetime\";\r\n\r\n    /** 上传控件 */\r\n    public static final String HTML_UPLOAD = \"upload\";\r\n\r\n    /** 富文本控件 */\r\n    public static final String HTML_SUMMERNOTE = \"summernote\";\r\n\r\n    /** 字符串类型 */\r\n    public static final String TYPE_STRING = \"String\";\r\n\r\n    /** 整型 */\r\n    public static final String TYPE_INTEGER = \"Integer\";\r\n\r\n    /** 长整型 */\r\n    public static final String TYPE_LONG = \"Long\";\r\n\r\n    /** 浮点型 */\r\n    public static final String TYPE_DOUBLE = \"Double\";\r\n\r\n    /** 高精度计算类型 */\r\n    public static final String TYPE_BIGDECIMAL = \"BigDecimal\";\r\n\r\n    /** 时间类型 */\r\n    public static final String TYPE_DATE = \"Date\";\r\n\r\n    /** 模糊查询 */\r\n    public static final String QUERY_LIKE = \"LIKE\";\r\n\r\n    /** 相等查询 */\r\n    public static final String QUERY_EQ = \"EQ\";\r\n\r\n    /** 需要 */\r\n    public static final String REQUIRE = \"1\";\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/constant/PermissionConstants.java",
    "content": "package com.ruoyi.common.constant;\r\n\r\n/**\r\n * 权限通用常量\r\n * \r\n * @author ruoyi\r\n */\r\npublic class PermissionConstants\r\n{\r\n    /** 新增权限 */\r\n    public static final String ADD_PERMISSION = \"add\";\r\n\r\n    /** 修改权限 */\r\n    public static final String EDIT_PERMISSION = \"edit\";\r\n\r\n    /** 删除权限 */\r\n    public static final String REMOVE_PERMISSION = \"remove\";\r\n    \r\n    /** 导出权限 */\r\n    public static final String EXPORT_PERMISSION = \"export\";\r\n\r\n    /** 显示权限 */\r\n    public static final String VIEW_PERMISSION = \"view\";\r\n\r\n    /** 查询权限 */\r\n    public static final String LIST_PERMISSION = \"list\";\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java",
    "content": "package com.ruoyi.common.constant;\r\n\r\n/**\r\n * 任务调度通用常量\r\n * \r\n * @author ruoyi\r\n */\r\npublic class ScheduleConstants\r\n{\r\n    public static final String TASK_CLASS_NAME = \"TASK_CLASS_NAME\";\r\n\r\n    /** 执行目标key */\r\n    public static final String TASK_PROPERTIES = \"TASK_PROPERTIES\";\r\n\r\n    /** 默认 */\r\n    public static final String MISFIRE_DEFAULT = \"0\";\r\n\r\n    /** 立即触发执行 */\r\n    public static final String MISFIRE_IGNORE_MISFIRES = \"1\";\r\n\r\n    /** 触发一次执行 */\r\n    public static final String MISFIRE_FIRE_AND_PROCEED = \"2\";\r\n\r\n    /** 不触发立即执行 */\r\n    public static final String MISFIRE_DO_NOTHING = \"3\";\r\n\r\n    public enum Status\r\n    {\r\n        /**\r\n         * 正常\r\n         */\r\n        NORMAL(\"0\"),\r\n        /**\r\n         * 暂停\r\n         */\r\n        PAUSE(\"1\");\r\n\r\n        private String value;\r\n\r\n        private Status(String value)\r\n        {\r\n            this.value = value;\r\n        }\r\n\r\n        public String getValue()\r\n        {\r\n            return value;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/constant/ShiroConstants.java",
    "content": "package com.ruoyi.common.constant;\r\n\r\n/**\r\n * Shiro通用常量\r\n * \r\n * @author ruoyi\r\n */\r\npublic class ShiroConstants\r\n{\r\n    /**\r\n     * 当前登录的用户\r\n     */\r\n    public static final String CURRENT_USER = \"currentUser\";\r\n\r\n    /**\r\n     * 用户名字段\r\n     */\r\n    public static final String CURRENT_USERNAME = \"username\";\r\n\r\n    /**\r\n     * 锁定屏幕字段\r\n     */\r\n    public static final String LOCK_SCREEN = \"lockscreen\";\r\n\r\n    /**\r\n     * 消息key\r\n     */\r\n    public static final String MESSAGE = \"message\";\r\n\r\n    /**\r\n     * 错误key\r\n     */\r\n    public static final String ERROR = \"errorMsg\";\r\n\r\n    /**\r\n     * csrf session content\r\n     */\r\n    public static final String CSRF_TOKEN = \"csrf_token\";\r\n\r\n    /**\r\n     * csrf request header\r\n     */\r\n    public static final String X_CSRF_TOKEN = \"X-CSRF-Token\";\r\n\r\n    /**\r\n     * 当前在线会话\r\n     */\r\n    public static final String ONLINE_SESSION = \"online_session\";\r\n\r\n    /**\r\n     * 验证码key\r\n     */\r\n    public static final String CURRENT_CAPTCHA = \"captcha\";\r\n\r\n    /**\r\n     * 验证码开关\r\n     */\r\n    public static final String CURRENT_ENABLED = \"captchaEnabled\";\r\n\r\n    /**\r\n     * 验证码类型\r\n     */\r\n    public static final String CURRENT_TYPE = \"captchaType\";\r\n\r\n    /**\r\n     * 验证码\r\n     */\r\n    public static final String CURRENT_VALIDATECODE = \"validateCode\";\r\n\r\n    /**\r\n     * 验证码错误\r\n     */\r\n    public static final String CAPTCHA_ERROR = \"captchaError\";\r\n\r\n    /**\r\n     * 登录记录缓存\r\n     */\r\n    public static final String LOGIN_RECORD_CACHE = \"loginRecordCache\";\r\n\r\n    /**\r\n     * 系统活跃用户缓存\r\n     */\r\n    public static final String SYS_USERCACHE = \"sys-userCache\";\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java",
    "content": "package com.ruoyi.common.constant;\r\n\r\n/**\r\n * 用户常量信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserConstants\r\n{\r\n    /**\r\n     * 平台内系统用户的唯一标志\r\n     */\r\n    public static final String SYS_USER = \"SYS_USER\";\r\n\r\n    /** 正常状态 */\r\n    public static final String NORMAL = \"0\";\r\n\r\n    /** 异常状态 */\r\n    public static final String EXCEPTION = \"1\";\r\n\r\n    /** 用户封禁状态 */\r\n    public static final String USER_DISABLE = \"1\";\r\n\r\n    /** 角色正常状态 */\r\n    public static final String ROLE_NORMAL = \"0\";\r\n\r\n    /** 角色封禁状态 */\r\n    public static final String ROLE_DISABLE = \"1\";\r\n\r\n    /** 部门正常状态 */\r\n    public static final String DEPT_NORMAL = \"0\";\r\n\r\n    /** 部门停用状态 */\r\n    public static final String DEPT_DISABLE = \"1\";\r\n\r\n    /** 字典正常状态 */\r\n    public static final String DICT_NORMAL = \"0\";\r\n\r\n    /** 是否为系统默认（是） */\r\n    public static final String YES = \"Y\";\r\n    \r\n    /** 是否唯一的返回标识 */\r\n    public final static boolean UNIQUE = true;\r\n    public final static boolean NOT_UNIQUE = false;\r\n\r\n    /**\r\n     * 用户名长度限制\r\n     */\r\n    public static final int USERNAME_MIN_LENGTH = 2;\r\n    public static final int USERNAME_MAX_LENGTH = 20;\r\n\r\n    /**\r\n     * 密码长度限制\r\n     */\r\n    public static final int PASSWORD_MIN_LENGTH = 5;\r\n    public static final int PASSWORD_MAX_LENGTH = 20;\r\n\r\n    /**\r\n     * 用户类型\r\n     */\r\n    public static final String SYSTEM_USER_TYPE = \"00\";\r\n    public static final String REGISTER_USER_TYPE = \"01\";\r\n\r\n    /**\r\n     * 手机号码格式限制\r\n     */\r\n    public static final String MOBILE_PHONE_NUMBER_PATTERN = \"^0{0,1}(13[0-9]|15[0-9]|14[0-9]|18[0-9])[0-9]{8}$\";\r\n\r\n    /**\r\n     * 邮箱格式限制\r\n     */\r\n    public static final String EMAIL_PATTERN = \"^((([a-z]|\\\\d|[!#\\\\$%&'\\\\*\\\\+\\\\-\\\\/=\\\\?\\\\^_`{\\\\|}~]|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])+(\\\\.([a-z]|\\\\d|[!#\\\\$%&'\\\\*\\\\+\\\\-\\\\/=\\\\?\\\\^_`{\\\\|}~]|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])+)*)|((\\\\x22)((((\\\\x20|\\\\x09)*(\\\\x0d\\\\x0a))?(\\\\x20|\\\\x09)+)?(([\\\\x01-\\\\x08\\\\x0b\\\\x0c\\\\x0e-\\\\x1f\\\\x7f]|\\\\x21|[\\\\x23-\\\\x5b]|[\\\\x5d-\\\\x7e]|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])|(\\\\\\\\([\\\\x01-\\\\x09\\\\x0b\\\\x0c\\\\x0d-\\\\x7f]|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF]))))*(((\\\\x20|\\\\x09)*(\\\\x0d\\\\x0a))?(\\\\x20|\\\\x09)+)?(\\\\x22)))@((([a-z]|\\\\d|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])|(([a-z]|\\\\d|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])([a-z]|\\\\d|-|\\\\.|_|~|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])*([a-z]|\\\\d|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])))\\\\.)+(([a-z]|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])|(([a-z]|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])([a-z]|\\\\d|-|\\\\.|_|~|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])*([a-z]|[\\\\u00A0-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFEF])))\\\\.?\";\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/context/PermissionContextHolder.java",
    "content": "package com.ruoyi.common.core.context;\n\nimport org.springframework.web.context.request.RequestAttributes;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport com.ruoyi.common.core.text.Convert;\n\n/**\n * 权限信息\n * \n * @author ruoyi\n */\npublic class PermissionContextHolder\n{\n    private static final String PERMISSION_CONTEXT_ATTRIBUTES = \"PERMISSION_CONTEXT\";\n\n    public static void setContext(String permission)\n    {\n        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,\n                RequestAttributes.SCOPE_REQUEST);\n    }\n\n    public static String getContext()\n    {\n        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,\n                RequestAttributes.SCOPE_REQUEST));\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java",
    "content": "package com.ruoyi.common.core.controller;\r\n\r\nimport java.beans.PropertyEditorSupport;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport jakarta.servlet.http.HttpSession;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.web.bind.WebDataBinder;\r\nimport org.springframework.web.bind.annotation.InitBinder;\r\nimport com.github.pagehelper.PageHelper;\r\nimport com.github.pagehelper.PageInfo;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.domain.AjaxResult.Type;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.page.PageDomain;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.core.page.TableSupport;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.PageUtils;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.sql.SqlUtil;\r\n\r\n/**\r\n * web层通用数据处理\r\n * \r\n * @author ruoyi\r\n */\r\npublic class BaseController\r\n{\r\n    protected final Logger logger = LoggerFactory.getLogger(this.getClass());\r\n\r\n    /**\r\n     * 将前台传递过来的日期格式的字符串，自动转化为Date类型\r\n     */\r\n    @InitBinder\r\n    public void initBinder(WebDataBinder binder)\r\n    {\r\n        // Date 类型转换\r\n        binder.registerCustomEditor(Date.class, new PropertyEditorSupport()\r\n        {\r\n            @Override\r\n            public void setAsText(String text)\r\n            {\r\n                setValue(DateUtils.parseDate(text));\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * 设置请求分页数据\r\n     */\r\n    protected void startPage()\r\n    {\r\n        PageUtils.startPage();\r\n    }\r\n\r\n    /**\r\n     * 设置请求排序数据\r\n     */\r\n    protected void startOrderBy()\r\n    {\r\n        PageDomain pageDomain = TableSupport.buildPageRequest();\r\n        if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))\r\n        {\r\n            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());\r\n            PageHelper.orderBy(orderBy);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 清理分页的线程变量\r\n     */\r\n    protected void clearPage()\r\n    {\r\n        PageUtils.clearPage();\r\n    }\r\n\r\n    /**\r\n     * 获取request\r\n     */\r\n    public HttpServletRequest getRequest()\r\n    {\r\n        return ServletUtils.getRequest();\r\n    }\r\n\r\n    /**\r\n     * 获取response\r\n     */\r\n    public HttpServletResponse getResponse()\r\n    {\r\n        return ServletUtils.getResponse();\r\n    }\r\n\r\n    /**\r\n     * 获取session\r\n     */\r\n    public HttpSession getSession()\r\n    {\r\n        return getRequest().getSession();\r\n    }\r\n\r\n    /**\r\n     * 响应请求分页数据\r\n     */\r\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\r\n    protected TableDataInfo getDataTable(List<?> list)\r\n    {\r\n        TableDataInfo rspData = new TableDataInfo();\r\n        rspData.setCode(0);\r\n        rspData.setRows(list);\r\n        rspData.setTotal(new PageInfo(list).getTotal());\r\n        return rspData;\r\n    }\r\n\r\n    /**\r\n     * 响应返回结果\r\n     * \r\n     * @param rows 影响行数\r\n     * @return 操作结果\r\n     */\r\n    protected AjaxResult toAjax(int rows)\r\n    {\r\n        return rows > 0 ? success() : error();\r\n    }\r\n\r\n    /**\r\n     * 响应返回结果\r\n     * \r\n     * @param result 结果\r\n     * @return 操作结果\r\n     */\r\n    protected AjaxResult toAjax(boolean result)\r\n    {\r\n        return result ? success() : error();\r\n    }\r\n\r\n    /**\r\n     * 返回成功\r\n     */\r\n    public AjaxResult success()\r\n    {\r\n        return AjaxResult.success();\r\n    }\r\n\r\n    /**\r\n     * 返回失败消息\r\n     */\r\n    public AjaxResult error()\r\n    {\r\n        return AjaxResult.error();\r\n    }\r\n\r\n    /**\r\n     * 返回成功消息\r\n     */\r\n    public AjaxResult success(String message)\r\n    {\r\n        return AjaxResult.success(message);\r\n    }\r\n\r\n    /**\r\n     * 返回成功数据\r\n     */\r\n    public static AjaxResult success(Object data)\r\n    {\r\n        return AjaxResult.success(\"操作成功\", data);\r\n    }\r\n\r\n    /**\r\n     * 返回失败消息\r\n     */\r\n    public AjaxResult error(String message)\r\n    {\r\n        return AjaxResult.error(message);\r\n    }\r\n\r\n    /**\r\n     * 返回错误码消息\r\n     */\r\n    public AjaxResult error(Type type, String message)\r\n    {\r\n        return new AjaxResult(type, message);\r\n    }\r\n\r\n    /**\r\n     * 页面跳转\r\n     */\r\n    public String redirect(String url)\r\n    {\r\n        return StringUtils.format(\"redirect:{}\", url);\r\n    }\r\n\r\n    /**\r\n     * 获取用户缓存信息\r\n     */\r\n    public SysUser getSysUser()\r\n    {\r\n        return ShiroUtils.getSysUser();\r\n    }\r\n\r\n    /**\r\n     * 设置用户缓存信息\r\n     */\r\n    public void setSysUser(SysUser user)\r\n    {\r\n        ShiroUtils.setSysUser(user);\r\n    }\r\n\r\n    /**\r\n     * 获取登录用户id\r\n     */\r\n    public Long getUserId()\r\n    {\r\n        return getSysUser().getUserId();\r\n    }\r\n\r\n    /**\r\n     * 获取登录用户名\r\n     */\r\n    public String getLoginName()\r\n    {\r\n        return getSysUser().getLoginName();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java",
    "content": "package com.ruoyi.common.core.domain;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.Objects;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 操作消息提醒\r\n *\r\n * @author ruoyi\r\n */\r\npublic class AjaxResult extends HashMap<String, Object>\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 状态码 */\r\n    public static final String CODE_TAG = \"code\";\r\n\r\n    /** 返回内容 */\r\n    public static final String MSG_TAG = \"msg\";\r\n\r\n    /** 数据对象 */\r\n    public static final String DATA_TAG = \"data\";\r\n\r\n    /**\r\n     * 状态类型\r\n     */\r\n    public enum Type\r\n    {\r\n        /** 成功 */\r\n        SUCCESS(0),\r\n        /** 警告 */\r\n        WARN(301),\r\n        /** 错误 */\r\n        ERROR(500);\r\n        private final int value;\r\n\r\n        Type(int value)\r\n        {\r\n            this.value = value;\r\n        }\r\n\r\n        public int value()\r\n        {\r\n            return this.value;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 初始化一个新创建的 AjaxResult 对象，使其表示一个空消息。\r\n     */\r\n    public AjaxResult()\r\n    {\r\n    }\r\n\r\n    /**\r\n     * 初始化一个新创建的 AjaxResult 对象\r\n     *\r\n     * @param type 状态类型\r\n     * @param msg 返回内容\r\n     */\r\n    public AjaxResult(Type type, String msg)\r\n    {\r\n        super.put(CODE_TAG, type.value);\r\n        super.put(MSG_TAG, msg);\r\n    }\r\n\r\n    /**\r\n     * 初始化一个新创建的 AjaxResult 对象\r\n     *\r\n     * @param type 状态类型\r\n     * @param msg 返回内容\r\n     * @param data 数据对象\r\n     */\r\n    public AjaxResult(Type type, String msg, Object data)\r\n    {\r\n        super.put(CODE_TAG, type.value);\r\n        super.put(MSG_TAG, msg);\r\n        if (StringUtils.isNotNull(data))\r\n        {\r\n            super.put(DATA_TAG, data);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 返回成功消息\r\n     *\r\n     * @return 成功消息\r\n     */\r\n    public static AjaxResult success()\r\n    {\r\n        return AjaxResult.success(\"操作成功\");\r\n    }\r\n\r\n    /**\r\n     * 返回成功数据\r\n     *\r\n     * @return 成功消息\r\n     */\r\n    public static AjaxResult success(Object data)\r\n    {\r\n        return AjaxResult.success(\"操作成功\", data);\r\n    }\r\n\r\n    /**\r\n     * 返回成功消息\r\n     *\r\n     * @param msg 返回内容\r\n     * @return 成功消息\r\n     */\r\n    public static AjaxResult success(String msg)\r\n    {\r\n        return AjaxResult.success(msg, null);\r\n    }\r\n\r\n    /**\r\n     * 返回成功消息\r\n     *\r\n     * @param msg 返回内容\r\n     * @param data 数据对象\r\n     * @return 成功消息\r\n     */\r\n    public static AjaxResult success(String msg, Object data)\r\n    {\r\n        return new AjaxResult(Type.SUCCESS, msg, data);\r\n    }\r\n\r\n    /**\r\n     * 返回警告消息\r\n     *\r\n     * @param msg 返回内容\r\n     * @return 警告消息\r\n     */\r\n    public static AjaxResult warn(String msg)\r\n    {\r\n        return AjaxResult.warn(msg, null);\r\n    }\r\n\r\n    /**\r\n     * 返回警告消息\r\n     *\r\n     * @param msg 返回内容\r\n     * @param data 数据对象\r\n     * @return 警告消息\r\n     */\r\n    public static AjaxResult warn(String msg, Object data)\r\n    {\r\n        return new AjaxResult(Type.WARN, msg, data);\r\n    }\r\n\r\n    /**\r\n     * 返回错误消息\r\n     *\r\n     * @return\r\n     */\r\n    public static AjaxResult error()\r\n    {\r\n        return AjaxResult.error(\"操作失败\");\r\n    }\r\n\r\n    /**\r\n     * 返回错误消息\r\n     *\r\n     * @param msg 返回内容\r\n     * @return 警告消息\r\n     */\r\n    public static AjaxResult error(String msg)\r\n    {\r\n        return AjaxResult.error(msg, null);\r\n    }\r\n\r\n    /**\r\n     * 返回错误消息\r\n     *\r\n     * @param msg 返回内容\r\n     * @param data 数据对象\r\n     * @return 警告消息\r\n     */\r\n    public static AjaxResult error(String msg, Object data)\r\n    {\r\n        return new AjaxResult(Type.ERROR, msg, data);\r\n    }\r\n\r\n    /**\r\n     * 是否为成功消息\r\n     *\r\n     * @return 结果\r\n     */\r\n    public boolean isSuccess()\r\n    {\r\n        return Objects.equals(Type.SUCCESS.value, this.get(CODE_TAG));\r\n    }\r\n\r\n    /**\r\n     * 是否为警告消息\r\n     *\r\n     * @return 结果\r\n     */\r\n    public boolean isWarn()\r\n    {\r\n        return Objects.equals(Type.WARN.value, this.get(CODE_TAG));\r\n    }\r\n\r\n    /**\r\n     * 是否为错误消息\r\n     *\r\n     * @return 结果\r\n     */\r\n    public boolean isError()\r\n    {\r\n        return Objects.equals(Type.ERROR.value, this.get(CODE_TAG));\r\n    }\r\n\r\n    /**\r\n     * 方便链式调用\r\n     *\r\n     * @param key 键\r\n     * @param value 值\r\n     * @return 数据对象\r\n     */\r\n    @Override\r\n    public AjaxResult put(String key, Object value)\r\n    {\r\n        super.put(key, value);\r\n        return this;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java",
    "content": "package com.ruoyi.common.core.domain;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\nimport com.fasterxml.jackson.annotation.JsonFormat;\r\nimport com.fasterxml.jackson.annotation.JsonIgnore;\r\nimport com.fasterxml.jackson.annotation.JsonInclude;\r\n\r\n/**\r\n * Entity基类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class BaseEntity implements Serializable\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 搜索值 */\r\n    @JsonIgnore\r\n    private String searchValue;\r\n\r\n    /** 创建者 */\r\n    private String createBy;\r\n\r\n    /** 创建时间 */\r\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")\r\n    private Date createTime;\r\n\r\n    /** 更新者 */\r\n    private String updateBy;\r\n\r\n    /** 更新时间 */\r\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")\r\n    private Date updateTime;\r\n\r\n    /** 备注 */\r\n    private String remark;\r\n\r\n    /** 请求参数 */\r\n    @JsonInclude(JsonInclude.Include.NON_EMPTY)\r\n    private Map<String, Object> params;\r\n\r\n    public String getSearchValue()\r\n    {\r\n        return searchValue;\r\n    }\r\n\r\n    public void setSearchValue(String searchValue)\r\n    {\r\n        this.searchValue = searchValue;\r\n    }\r\n\r\n    public String getCreateBy()\r\n    {\r\n        return createBy;\r\n    }\r\n\r\n    public void setCreateBy(String createBy)\r\n    {\r\n        this.createBy = createBy;\r\n    }\r\n\r\n    public Date getCreateTime()\r\n    {\r\n        return createTime;\r\n    }\r\n\r\n    public void setCreateTime(Date createTime)\r\n    {\r\n        this.createTime = createTime;\r\n    }\r\n\r\n    public String getUpdateBy()\r\n    {\r\n        return updateBy;\r\n    }\r\n\r\n    public void setUpdateBy(String updateBy)\r\n    {\r\n        this.updateBy = updateBy;\r\n    }\r\n\r\n    public Date getUpdateTime()\r\n    {\r\n        return updateTime;\r\n    }\r\n\r\n    public void setUpdateTime(Date updateTime)\r\n    {\r\n        this.updateTime = updateTime;\r\n    }\r\n\r\n    public String getRemark()\r\n    {\r\n        return remark;\r\n    }\r\n\r\n    public void setRemark(String remark)\r\n    {\r\n        this.remark = remark;\r\n    }\r\n\r\n    public Map<String, Object> getParams()\r\n    {\r\n        if (params == null)\r\n        {\r\n            params = new HashMap<>();\r\n        }\r\n        return params;\r\n    }\r\n\r\n    public void setParams(Map<String, Object> params)\r\n    {\r\n        this.params = params;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/CxSelect.java",
    "content": "package com.ruoyi.common.core.domain;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.List;\r\n\r\n/**\r\n * CxSelect树结构实体类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class CxSelect implements Serializable\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * 数据值字段名称\r\n     */\r\n    private String v;\r\n\r\n    /**\r\n     * 数据标题字段名称\r\n     */\r\n    private String n;\r\n\r\n    /**\r\n     * 子集数据字段名称\r\n     */\r\n    private List<CxSelect> s;\r\n\r\n    public CxSelect()\r\n    {\r\n    }\r\n\r\n    public CxSelect(String v, String n)\r\n    {\r\n        this.v = v;\r\n        this.n = n;\r\n    }\r\n\r\n    public List<CxSelect> getS()\r\n    {\r\n        return s;\r\n    }\r\n\r\n    public void setN(String n)\r\n    {\r\n        this.n = n;\r\n    }\r\n\r\n    public String getN()\r\n    {\r\n        return n;\r\n    }\r\n\r\n    public void setS(List<CxSelect> s)\r\n    {\r\n        this.s = s;\r\n    }\r\n\r\n    public String getV()\r\n    {\r\n        return v;\r\n    }\r\n\r\n    public void setV(String v)\r\n    {\r\n        this.v = v;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java",
    "content": "package com.ruoyi.common.core.domain;\r\n\r\nimport java.io.Serializable;\r\n\r\n/**\r\n * 响应信息主体\r\n *\r\n * @author ruoyi\r\n */\r\npublic class R<T> implements Serializable\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 成功 */\r\n    public static final int SUCCESS = 0;\r\n\r\n    /** 失败 */\r\n    public static final int FAIL = 500;\r\n\r\n    private int code;\r\n\r\n    private String msg;\r\n\r\n    private T data;\r\n\r\n    public static <T> R<T> ok()\r\n    {\r\n        return restResult(null, SUCCESS, \"操作成功\");\r\n    }\r\n\r\n    public static <T> R<T> ok(T data)\r\n    {\r\n        return restResult(data, SUCCESS, \"操作成功\");\r\n    }\r\n\r\n    public static <T> R<T> ok(T data, String msg)\r\n    {\r\n        return restResult(data, SUCCESS, msg);\r\n    }\r\n\r\n    public static <T> R<T> fail()\r\n    {\r\n        return restResult(null, FAIL, \"操作失败\");\r\n    }\r\n\r\n    public static <T> R<T> fail(String msg)\r\n    {\r\n        return restResult(null, FAIL, msg);\r\n    }\r\n\r\n    public static <T> R<T> fail(T data)\r\n    {\r\n        return restResult(data, FAIL, \"操作失败\");\r\n    }\r\n\r\n    public static <T> R<T> fail(T data, String msg)\r\n    {\r\n        return restResult(data, FAIL, msg);\r\n    }\r\n\r\n    public static <T> R<T> fail(int code, String msg)\r\n    {\r\n        return restResult(null, code, msg);\r\n    }\r\n\r\n    private static <T> R<T> restResult(T data, int code, String msg)\r\n    {\r\n        R<T> apiResult = new R<>();\r\n        apiResult.setCode(code);\r\n        apiResult.setData(data);\r\n        apiResult.setMsg(msg);\r\n        return apiResult;\r\n    }\r\n\r\n    public int getCode()\r\n    {\r\n        return code;\r\n    }\r\n\r\n    public void setCode(int code)\r\n    {\r\n        this.code = code;\r\n    }\r\n\r\n    public String getMsg()\r\n    {\r\n        return msg;\r\n    }\r\n\r\n    public void setMsg(String msg)\r\n    {\r\n        this.msg = msg;\r\n    }\r\n\r\n    public T getData()\r\n    {\r\n        return data;\r\n    }\r\n\r\n    public void setData(T data)\r\n    {\r\n        this.data = data;\r\n    }\r\n\r\n    public static <T> Boolean isError(R<T> ret)\r\n    {\r\n        return !isSuccess(ret);\r\n    }\r\n\r\n    public static <T> Boolean isSuccess(R<T> ret)\r\n    {\r\n        return R.SUCCESS == ret.getCode();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java",
    "content": "package com.ruoyi.common.core.domain;\r\n\r\n/**\r\n * Tree基类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class TreeEntity extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 父菜单名称 */\r\n    private String parentName;\r\n\r\n    /** 父菜单ID */\r\n    private Long parentId;\r\n\r\n    /** 显示顺序 */\r\n    private Integer orderNum;\r\n\r\n    /** 祖级列表 */\r\n    private String ancestors;\r\n\r\n    public String getParentName()\r\n    {\r\n        return parentName;\r\n    }\r\n\r\n    public void setParentName(String parentName)\r\n    {\r\n        this.parentName = parentName;\r\n    }\r\n\r\n    public Long getParentId()\r\n    {\r\n        return parentId;\r\n    }\r\n\r\n    public void setParentId(Long parentId)\r\n    {\r\n        this.parentId = parentId;\r\n    }\r\n\r\n    public Integer getOrderNum()\r\n    {\r\n        return orderNum;\r\n    }\r\n\r\n    public void setOrderNum(Integer orderNum)\r\n    {\r\n        this.orderNum = orderNum;\r\n    }\r\n\r\n    public String getAncestors()\r\n    {\r\n        return ancestors;\r\n    }\r\n\r\n    public void setAncestors(String ancestors)\r\n    {\r\n        this.ancestors = ancestors;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/Ztree.java",
    "content": "package com.ruoyi.common.core.domain;\r\n\r\nimport java.io.Serializable;\r\n\r\n/**\r\n * Ztree树结构实体类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Ztree implements Serializable\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 节点ID */\r\n    private Long id;\r\n\r\n    /** 节点父ID */\r\n    private Long pId;\r\n\r\n    /** 节点名称 */\r\n    private String name;\r\n\r\n    /** 节点标题 */\r\n    private String title;\r\n\r\n    /** 是否勾选 */\r\n    private boolean checked = false;\r\n\r\n    /** 是否展开 */\r\n    private boolean open = false;\r\n\r\n    /** 是否能勾选 */\r\n    private boolean nocheck = false;\r\n\r\n    public Long getId()\r\n    {\r\n        return id;\r\n    }\r\n\r\n    public void setId(Long id)\r\n    {\r\n        this.id = id;\r\n    }\r\n\r\n    public Long getpId()\r\n    {\r\n        return pId;\r\n    }\r\n\r\n    public void setpId(Long pId)\r\n    {\r\n        this.pId = pId;\r\n    }\r\n\r\n    public String getName()\r\n    {\r\n        return name;\r\n    }\r\n\r\n    public void setName(String name)\r\n    {\r\n        this.name = name;\r\n    }\r\n\r\n    public String getTitle()\r\n    {\r\n        return title;\r\n    }\r\n\r\n    public void setTitle(String title)\r\n    {\r\n        this.title = title;\r\n    }\r\n\r\n    public boolean isChecked()\r\n    {\r\n        return checked;\r\n    }\r\n\r\n    public void setChecked(boolean checked)\r\n    {\r\n        this.checked = checked;\r\n    }\r\n\r\n    public boolean isOpen()\r\n    {\r\n        return open;\r\n    }\r\n\r\n    public void setOpen(boolean open)\r\n    {\r\n        this.open = open;\r\n    }\r\n\r\n    public boolean isNocheck()\r\n    {\r\n        return nocheck;\r\n    }\r\n\r\n    public void setNocheck(boolean nocheck)\r\n    {\r\n        this.nocheck = nocheck;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java",
    "content": "package com.ruoyi.common.core.domain.entity;\r\n\r\nimport jakarta.validation.constraints.Email;\r\nimport jakarta.validation.constraints.NotBlank;\r\nimport jakarta.validation.constraints.NotNull;\r\nimport jakarta.validation.constraints.Size;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.fasterxml.jackson.annotation.JsonIgnore;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 部门表 sys_dept\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysDept extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 部门ID */\r\n    private Long deptId;\r\n\r\n    /** 父部门ID */\r\n    private Long parentId;\r\n\r\n    /** 祖级列表 */\r\n    private String ancestors;\r\n\r\n    /** 部门名称 */\r\n    private String deptName;\r\n\r\n    /** 显示顺序 */\r\n    private Integer orderNum;\r\n\r\n    /** 负责人 */\r\n    private String leader;\r\n\r\n    /** 联系电话 */\r\n    private String phone;\r\n\r\n    /** 邮箱 */\r\n    private String email;\r\n\r\n    /** 部门状态:0正常,1停用 */\r\n    private String status;\r\n\r\n    /** 删除标志（0代表存在 2代表删除） */\r\n    private String delFlag;\r\n\r\n    /** 父部门名称 */\r\n    private String parentName;\r\n\r\n    /** 排除编号 */\r\n    private Long excludeId;\r\n\r\n    public Long getDeptId()\r\n    {\r\n        return deptId;\r\n    }\r\n\r\n    public void setDeptId(Long deptId)\r\n    {\r\n        this.deptId = deptId;\r\n    }\r\n\r\n    public Long getParentId()\r\n    {\r\n        return parentId;\r\n    }\r\n\r\n    public void setParentId(Long parentId)\r\n    {\r\n        this.parentId = parentId;\r\n    }\r\n\r\n    public String getAncestors()\r\n    {\r\n        return ancestors;\r\n    }\r\n\r\n    public void setAncestors(String ancestors)\r\n    {\r\n        this.ancestors = ancestors;\r\n    }\r\n\r\n    @NotBlank(message = \"部门名称不能为空\")\r\n    @Size(min = 0, max = 30, message = \"部门名称长度不能超过30个字符\")\r\n    public String getDeptName()\r\n    {\r\n        return deptName;\r\n    }\r\n\r\n    public void setDeptName(String deptName)\r\n    {\r\n        this.deptName = deptName;\r\n    }\r\n\r\n    @NotNull(message = \"显示顺序不能为空\")\r\n    public Integer getOrderNum()\r\n    {\r\n        return orderNum;\r\n    }\r\n\r\n    public void setOrderNum(Integer orderNum)\r\n    {\r\n        this.orderNum = orderNum;\r\n    }\r\n\r\n    public String getLeader()\r\n    {\r\n        return leader;\r\n    }\r\n\r\n    public void setLeader(String leader)\r\n    {\r\n        this.leader = leader;\r\n    }\r\n\r\n    @Size(min = 0, max = 11, message = \"联系电话长度不能超过11个字符\")\r\n    public String getPhone()\r\n    {\r\n        return phone;\r\n    }\r\n\r\n    public void setPhone(String phone)\r\n    {\r\n        this.phone = phone;\r\n    }\r\n\r\n    @Email(message = \"邮箱格式不正确\")\r\n    @Size(min = 0, max = 50, message = \"邮箱长度不能超过50个字符\")\r\n    public String getEmail()\r\n    {\r\n        return email;\r\n    }\r\n\r\n    public void setEmail(String email)\r\n    {\r\n        this.email = email;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public String getDelFlag()\r\n    {\r\n        return delFlag;\r\n    }\r\n\r\n    public void setDelFlag(String delFlag)\r\n    {\r\n        this.delFlag = delFlag;\r\n    }\r\n\r\n    public String getParentName()\r\n    {\r\n        return parentName;\r\n    }\r\n\r\n    public void setParentName(String parentName)\r\n    {\r\n        this.parentName = parentName;\r\n    }\r\n\r\n    @JsonIgnore\r\n    public Long getExcludeId()\r\n    {\r\n        return excludeId;\r\n    }\r\n\r\n    public void setExcludeId(Long excludeId)\r\n    {\r\n        this.excludeId = excludeId;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"deptId\", getDeptId())\r\n            .append(\"parentId\", getParentId())\r\n            .append(\"ancestors\", getAncestors())\r\n            .append(\"deptName\", getDeptName())\r\n            .append(\"orderNum\", getOrderNum())\r\n            .append(\"leader\", getLeader())\r\n            .append(\"phone\", getPhone())\r\n            .append(\"email\", getEmail())\r\n            .append(\"status\", getStatus())\r\n            .append(\"delFlag\", getDelFlag())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java",
    "content": "package com.ruoyi.common.core.domain.entity;\r\n\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 字典数据表 sys_dict_data\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysDictData extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 字典编码 */\r\n    @Excel(name = \"字典编码\", cellType = ColumnType.NUMERIC)\r\n    private Long dictCode;\r\n\r\n    /** 字典排序 */\r\n    @Excel(name = \"字典排序\", cellType = ColumnType.NUMERIC)\r\n    private Long dictSort;\r\n\r\n    /** 字典标签 */\r\n    @Excel(name = \"字典标签\")\r\n    private String dictLabel;\r\n\r\n    /** 字典键值 */\r\n    @Excel(name = \"字典键值\")\r\n    private String dictValue;\r\n\r\n    /** 字典类型 */\r\n    @Excel(name = \"字典类型\")\r\n    private String dictType;\r\n\r\n    /** 样式属性（其他样式扩展） */\r\n    @Excel(name = \"字典样式\")\r\n    private String cssClass;\r\n\r\n    /** 表格字典样式 */\r\n    private String listClass;\r\n\r\n    /** 是否默认（Y是 N否） */\r\n    @Excel(name = \"是否默认\", readConverterExp = \"Y=是,N=否\")\r\n    private String isDefault;\r\n\r\n    /** 状态（0正常 1停用） */\r\n    @Excel(name = \"状态\", readConverterExp = \"0=正常,1=停用\")\r\n    private String status;\r\n\r\n    public Long getDictCode()\r\n    {\r\n        return dictCode;\r\n    }\r\n\r\n    public void setDictCode(Long dictCode)\r\n    {\r\n        this.dictCode = dictCode;\r\n    }\r\n\r\n    public Long getDictSort()\r\n    {\r\n        return dictSort;\r\n    }\r\n\r\n    public void setDictSort(Long dictSort)\r\n    {\r\n        this.dictSort = dictSort;\r\n    }\r\n\r\n    @NotBlank(message = \"字典标签不能为空\")\r\n    @Size(min = 0, max = 100, message = \"字典标签长度不能超过100个字符\")\r\n    public String getDictLabel()\r\n    {\r\n        return dictLabel;\r\n    }\r\n\r\n    public void setDictLabel(String dictLabel)\r\n    {\r\n        this.dictLabel = dictLabel;\r\n    }\r\n\r\n    @NotBlank(message = \"字典键值不能为空\")\r\n    @Size(min = 0, max = 100, message = \"字典键值长度不能超过100个字符\")\r\n    public String getDictValue()\r\n    {\r\n        return dictValue;\r\n    }\r\n\r\n    public void setDictValue(String dictValue)\r\n    {\r\n        this.dictValue = dictValue;\r\n    }\r\n\r\n    @NotBlank(message = \"字典类型不能为空\")\r\n    @Size(min = 0, max = 100, message = \"字典类型长度不能超过100个字符\")\r\n    public String getDictType()\r\n    {\r\n        return dictType;\r\n    }\r\n\r\n    public void setDictType(String dictType)\r\n    {\r\n        this.dictType = dictType;\r\n    }\r\n\r\n    @Size(min = 0, max = 100, message = \"样式属性长度不能超过100个字符\")\r\n    public String getCssClass()\r\n    {\r\n        return cssClass;\r\n    }\r\n\r\n    public void setCssClass(String cssClass)\r\n    {\r\n        this.cssClass = cssClass;\r\n    }\r\n\r\n    public String getListClass()\r\n    {\r\n        return listClass;\r\n    }\r\n\r\n    public void setListClass(String listClass)\r\n    {\r\n        this.listClass = listClass;\r\n    }\r\n\r\n    public boolean getDefault()\r\n    {\r\n        return UserConstants.YES.equals(this.isDefault);\r\n    }\r\n\r\n    public String getIsDefault()\r\n    {\r\n        return isDefault;\r\n    }\r\n\r\n    public void setIsDefault(String isDefault)\r\n    {\r\n        this.isDefault = isDefault;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"dictCode\", getDictCode())\r\n            .append(\"dictSort\", getDictSort())\r\n            .append(\"dictLabel\", getDictLabel())\r\n            .append(\"dictValue\", getDictValue())\r\n            .append(\"dictType\", getDictType())\r\n            .append(\"cssClass\", getCssClass())\r\n            .append(\"listClass\", getListClass())\r\n            .append(\"isDefault\", getIsDefault())\r\n            .append(\"status\", getStatus())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java",
    "content": "package com.ruoyi.common.core.domain.entity;\r\n\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 字典类型表 sys_dict_type\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysDictType extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 字典主键 */\r\n    @Excel(name = \"字典主键\", cellType = ColumnType.NUMERIC)\r\n    private Long dictId;\r\n\r\n    /** 字典名称 */\r\n    @Excel(name = \"字典名称\")\r\n    private String dictName;\r\n\r\n    /** 字典类型 */\r\n    @Excel(name = \"字典类型\")\r\n    private String dictType;\r\n\r\n    /** 状态（0正常 1停用） */\r\n    @Excel(name = \"状态\", readConverterExp = \"0=正常,1=停用\")\r\n    private String status;\r\n\r\n    public Long getDictId()\r\n    {\r\n        return dictId;\r\n    }\r\n\r\n    public void setDictId(Long dictId)\r\n    {\r\n        this.dictId = dictId;\r\n    }\r\n\r\n    @NotBlank(message = \"字典名称不能为空\")\r\n    @Size(min = 0, max = 100, message = \"字典类型名称长度不能超过100个字符\")\r\n    public String getDictName()\r\n    {\r\n        return dictName;\r\n    }\r\n\r\n    public void setDictName(String dictName)\r\n    {\r\n        this.dictName = dictName;\r\n    }\r\n\r\n    @NotBlank(message = \"字典类型不能为空\")\r\n    @Size(min = 0, max = 100, message = \"字典类型类型长度不能超过100个字符\")\r\n    @Pattern(regexp = \"^[a-z][a-z0-9_]*$\", message = \"字典类型必须以字母开头，且只能为（小写字母，数字，下滑线）\")\r\n    public String getDictType()\r\n    {\r\n        return dictType;\r\n    }\r\n\r\n    public void setDictType(String dictType)\r\n    {\r\n        this.dictType = dictType;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"dictId\", getDictId())\r\n            .append(\"dictName\", getDictName())\r\n            .append(\"dictType\", getDictType())\r\n            .append(\"status\", getStatus())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java",
    "content": "package com.ruoyi.common.core.domain.entity;\r\n\r\nimport java.util.List;\r\nimport java.util.ArrayList;\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 菜单权限表 sys_menu\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysMenu extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 菜单ID */\r\n    private Long menuId;\r\n\r\n    /** 菜单名称 */\r\n    private String menuName;\r\n\r\n    /** 父菜单名称 */\r\n    private String parentName;\r\n\r\n    /** 父菜单ID */\r\n    private Long parentId;\r\n\r\n    /** 显示顺序 */\r\n    private String orderNum;\r\n\r\n    /** 菜单URL */\r\n    private String url;\r\n\r\n    /** 打开方式（menuItem页签 menuBlank新窗口） */\r\n    private String target;\r\n\r\n    /** 类型（M目录 C菜单 F按钮） */\r\n    private String menuType;\r\n\r\n    /** 菜单状态（0显示 1隐藏） */\r\n    private String visible;\r\n\r\n    /** 是否刷新（0刷新 1不刷新） */\r\n    private String isRefresh;\r\n\r\n    /** 权限字符串 */\r\n    private String perms;\r\n\r\n    /** 菜单图标 */\r\n    private String icon;\r\n\r\n    /** 子菜单 */\r\n    private List<SysMenu> children = new ArrayList<SysMenu>();\r\n\r\n    public Long getMenuId()\r\n    {\r\n        return menuId;\r\n    }\r\n\r\n    public void setMenuId(Long menuId)\r\n    {\r\n        this.menuId = menuId;\r\n    }\r\n\r\n    @NotBlank(message = \"菜单名称不能为空\")\r\n    @Size(min = 0, max = 50, message = \"菜单名称长度不能超过50个字符\")\r\n    public String getMenuName()\r\n    {\r\n        return menuName;\r\n    }\r\n\r\n    public void setMenuName(String menuName)\r\n    {\r\n        this.menuName = menuName;\r\n    }\r\n\r\n    public String getParentName()\r\n    {\r\n        return parentName;\r\n    }\r\n\r\n    public void setParentName(String parentName)\r\n    {\r\n        this.parentName = parentName;\r\n    }\r\n\r\n    public Long getParentId()\r\n    {\r\n        return parentId;\r\n    }\r\n\r\n    public void setParentId(Long parentId)\r\n    {\r\n        this.parentId = parentId;\r\n    }\r\n\r\n    @NotBlank(message = \"显示顺序不能为空\")\r\n    public String getOrderNum()\r\n    {\r\n        return orderNum;\r\n    }\r\n\r\n    public void setOrderNum(String orderNum)\r\n    {\r\n        this.orderNum = orderNum;\r\n    }\r\n\r\n    @Size(min = 0, max = 200, message = \"请求地址不能超过200个字符\")\r\n    public String getUrl()\r\n    {\r\n        return url;\r\n    }\r\n\r\n    public void setUrl(String url)\r\n    {\r\n        this.url = url;\r\n    }\r\n\r\n    public String getTarget()\r\n    {\r\n        return target;\r\n    }\r\n\r\n    public void setTarget(String target)\r\n    {\r\n        this.target = target;\r\n    }\r\n\r\n    @NotBlank(message = \"菜单类型不能为空\")\r\n    public String getMenuType()\r\n    {\r\n        return menuType;\r\n    }\r\n\r\n    public void setMenuType(String menuType)\r\n    {\r\n        this.menuType = menuType;\r\n    }\r\n\r\n    public String getVisible()\r\n    {\r\n        return visible;\r\n    }\r\n\r\n    public void setVisible(String visible)\r\n    {\r\n        this.visible = visible;\r\n    }\r\n\r\n    public String getIsRefresh()\r\n    {\r\n        return isRefresh;\r\n    }\r\n\r\n    public void setIsRefresh(String isRefresh)\r\n    {\r\n        this.isRefresh = isRefresh;\r\n    }\r\n\r\n    @Size(min = 0, max = 100, message = \"权限标识长度不能超过100个字符\")\r\n    public String getPerms()\r\n    {\r\n        return perms;\r\n    }\r\n\r\n    public void setPerms(String perms)\r\n    {\r\n        this.perms = perms;\r\n    }\r\n\r\n    public String getIcon()\r\n    {\r\n        return icon;\r\n    }\r\n\r\n    public void setIcon(String icon)\r\n    {\r\n        this.icon = icon;\r\n    }\r\n\r\n    public List<SysMenu> getChildren()\r\n    {\r\n        return children;\r\n    }\r\n\r\n    public void setChildren(List<SysMenu> children)\r\n    {\r\n        this.children = children;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"menuId\", getMenuId())\r\n            .append(\"menuName\", getMenuName())\r\n            .append(\"parentId\", getParentId())\r\n            .append(\"orderNum\", getOrderNum())\r\n            .append(\"url\", getUrl())\r\n            .append(\"target\", getTarget())\r\n            .append(\"menuType\", getMenuType())\r\n            .append(\"visible\", getVisible())\r\n            .append(\"perms\", getPerms())\r\n            .append(\"icon\", getIcon())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java",
    "content": "package com.ruoyi.common.core.domain.entity;\r\n\r\nimport java.util.Set;\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 角色表 sys_role\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysRole extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 角色ID */\r\n    @Excel(name = \"角色序号\", cellType = ColumnType.NUMERIC)\r\n    private Long roleId;\r\n\r\n    /** 角色名称 */\r\n    @Excel(name = \"角色名称\")\r\n    private String roleName;\r\n\r\n    /** 角色权限 */\r\n    @Excel(name = \"角色权限\")\r\n    private String roleKey;\r\n\r\n    /** 角色排序 */\r\n    @Excel(name = \"角色排序\", cellType = ColumnType.NUMERIC)\r\n    private String roleSort;\r\n\r\n    /** 数据范围（1：所有数据权限；2：自定义数据权限；3：本部门数据权限；4：本部门及以下数据权限；5：仅本人数据权限） */\r\n    @Excel(name = \"数据范围\", readConverterExp = \"1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限\")\r\n    private String dataScope;\r\n\r\n    /** 角色状态（0正常 1停用） */\r\n    @Excel(name = \"角色状态\", readConverterExp = \"0=正常,1=停用\")\r\n    private String status;\r\n\r\n    /** 删除标志（0代表存在 2代表删除） */\r\n    private String delFlag;\r\n\r\n    /** 用户是否存在此角色标识 默认不存在 */\r\n    private boolean flag = false;\r\n\r\n    /** 菜单组 */\r\n    private Long[] menuIds;\r\n\r\n    /** 部门组（数据权限） */\r\n    private Long[] deptIds;\r\n\r\n    /** 角色菜单权限 */\r\n    private Set<String> permissions;\r\n\r\n    public SysRole()\r\n    {\r\n\r\n    }\r\n\r\n    public SysRole(Long roleId)\r\n    {\r\n        this.roleId = roleId;\r\n    }\r\n\r\n    public Long getRoleId()\r\n    {\r\n        return roleId;\r\n    }\r\n\r\n    public void setRoleId(Long roleId)\r\n    {\r\n        this.roleId = roleId;\r\n    }\r\n\r\n    public boolean isAdmin()\r\n    {\r\n        return isAdmin(this.roleId);\r\n    }\r\n\r\n    public static boolean isAdmin(Long roleId)\r\n    {\r\n        return roleId != null && 1L == roleId;\r\n    }\r\n\r\n    public String getDataScope()\r\n    {\r\n        return dataScope;\r\n    }\r\n\r\n    public void setDataScope(String dataScope)\r\n    {\r\n        this.dataScope = dataScope;\r\n    }\r\n\r\n    @NotBlank(message = \"角色名称不能为空\")\r\n    @Size(min = 0, max = 30, message = \"角色名称长度不能超过30个字符\")\r\n    public String getRoleName()\r\n    {\r\n        return roleName;\r\n    }\r\n\r\n    public void setRoleName(String roleName)\r\n    {\r\n        this.roleName = roleName;\r\n    }\r\n\r\n    @NotBlank(message = \"权限字符不能为空\")\r\n    @Size(min = 0, max = 100, message = \"权限字符长度不能超过100个字符\")\r\n    public String getRoleKey()\r\n    {\r\n        return roleKey;\r\n    }\r\n\r\n    public void setRoleKey(String roleKey)\r\n    {\r\n        this.roleKey = roleKey;\r\n    }\r\n\r\n    @NotBlank(message = \"显示顺序不能为空\")\r\n    public String getRoleSort()\r\n    {\r\n        return roleSort;\r\n    }\r\n\r\n    public void setRoleSort(String roleSort)\r\n    {\r\n        this.roleSort = roleSort;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public String getDelFlag()\r\n    {\r\n        return delFlag;\r\n    }\r\n\r\n    public void setDelFlag(String delFlag)\r\n    {\r\n        this.delFlag = delFlag;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public boolean isFlag()\r\n    {\r\n        return flag;\r\n    }\r\n\r\n    public void setFlag(boolean flag)\r\n    {\r\n        this.flag = flag;\r\n    }\r\n\r\n    public Long[] getMenuIds()\r\n    {\r\n        return menuIds;\r\n    }\r\n\r\n    public void setMenuIds(Long[] menuIds)\r\n    {\r\n        this.menuIds = menuIds;\r\n    }\r\n\r\n    public Long[] getDeptIds()\r\n    {\r\n        return deptIds;\r\n    }\r\n\r\n    public void setDeptIds(Long[] deptIds)\r\n    {\r\n        this.deptIds = deptIds;\r\n    }\r\n\r\n    public Set<String> getPermissions()\r\n    {\r\n        return permissions;\r\n    }\r\n\r\n    public void setPermissions(Set<String> permissions)\r\n    {\r\n        this.permissions = permissions;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"roleId\", getRoleId())\r\n            .append(\"roleName\", getRoleName())\r\n            .append(\"roleKey\", getRoleKey())\r\n            .append(\"roleSort\", getRoleSort())\r\n            .append(\"dataScope\", getDataScope())\r\n            .append(\"status\", getStatus())\r\n            .append(\"delFlag\", getDelFlag())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java",
    "content": "package com.ruoyi.common.core.domain.entity;\r\n\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.fasterxml.jackson.annotation.JsonIgnore;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.annotation.Excel.Type;\r\nimport com.ruoyi.common.annotation.Excels;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.xss.Xss;\r\n\r\n/**\r\n * 用户对象 sys_user\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysUser extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 用户ID */\r\n    @Excel(name = \"用户序号\", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = \"用户编号\")\r\n    private Long userId;\r\n\r\n    /** 部门ID */\r\n    @Excel(name = \"部门编号\", type = Type.IMPORT)\r\n    private Long deptId;\r\n\r\n    /** 部门父ID */\r\n    private Long parentId;\r\n\r\n    /** 角色ID */\r\n    private Long roleId;\r\n\r\n    /** 登录名称 */\r\n    @Excel(name = \"登录名称\")\r\n    private String loginName;\r\n\r\n    /** 用户名称 */\r\n    @Excel(name = \"用户名称\")\r\n    private String userName;\r\n\r\n    /** 用户类型 */\r\n    private String userType;\r\n\r\n    /** 用户邮箱 */\r\n    @Excel(name = \"用户邮箱\")\r\n    private String email;\r\n\r\n    /** 手机号码 */\r\n    @Excel(name = \"手机号码\", cellType = ColumnType.TEXT)\r\n    private String phonenumber;\r\n\r\n    /** 用户性别 */\r\n    @Excel(name = \"用户性别\", readConverterExp = \"0=男,1=女,2=未知\")\r\n    private String sex;\r\n\r\n    /** 用户头像 */\r\n    private String avatar;\r\n\r\n    /** 密码 */\r\n    private String password;\r\n\r\n    /** 盐加密 */\r\n    private String salt;\r\n\r\n    /** 账号状态（0正常 1停用） */\r\n    @Excel(name = \"账号状态\", readConverterExp = \"0=正常,1=停用\")\r\n    private String status;\r\n\r\n    /** 删除标志（0代表存在 2代表删除） */\r\n    private String delFlag;\r\n\r\n    /** 最后登录IP */\r\n    @Excel(name = \"最后登录IP\", type = Type.EXPORT)\r\n    private String loginIp;\r\n\r\n    /** 最后登录时间 */\r\n    @Excel(name = \"最后登录时间\", width = 30, dateFormat = \"yyyy-MM-dd HH:mm:ss\", type = Type.EXPORT)\r\n    private Date loginDate;\r\n\r\n    /** 密码最后更新时间 */\r\n    private Date pwdUpdateDate;\r\n\r\n    /** 部门对象 */\r\n    @Excels({\r\n        @Excel(name = \"部门名称\", targetAttr = \"deptName\", type = Type.EXPORT),\r\n        @Excel(name = \"部门负责人\", targetAttr = \"leader\", type = Type.EXPORT)\r\n    })\r\n    private SysDept dept;\r\n\r\n    private List<SysRole> roles;\r\n\r\n    /** 角色组 */\r\n    private Long[] roleIds;\r\n\r\n    /** 岗位组 */\r\n    private Long[] postIds;\r\n\r\n    public SysUser()\r\n    {\r\n\r\n    }\r\n\r\n    public SysUser(Long userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public Long getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n\r\n    public void setUserId(Long userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public boolean isAdmin()\r\n    {\r\n        return ShiroUtils.isAdmin(this.userId);\r\n    }\r\n\r\n    public Long getDeptId()\r\n    {\r\n        return deptId;\r\n    }\r\n\r\n    public void setDeptId(Long deptId)\r\n    {\r\n        this.deptId = deptId;\r\n    }\r\n\r\n    public Long getParentId()\r\n    {\r\n        return parentId;\r\n    }\r\n\r\n    public void setParentId(Long parentId)\r\n    {\r\n        this.parentId = parentId;\r\n    }\r\n\r\n    public Long getRoleId()\r\n    {\r\n        return roleId;\r\n    }\r\n\r\n    public void setRoleId(Long roleId)\r\n    {\r\n        this.roleId = roleId;\r\n    }\r\n\r\n    @Xss(message = \"登录账号不能包含脚本字符\")\r\n    @NotBlank(message = \"登录账号不能为空\")\r\n    @Size(min = 0, max = 30, message = \"登录账号长度不能超过30个字符\")\r\n    public String getLoginName()\r\n    {\r\n        return loginName;\r\n    }\r\n\r\n    public void setLoginName(String loginName)\r\n    {\r\n        this.loginName = loginName;\r\n    }\r\n\r\n    @Xss(message = \"用户昵称不能包含脚本字符\")\r\n    @Size(min = 0, max = 30, message = \"用户昵称长度不能超过30个字符\")\r\n    public String getUserName()\r\n    {\r\n        return userName;\r\n    }\r\n\r\n    public void setUserName(String userName)\r\n    {\r\n        this.userName = userName;\r\n    }\r\n\r\n    public String getUserType()\r\n    {\r\n        return userType;\r\n    }\r\n\r\n    public void setUserType(String userType)\r\n    {\r\n        this.userType = userType;\r\n    }\r\n\r\n    @Email(message = \"邮箱格式不正确\")\r\n    @Size(min = 0, max = 50, message = \"邮箱长度不能超过50个字符\")\r\n    public String getEmail()\r\n    {\r\n        return email;\r\n    }\r\n\r\n    public void setEmail(String email)\r\n    {\r\n        this.email = email;\r\n    }\r\n\r\n    @Size(min = 0, max = 11, message = \"手机号码长度不能超过11个字符\")\r\n    public String getPhonenumber()\r\n    {\r\n        return phonenumber;\r\n    }\r\n\r\n    public void setPhonenumber(String phonenumber)\r\n    {\r\n        this.phonenumber = phonenumber;\r\n    }\r\n\r\n    public String getSex()\r\n    {\r\n        return sex;\r\n    }\r\n\r\n    public void setSex(String sex)\r\n    {\r\n        this.sex = sex;\r\n    }\r\n\r\n    public String getAvatar()\r\n    {\r\n        return avatar;\r\n    }\r\n\r\n    public void setAvatar(String avatar)\r\n    {\r\n        this.avatar = avatar;\r\n    }\r\n\r\n    @JsonIgnore\r\n    public String getPassword()\r\n    {\r\n        return password;\r\n    }\r\n\r\n    public void setPassword(String password)\r\n    {\r\n        this.password = password;\r\n    }\r\n\r\n    @JsonIgnore\r\n    public String getSalt()\r\n    {\r\n        return salt;\r\n    }\r\n\r\n    public void setSalt(String salt)\r\n    {\r\n        this.salt = salt;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public String getDelFlag()\r\n    {\r\n        return delFlag;\r\n    }\r\n\r\n    public void setDelFlag(String delFlag)\r\n    {\r\n        this.delFlag = delFlag;\r\n    }\r\n\r\n    public String getLoginIp()\r\n    {\r\n        return loginIp;\r\n    }\r\n\r\n    public void setLoginIp(String loginIp)\r\n    {\r\n        this.loginIp = loginIp;\r\n    }\r\n\r\n    public Date getLoginDate()\r\n    {\r\n        return loginDate;\r\n    }\r\n\r\n    public void setLoginDate(Date loginDate)\r\n    {\r\n        this.loginDate = loginDate;\r\n    }\r\n\r\n    public Date getPwdUpdateDate()\r\n    {\r\n        return pwdUpdateDate;\r\n    }\r\n\r\n    public void setPwdUpdateDate(Date pwdUpdateDate)\r\n    {\r\n        this.pwdUpdateDate = pwdUpdateDate;\r\n    }\r\n\r\n    public SysDept getDept()\r\n    {\r\n        if (dept == null)\r\n        {\r\n            dept = new SysDept();\r\n        }\r\n        return dept;\r\n    }\r\n\r\n    public void setDept(SysDept dept)\r\n    {\r\n        this.dept = dept;\r\n    }\r\n\r\n    public List<SysRole> getRoles()\r\n    {\r\n        return roles;\r\n    }\r\n\r\n    public void setRoles(List<SysRole> roles)\r\n    {\r\n        this.roles = roles;\r\n    }\r\n\r\n    public Long[] getRoleIds()\r\n    {\r\n        return roleIds;\r\n    }\r\n\r\n    public void setRoleIds(Long[] roleIds)\r\n    {\r\n        this.roleIds = roleIds;\r\n    }\r\n\r\n    public Long[] getPostIds()\r\n    {\r\n        return postIds;\r\n    }\r\n\r\n    public void setPostIds(Long[] postIds)\r\n    {\r\n        this.postIds = postIds;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"userId\", getUserId())\r\n            .append(\"deptId\", getDeptId())\r\n            .append(\"loginName\", getLoginName())\r\n            .append(\"userName\", getUserName())\r\n            .append(\"userType\", getUserType())\r\n            .append(\"email\", getEmail())\r\n            .append(\"phonenumber\", getPhonenumber())\r\n            .append(\"sex\", getSex())\r\n            .append(\"avatar\", getAvatar())\r\n            .append(\"password\", getPassword())\r\n            .append(\"salt\", getSalt())\r\n            .append(\"status\", getStatus())\r\n            .append(\"delFlag\", getDelFlag())\r\n            .append(\"loginIp\", getLoginIp())\r\n            .append(\"loginDate\", getLoginDate())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .append(\"dept\", getDept())\r\n\t\t\t.append(\"roles\", getRoles())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java",
    "content": "package com.ruoyi.common.core.page;\r\n\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 分页数据\r\n * \r\n * @author ruoyi\r\n */\r\npublic class PageDomain\r\n{\r\n    /** 当前记录起始索引 */\r\n    private Integer pageNum;\r\n\r\n    /** 每页显示记录数 */\r\n    private Integer pageSize;\r\n\r\n    /** 排序列 */\r\n    private String orderByColumn;\r\n\r\n    /** 排序的方向desc或者asc */\r\n    private String isAsc = \"asc\";\r\n\r\n    /** 分页参数合理化 */\r\n    private Boolean reasonable = true;\r\n\r\n    public String getOrderBy()\r\n    {\r\n        if (StringUtils.isEmpty(orderByColumn))\r\n        {\r\n            return \"\";\r\n        }\r\n        return StringUtils.toUnderScoreCase(orderByColumn) + \" \" + isAsc;\r\n    }\r\n\r\n    public Integer getPageNum()\r\n    {\r\n        return pageNum;\r\n    }\r\n\r\n    public void setPageNum(Integer pageNum)\r\n    {\r\n        this.pageNum = pageNum;\r\n    }\r\n\r\n    public Integer getPageSize()\r\n    {\r\n        return pageSize;\r\n    }\r\n\r\n    public void setPageSize(Integer pageSize)\r\n    {\r\n        this.pageSize = pageSize;\r\n    }\r\n\r\n    public String getOrderByColumn()\r\n    {\r\n        return orderByColumn;\r\n    }\r\n\r\n    public void setOrderByColumn(String orderByColumn)\r\n    {\r\n        this.orderByColumn = orderByColumn;\r\n    }\r\n\r\n    public String getIsAsc()\r\n    {\r\n        return isAsc;\r\n    }\r\n\r\n    public void setIsAsc(String isAsc)\r\n    {\r\n        this.isAsc = isAsc;\r\n    }\r\n\r\n    public Boolean getReasonable()\r\n    {\r\n        if (StringUtils.isNull(reasonable))\r\n        {\r\n            return Boolean.TRUE;\r\n        }\r\n        return reasonable;\r\n    }\r\n\r\n    public void setReasonable(Boolean reasonable)\r\n    {\r\n        this.reasonable = reasonable;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java",
    "content": "package com.ruoyi.common.core.page;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.List;\r\n\r\n/**\r\n * 表格分页数据对象\r\n * \r\n * @author ruoyi\r\n */\r\npublic class TableDataInfo implements Serializable\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 总记录数 */\r\n    private long total;\r\n\r\n    /** 列表数据 */\r\n    private List<?> rows;\r\n\r\n    /** 消息状态码 */\r\n    private int code;\r\n\r\n    /** 消息内容 */\r\n    private String msg;\r\n\r\n    /**\r\n     * 表格数据对象\r\n     */\r\n    public TableDataInfo()\r\n    {\r\n    }\r\n\r\n    /**\r\n     * 分页\r\n     * \r\n     * @param list 列表数据\r\n     * @param total 总记录数\r\n     */\r\n    public TableDataInfo(List<?> list, long total)\r\n    {\r\n        this.rows = list;\r\n        this.total = total;\r\n    }\r\n\r\n    public long getTotal()\r\n    {\r\n        return total;\r\n    }\r\n\r\n    public void setTotal(long total)\r\n    {\r\n        this.total = total;\r\n    }\r\n\r\n    public List<?> getRows()\r\n    {\r\n        return rows;\r\n    }\r\n\r\n    public void setRows(List<?> rows)\r\n    {\r\n        this.rows = rows;\r\n    }\r\n\r\n    public int getCode()\r\n    {\r\n        return code;\r\n    }\r\n\r\n    public void setCode(int code)\r\n    {\r\n        this.code = code;\r\n    }\r\n\r\n    public String getMsg()\r\n    {\r\n        return msg;\r\n    }\r\n\r\n    public void setMsg(String msg)\r\n    {\r\n        this.msg = msg;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java",
    "content": "package com.ruoyi.common.core.page;\r\n\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\n\r\n/**\r\n * 表格数据处理\r\n * \r\n * @author ruoyi\r\n */\r\npublic class TableSupport\r\n{\r\n    /**\r\n     * 当前记录起始索引\r\n     */\r\n    public static final String PAGE_NUM = \"pageNum\";\r\n\r\n    /**\r\n     * 每页显示记录数\r\n     */\r\n    public static final String PAGE_SIZE = \"pageSize\";\r\n\r\n    /**\r\n     * 排序列\r\n     */\r\n    public static final String ORDER_BY_COLUMN = \"orderByColumn\";\r\n\r\n    /**\r\n     * 排序的方向 \"desc\" 或者 \"asc\".\r\n     */\r\n    public static final String IS_ASC = \"isAsc\";\r\n\r\n    /**\r\n     * 分页参数合理化\r\n     */\r\n    public static final String REASONABLE = \"reasonable\";\r\n\r\n    /**\r\n     * 封装分页对象\r\n     */\r\n    public static PageDomain getPageDomain()\r\n    {\r\n        PageDomain pageDomain = new PageDomain();\r\n        pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));\r\n        pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));\r\n        pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));\r\n        pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));\r\n        pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));\r\n        return pageDomain;\r\n    }\r\n\r\n    public static PageDomain buildPageRequest()\r\n    {\r\n        return getPageDomain();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/session/OnlineSession.java",
    "content": "package com.ruoyi.common.core.session;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport org.apache.shiro.session.mgt.SimpleSession;\r\nimport com.ruoyi.common.enums.OnlineStatus;\r\n\r\n/**\r\n * 在线用户会话属性\r\n * \r\n * @author ruoyi\r\n */\r\npublic class OnlineSession extends SimpleSession\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 用户ID */\r\n    private Long userId;\r\n\r\n    /** 用户名称 */\r\n    private String loginName;\r\n\r\n    /** 部门名称 */\r\n    private String deptName;\r\n\t\r\n\t/** 用户头像 */\r\n\tprivate String avatar;\r\n\r\n    /** 登录IP地址 */\r\n    private String host;\r\n\r\n    /** 浏览器类型 */\r\n    private String browser;\r\n\r\n    /** 操作系统 */\r\n    private String os;\r\n\r\n    /** 在线状态 */\r\n    private OnlineStatus status = OnlineStatus.on_line;\r\n\r\n    /** 属性是否改变 优化session数据同步 */\r\n    private transient boolean attributeChanged = false;\r\n\r\n    @Override\r\n    public String getHost()\r\n    {\r\n        return host;\r\n    }\r\n\r\n    @Override\r\n    public void setHost(String host)\r\n    {\r\n        this.host = host;\r\n    }\r\n\r\n    public String getBrowser()\r\n    {\r\n        return browser;\r\n    }\r\n\r\n    public void setBrowser(String browser)\r\n    {\r\n        this.browser = browser;\r\n    }\r\n\r\n    public String getOs()\r\n    {\r\n        return os;\r\n    }\r\n\r\n    public void setOs(String os)\r\n    {\r\n        this.os = os;\r\n    }\r\n\r\n    public Long getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n\r\n    public void setUserId(Long userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public String getLoginName()\r\n    {\r\n        return loginName;\r\n    }\r\n\r\n    public void setLoginName(String loginName)\r\n    {\r\n        this.loginName = loginName;\r\n    }\r\n\r\n    public String getDeptName()\r\n    {\r\n        return deptName;\r\n    }\r\n\r\n    public void setDeptName(String deptName)\r\n    {\r\n        this.deptName = deptName;\r\n    }\r\n\r\n    public OnlineStatus getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(OnlineStatus status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public void markAttributeChanged()\r\n    {\r\n        this.attributeChanged = true;\r\n    }\r\n\r\n    public void resetAttributeChanged()\r\n    {\r\n        this.attributeChanged = false;\r\n    }\r\n\r\n    public boolean isAttributeChanged()\r\n    {\r\n        return attributeChanged;\r\n    }\r\n\r\n\tpublic String getAvatar() {\r\n\t\treturn avatar;\r\n\t}\r\n\r\n\tpublic void setAvatar(String avatar) {\r\n\t\tthis.avatar = avatar;\r\n\t}\r\n\t\r\n    @Override\r\n    public void setAttribute(Object key, Object value)\r\n    {\r\n        super.setAttribute(key, value);\r\n    }\r\n\r\n    @Override\r\n    public Object removeAttribute(Object key)\r\n    {\r\n        return super.removeAttribute(key);\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"userId\", getUserId())\r\n            .append(\"loginName\", getLoginName())\r\n            .append(\"deptName\", getDeptName())\r\n            .append(\"avatar\", getAvatar())\r\n            .append(\"host\", getHost())\r\n            .append(\"browser\", getBrowser())\r\n            .append(\"os\", getOs())\r\n            .append(\"status\", getStatus())\r\n            .append(\"attributeChanged\", isAttributeChanged())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java",
    "content": "package com.ruoyi.common.core.text;\r\n\r\nimport java.nio.charset.Charset;\r\nimport java.nio.charset.StandardCharsets;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 字符集工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class CharsetKit\r\n{\r\n    /** ISO-8859-1 */\r\n    public static final String ISO_8859_1 = \"ISO-8859-1\";\r\n    /** UTF-8 */\r\n    public static final String UTF_8 = \"UTF-8\";\r\n    /** GBK */\r\n    public static final String GBK = \"GBK\";\r\n\r\n    /** ISO-8859-1 */\r\n    public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);\r\n    /** UTF-8 */\r\n    public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);\r\n    /** GBK */\r\n    public static final Charset CHARSET_GBK = Charset.forName(GBK);\r\n\r\n    /**\r\n     * 转换为Charset对象\r\n     * \r\n     * @param charset 字符集，为空则返回默认字符集\r\n     * @return Charset\r\n     */\r\n    public static Charset charset(String charset)\r\n    {\r\n        return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);\r\n    }\r\n\r\n    /**\r\n     * 转换字符串的字符集编码\r\n     * \r\n     * @param source 字符串\r\n     * @param srcCharset 源字符集，默认ISO-8859-1\r\n     * @param destCharset 目标字符集，默认UTF-8\r\n     * @return 转换后的字符集\r\n     */\r\n    public static String convert(String source, String srcCharset, String destCharset)\r\n    {\r\n        return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));\r\n    }\r\n\r\n    /**\r\n     * 转换字符串的字符集编码\r\n     * \r\n     * @param source 字符串\r\n     * @param srcCharset 源字符集，默认ISO-8859-1\r\n     * @param destCharset 目标字符集，默认UTF-8\r\n     * @return 转换后的字符集\r\n     */\r\n    public static String convert(String source, Charset srcCharset, Charset destCharset)\r\n    {\r\n        if (null == srcCharset)\r\n        {\r\n            srcCharset = StandardCharsets.ISO_8859_1;\r\n        }\r\n\r\n        if (null == destCharset)\r\n        {\r\n            destCharset = StandardCharsets.UTF_8;\r\n        }\r\n\r\n        if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))\r\n        {\r\n            return source;\r\n        }\r\n        return new String(source.getBytes(srcCharset), destCharset);\r\n    }\r\n\r\n    /**\r\n     * @return 系统字符集编码\r\n     */\r\n    public static String systemCharset()\r\n    {\r\n        return Charset.defaultCharset().name();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/text/Convert.java",
    "content": "package com.ruoyi.common.core.text;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.math.BigInteger;\r\nimport java.math.RoundingMode;\r\nimport java.nio.ByteBuffer;\r\nimport java.nio.charset.Charset;\r\nimport java.text.NumberFormat;\r\nimport java.util.Set;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport org.apache.commons.lang3.ArrayUtils;\r\n\r\n/**\r\n * 类型转换器\r\n *\r\n * @author ruoyi\r\n */\r\npublic class Convert\r\n{\r\n    /**\r\n     * 转换为字符串<br>\r\n     * 如果给定的值为null，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static String toStr(Object value, String defaultValue)\r\n    {\r\n        if (null == value)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof String)\r\n        {\r\n            return (String) value;\r\n        }\r\n        return value.toString();\r\n    }\r\n\r\n    /**\r\n     * 转换为字符串<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static String toStr(Object value)\r\n    {\r\n        return toStr(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为字符<br>\r\n     * 如果给定的值为null，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Character toChar(Object value, Character defaultValue)\r\n    {\r\n        if (null == value)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Character)\r\n        {\r\n            return (Character) value;\r\n        }\r\n\r\n        final String valueStr = toStr(value, null);\r\n        return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);\r\n    }\r\n\r\n    /**\r\n     * 转换为字符<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Character toChar(Object value)\r\n    {\r\n        return toChar(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为byte<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Byte toByte(Object value, Byte defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Byte)\r\n        {\r\n            return (Byte) value;\r\n        }\r\n        if (value instanceof Number)\r\n        {\r\n            return ((Number) value).byteValue();\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return Byte.parseByte(valueStr);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为byte<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Byte toByte(Object value)\r\n    {\r\n        return toByte(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为Short<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Short toShort(Object value, Short defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Short)\r\n        {\r\n            return (Short) value;\r\n        }\r\n        if (value instanceof Number)\r\n        {\r\n            return ((Number) value).shortValue();\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return Short.parseShort(valueStr.trim());\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为Short<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Short toShort(Object value)\r\n    {\r\n        return toShort(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为Number<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Number toNumber(Object value, Number defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Number)\r\n        {\r\n            return (Number) value;\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return NumberFormat.getInstance().parse(valueStr);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为Number<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Number toNumber(Object value)\r\n    {\r\n        return toNumber(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为int<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Integer toInt(Object value, Integer defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Integer)\r\n        {\r\n            return (Integer) value;\r\n        }\r\n        if (value instanceof Number)\r\n        {\r\n            return ((Number) value).intValue();\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return Integer.parseInt(valueStr.trim());\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为int<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Integer toInt(Object value)\r\n    {\r\n        return toInt(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为Integer数组<br>\r\n     *\r\n     * @param str 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Integer[] toIntArray(String str)\r\n    {\r\n        return toIntArray(\",\", str);\r\n    }\r\n\r\n    /**\r\n     * 转换为Long数组<br>\r\n     *\r\n     * @param str 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Long[] toLongArray(String str)\r\n    {\r\n        return toLongArray(\",\", str);\r\n    }\r\n\r\n    /**\r\n     * 转换为Integer数组<br>\r\n     *\r\n     * @param split 分隔符\r\n     * @param split 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Integer[] toIntArray(String split, String str)\r\n    {\r\n        if (StringUtils.isEmpty(str))\r\n        {\r\n            return new Integer[] {};\r\n        }\r\n        String[] arr = str.split(split);\r\n        final Integer[] ints = new Integer[arr.length];\r\n        for (int i = 0; i < arr.length; i++)\r\n        {\r\n            final Integer v = toInt(arr[i], 0);\r\n            ints[i] = v;\r\n        }\r\n        return ints;\r\n    }\r\n\r\n    /**\r\n     * 转换为Long数组<br>\r\n     *\r\n     * @param split 分隔符\r\n     * @param str 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Long[] toLongArray(String split, String str)\r\n    {\r\n        if (StringUtils.isEmpty(str))\r\n        {\r\n            return new Long[] {};\r\n        }\r\n        String[] arr = str.split(split);\r\n        final Long[] longs = new Long[arr.length];\r\n        for (int i = 0; i < arr.length; i++)\r\n        {\r\n            final Long v = toLong(arr[i], null);\r\n            longs[i] = v;\r\n        }\r\n        return longs;\r\n    }\r\n\r\n    /**\r\n     * 转换为String数组<br>\r\n     *\r\n     * @param str 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static String[] toStrArray(String str)\r\n    {\r\n        if (StringUtils.isEmpty(str))\r\n        {\r\n            return new String[] {};\r\n        }\r\n        return toStrArray(\",\", str);\r\n    }\r\n\r\n    /**\r\n     * 转换为String数组<br>\r\n     *\r\n     * @param split 分隔符\r\n     * @param split 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static String[] toStrArray(String split, String str)\r\n    {\r\n        return str.split(split);\r\n    }\r\n\r\n    /**\r\n     * 转换为long<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Long toLong(Object value, Long defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Long)\r\n        {\r\n            return (Long) value;\r\n        }\r\n        if (value instanceof Number)\r\n        {\r\n            return ((Number) value).longValue();\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            // 支持科学计数法\r\n            return new BigDecimal(valueStr.trim()).longValue();\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为long<br>\r\n     * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Long toLong(Object value)\r\n    {\r\n        return toLong(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为double<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Double toDouble(Object value, Double defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Double)\r\n        {\r\n            return (Double) value;\r\n        }\r\n        if (value instanceof Number)\r\n        {\r\n            return ((Number) value).doubleValue();\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            // 支持科学计数法\r\n            return new BigDecimal(valueStr.trim()).doubleValue();\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为double<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Double toDouble(Object value)\r\n    {\r\n        return toDouble(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为Float<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Float toFloat(Object value, Float defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Float)\r\n        {\r\n            return (Float) value;\r\n        }\r\n        if (value instanceof Number)\r\n        {\r\n            return ((Number) value).floatValue();\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return Float.parseFloat(valueStr.trim());\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为Float<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Float toFloat(Object value)\r\n    {\r\n        return toFloat(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为boolean<br>\r\n     * String支持的值为：true、false、yes、ok、no，1,0 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static Boolean toBool(Object value, Boolean defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof Boolean)\r\n        {\r\n            return (Boolean) value;\r\n        }\r\n        String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        valueStr = valueStr.trim().toLowerCase();\r\n        switch (valueStr)\r\n        {\r\n            case \"true\":\r\n            case \"yes\":\r\n            case \"ok\":\r\n            case \"1\":\r\n                return true;\r\n            case \"false\":\r\n            case \"no\":\r\n            case \"0\":\r\n                return false;\r\n            default:\r\n                return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为boolean<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static Boolean toBool(Object value)\r\n    {\r\n        return toBool(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为Enum对象<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     *\r\n     * @param clazz Enum的Class\r\n     * @param value 值\r\n     * @param defaultValue 默认值\r\n     * @return Enum\r\n     */\r\n    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (clazz.isAssignableFrom(value.getClass()))\r\n        {\r\n            @SuppressWarnings(\"unchecked\")\r\n            E myE = (E) value;\r\n            return myE;\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return Enum.valueOf(clazz, valueStr);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为Enum对象<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\r\n     *\r\n     * @param clazz Enum的Class\r\n     * @param value 值\r\n     * @return Enum\r\n     */\r\n    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)\r\n    {\r\n        return toEnum(clazz, value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为BigInteger<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static BigInteger toBigInteger(Object value, BigInteger defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof BigInteger)\r\n        {\r\n            return (BigInteger) value;\r\n        }\r\n        if (value instanceof Long)\r\n        {\r\n            return BigInteger.valueOf((Long) value);\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return new BigInteger(valueStr);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为BigInteger<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static BigInteger toBigInteger(Object value)\r\n    {\r\n        return toBigInteger(value, null);\r\n    }\r\n\r\n    /**\r\n     * 转换为BigDecimal<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @param defaultValue 转换错误时的默认值\r\n     * @return 结果\r\n     */\r\n    public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)\r\n    {\r\n        if (value == null)\r\n        {\r\n            return defaultValue;\r\n        }\r\n        if (value instanceof BigDecimal)\r\n        {\r\n            return (BigDecimal) value;\r\n        }\r\n        if (value instanceof Long)\r\n        {\r\n            return new BigDecimal((Long) value);\r\n        }\r\n        if (value instanceof Double)\r\n        {\r\n            return BigDecimal.valueOf((Double) value);\r\n        }\r\n        if (value instanceof Integer)\r\n        {\r\n            return new BigDecimal((Integer) value);\r\n        }\r\n        final String valueStr = toStr(value, null);\r\n        if (StringUtils.isEmpty(valueStr))\r\n        {\r\n            return defaultValue;\r\n        }\r\n        try\r\n        {\r\n            return new BigDecimal(valueStr);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            return defaultValue;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为BigDecimal<br>\r\n     * 如果给定的值为空，或者转换失败，返回默认值<br>\r\n     * 转换失败不会报错\r\n     *\r\n     * @param value 被转换的值\r\n     * @return 结果\r\n     */\r\n    public static BigDecimal toBigDecimal(Object value)\r\n    {\r\n        return toBigDecimal(value, null);\r\n    }\r\n\r\n    /**\r\n     * 将对象转为字符串<br>\r\n     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法\r\n     *\r\n     * @param obj 对象\r\n     * @return 字符串\r\n     */\r\n    public static String utf8Str(Object obj)\r\n    {\r\n        return str(obj, CharsetKit.CHARSET_UTF_8);\r\n    }\r\n\r\n    /**\r\n     * 将对象转为字符串<br>\r\n     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法\r\n     *\r\n     * @param obj 对象\r\n     * @param charsetName 字符集\r\n     * @return 字符串\r\n     */\r\n    public static String str(Object obj, String charsetName)\r\n    {\r\n        return str(obj, Charset.forName(charsetName));\r\n    }\r\n\r\n    /**\r\n     * 将对象转为字符串<br>\r\n     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法\r\n     *\r\n     * @param obj 对象\r\n     * @param charset 字符集\r\n     * @return 字符串\r\n     */\r\n    public static String str(Object obj, Charset charset)\r\n    {\r\n        if (null == obj)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        if (obj instanceof String)\r\n        {\r\n            return (String) obj;\r\n        }\r\n        else if (obj instanceof byte[])\r\n        {\r\n            return str((byte[]) obj, charset);\r\n        }\r\n        else if (obj instanceof Byte[])\r\n        {\r\n            byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);\r\n            return str(bytes, charset);\r\n        }\r\n        else if (obj instanceof ByteBuffer)\r\n        {\r\n            return str((ByteBuffer) obj, charset);\r\n        }\r\n        return obj.toString();\r\n    }\r\n\r\n    /**\r\n     * 将byte数组转为字符串\r\n     *\r\n     * @param bytes byte数组\r\n     * @param charset 字符集\r\n     * @return 字符串\r\n     */\r\n    public static String str(byte[] bytes, String charset)\r\n    {\r\n        return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));\r\n    }\r\n\r\n    /**\r\n     * 解码字节码\r\n     *\r\n     * @param data 字符串\r\n     * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\r\n     * @return 解码后的字符串\r\n     */\r\n    public static String str(byte[] data, Charset charset)\r\n    {\r\n        if (data == null)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        if (null == charset)\r\n        {\r\n            return new String(data);\r\n        }\r\n        return new String(data, charset);\r\n    }\r\n\r\n    /**\r\n     * 将编码的byteBuffer数据转换为字符串\r\n     *\r\n     * @param data 数据\r\n     * @param charset 字符集，如果为空使用当前系统字符集\r\n     * @return 字符串\r\n     */\r\n    public static String str(ByteBuffer data, String charset)\r\n    {\r\n        if (data == null)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        return str(data, Charset.forName(charset));\r\n    }\r\n\r\n    /**\r\n     * 将编码的byteBuffer数据转换为字符串\r\n     *\r\n     * @param data 数据\r\n     * @param charset 字符集，如果为空使用当前系统字符集\r\n     * @return 字符串\r\n     */\r\n    public static String str(ByteBuffer data, Charset charset)\r\n    {\r\n        if (null == charset)\r\n        {\r\n            charset = Charset.defaultCharset();\r\n        }\r\n        return charset.decode(data).toString();\r\n    }\r\n\r\n    // ----------------------------------------------------------------------- 全角半角转换\r\n    /**\r\n     * 半角转全角\r\n     *\r\n     * @param input String.\r\n     * @return 全角字符串.\r\n     */\r\n    public static String toSBC(String input)\r\n    {\r\n        return toSBC(input, null);\r\n    }\r\n\r\n    /**\r\n     * 半角转全角\r\n     *\r\n     * @param input String\r\n     * @param notConvertSet 不替换的字符集合\r\n     * @return 全角字符串.\r\n     */\r\n    public static String toSBC(String input, Set<Character> notConvertSet)\r\n    {\r\n        char[] c = input.toCharArray();\r\n        for (int i = 0; i < c.length; i++)\r\n        {\r\n            if (null != notConvertSet && notConvertSet.contains(c[i]))\r\n            {\r\n                // 跳过不替换的字符\r\n                continue;\r\n            }\r\n\r\n            if (c[i] == ' ')\r\n            {\r\n                c[i] = '\\u3000';\r\n            }\r\n            else if (c[i] < '\\177')\r\n            {\r\n                c[i] = (char) (c[i] + 65248);\r\n\r\n            }\r\n        }\r\n        return new String(c);\r\n    }\r\n\r\n    /**\r\n     * 全角转半角\r\n     *\r\n     * @param input String.\r\n     * @return 半角字符串\r\n     */\r\n    public static String toDBC(String input)\r\n    {\r\n        return toDBC(input, null);\r\n    }\r\n\r\n    /**\r\n     * 替换全角为半角\r\n     *\r\n     * @param text 文本\r\n     * @param notConvertSet 不替换的字符集合\r\n     * @return 替换后的字符\r\n     */\r\n    public static String toDBC(String text, Set<Character> notConvertSet)\r\n    {\r\n        char[] c = text.toCharArray();\r\n        for (int i = 0; i < c.length; i++)\r\n        {\r\n            if (null != notConvertSet && notConvertSet.contains(c[i]))\r\n            {\r\n                // 跳过不替换的字符\r\n                continue;\r\n            }\r\n\r\n            if (c[i] == '\\u3000')\r\n            {\r\n                c[i] = ' ';\r\n            }\r\n            else if (c[i] > '\\uFF00' && c[i] < '\\uFF5F')\r\n            {\r\n                c[i] = (char) (c[i] - 65248);\r\n            }\r\n        }\r\n        String returnString = new String(c);\r\n\r\n        return returnString;\r\n    }\r\n\r\n    /**\r\n     * 数字金额大写转换 先写个完整的然后将如零拾替换成零\r\n     *\r\n     * @param n 数字\r\n     * @return 中文大写数字\r\n     */\r\n    public static String digitUppercase(double n)\r\n    {\r\n        String[] fraction = { \"角\", \"分\" };\r\n        String[] digit = { \"零\", \"壹\", \"贰\", \"叁\", \"肆\", \"伍\", \"陆\", \"柒\", \"捌\", \"玖\" };\r\n        String[][] unit = { { \"元\", \"万\", \"亿\" }, { \"\", \"拾\", \"佰\", \"仟\" } };\r\n\r\n        String head = n < 0 ? \"负\" : \"\";\r\n        n = Math.abs(n);\r\n\r\n        String s = \"\";\r\n        for (int i = 0; i < fraction.length; i++)\r\n        {\r\n            // 优化double计算精度丢失问题\r\n            BigDecimal nNum = new BigDecimal(n);\r\n            BigDecimal decimal = new BigDecimal(10);\r\n            BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);\r\n            double d = scale.doubleValue();\r\n            s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll(\"(零.)+\", \"\");\r\n        }\r\n        if (s.length() < 1)\r\n        {\r\n            s = \"整\";\r\n        }\r\n        int integerPart = (int) Math.floor(n);\r\n\r\n        for (int i = 0; i < unit[0].length && integerPart > 0; i++)\r\n        {\r\n            String p = \"\";\r\n            for (int j = 0; j < unit[1].length && n > 0; j++)\r\n            {\r\n                p = digit[integerPart % 10] + unit[1][j] + p;\r\n                integerPart = integerPart / 10;\r\n            }\r\n            s = p.replaceAll(\"(零.)*零$\", \"\").replaceAll(\"^$\", \"零\") + unit[0][i] + s;\r\n        }\r\n        return head + s.replaceAll(\"(零.)*零元\", \"元\").replaceFirst(\"(零.)+\", \"\").replaceAll(\"(零.)+\", \"零\").replaceAll(\"^整$\", \"零元整\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/core/text/StrFormatter.java",
    "content": "package com.ruoyi.common.core.text;\r\n\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 字符串格式化\r\n * \r\n * @author ruoyi\r\n */\r\npublic class StrFormatter\r\n{\r\n    public static final String EMPTY_JSON = \"{}\";\r\n    public static final char C_BACKSLASH = '\\\\';\r\n    public static final char C_DELIM_START = '{';\r\n    public static final char C_DELIM_END = '}';\r\n\r\n    /**\r\n     * 格式化字符串<br>\r\n     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>\r\n     * 如果想输出 {} 使用 \\\\转义 { 即可，如果想输出 {} 之前的 \\ 使用双转义符 \\\\\\\\ 即可<br>\r\n     * 例：<br>\r\n     * 通常使用：format(\"this is {} for {}\", \"a\", \"b\") -> this is a for b<br>\r\n     * 转义{}： format(\"this is \\\\{} for {}\", \"a\", \"b\") -> this is \\{} for a<br>\r\n     * 转义\\： format(\"this is \\\\\\\\{} for {}\", \"a\", \"b\") -> this is \\a for b<br>\r\n     * \r\n     * @param strPattern 字符串模板\r\n     * @param argArray 参数列表\r\n     * @return 结果\r\n     */\r\n    public static String format(final String strPattern, final Object... argArray)\r\n    {\r\n        if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))\r\n        {\r\n            return strPattern;\r\n        }\r\n        final int strPatternLength = strPattern.length();\r\n\r\n        // 初始化定义好的长度以获得更好的性能\r\n        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);\r\n\r\n        int handledPosition = 0;\r\n        int delimIndex;// 占位符所在位置\r\n        for (int argIndex = 0; argIndex < argArray.length; argIndex++)\r\n        {\r\n            delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);\r\n            if (delimIndex == -1)\r\n            {\r\n                if (handledPosition == 0)\r\n                {\r\n                    return strPattern;\r\n                }\r\n                else\r\n                { // 字符串模板剩余部分不再包含占位符，加入剩余部分后返回结果\r\n                    sbuf.append(strPattern, handledPosition, strPatternLength);\r\n                    return sbuf.toString();\r\n                }\r\n            }\r\n            else\r\n            {\r\n                if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)\r\n                {\r\n                    if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)\r\n                    {\r\n                        // 转义符之前还有一个转义符，占位符依旧有效\r\n                        sbuf.append(strPattern, handledPosition, delimIndex - 1);\r\n                        sbuf.append(Convert.utf8Str(argArray[argIndex]));\r\n                        handledPosition = delimIndex + 2;\r\n                    }\r\n                    else\r\n                    {\r\n                        // 占位符被转义\r\n                        argIndex--;\r\n                        sbuf.append(strPattern, handledPosition, delimIndex - 1);\r\n                        sbuf.append(C_DELIM_START);\r\n                        handledPosition = delimIndex + 1;\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    // 正常占位符\r\n                    sbuf.append(strPattern, handledPosition, delimIndex);\r\n                    sbuf.append(Convert.utf8Str(argArray[argIndex]));\r\n                    handledPosition = delimIndex + 2;\r\n                }\r\n            }\r\n        }\r\n        // 加入最后一个占位符后所有的字符\r\n        sbuf.append(strPattern, handledPosition, strPattern.length());\r\n\r\n        return sbuf.toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java",
    "content": "package com.ruoyi.common.enums;\r\n\r\n/**\r\n * 操作状态\r\n * \r\n * @author ruoyi\r\n */\r\npublic enum BusinessStatus\r\n{\r\n    /**\r\n     * 成功\r\n     */\r\n    SUCCESS,\r\n\r\n    /**\r\n     * 失败\r\n     */\r\n    FAIL,\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java",
    "content": "package com.ruoyi.common.enums;\r\n\r\n/**\r\n * 业务操作类型\r\n * \r\n * @author ruoyi\r\n */\r\npublic enum BusinessType\r\n{\r\n    /**\r\n     * 其它\r\n     */\r\n    OTHER,\r\n\r\n    /**\r\n     * 新增\r\n     */\r\n    INSERT,\r\n\r\n    /**\r\n     * 修改\r\n     */\r\n    UPDATE,\r\n\r\n    /**\r\n     * 删除\r\n     */\r\n    DELETE,\r\n\r\n    /**\r\n     * 授权\r\n     */\r\n    GRANT,\r\n\r\n    /**\r\n     * 导出\r\n     */\r\n    EXPORT,\r\n\r\n    /**\r\n     * 导入\r\n     */\r\n    IMPORT,\r\n\r\n    /**\r\n     * 强退\r\n     */\r\n    FORCE,\r\n\r\n    /**\r\n     * 生成代码\r\n     */\r\n    GENCODE,\r\n    \r\n    /**\r\n     * 清空\r\n     */\r\n    CLEAN,\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java",
    "content": "package com.ruoyi.common.enums;\r\n\r\n/**\r\n * 数据源\r\n * \r\n * @author ruoyi\r\n */\r\npublic enum DataSourceType\r\n{\r\n    /**\r\n     * 主库\r\n     */\r\n    MASTER,\r\n\r\n    /**\r\n     * 从库\r\n     */\r\n    SLAVE\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java",
    "content": "package com.ruoyi.common.enums;\n\nimport java.util.function.Function;\nimport com.ruoyi.common.utils.DesensitizedUtil;\n\n/**\n * 脱敏类型\n *\n * @author ruoyi\n */\npublic enum DesensitizedType\n{\n    /**\n     * 姓名，第2位星号替换\n     */\n    USERNAME(s -> s.replaceAll(\"(\\\\S)\\\\S(\\\\S*)\", \"$1*$2\")),\n\n    /**\n     * 密码，全部字符都用*代替\n     */\n    PASSWORD(DesensitizedUtil::password),\n\n    /**\n     * 身份证，中间10位星号替换\n     */\n    ID_CARD(s -> s.replaceAll(\"(\\\\d{4})\\\\d{10}(\\\\d{3}[Xx]|\\\\d{4})\", \"$1** **** ****$2\")),\n\n    /**\n     * 手机号，中间4位星号替换\n     */\n    PHONE(s -> s.replaceAll(\"(\\\\d{3})\\\\d{4}(\\\\d{4})\", \"$1****$2\")),\n\n    /**\n     * 电子邮箱，仅显示第一个字母和@后面的地址显示，其他星号替换\n     */\n    EMAIL(s -> s.replaceAll(\"(^.)[^@]*(@.*$)\", \"$1****$2\")),\n\n    /**\n     * 银行卡号，保留最后4位，其他星号替换\n     */\n    BANK_CARD(s -> s.replaceAll(\"\\\\d{15}(\\\\d{3})\", \"**** **** **** **** $1\")),\n\n    /**\n     * 车牌号码，包含普通车辆、新能源车辆\n     */\n    CAR_LICENSE(DesensitizedUtil::carLicense);\n\n    private final Function<String, String> desensitizer;\n\n    DesensitizedType(Function<String, String> desensitizer)\n    {\n        this.desensitizer = desensitizer;\n    }\n\n    public Function<String, String> desensitizer()\n    {\n        return desensitizer;\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/enums/OnlineStatus.java",
    "content": "package com.ruoyi.common.enums;\r\n\r\n/**\r\n * 用户会话\r\n * \r\n * @author ruoyi\r\n */\r\npublic enum OnlineStatus\r\n{\r\n    /** 用户状态 */\r\n    on_line(\"在线\"), off_line(\"离线\");\r\n\r\n    private final String info;\r\n\r\n    private OnlineStatus(String info)\r\n    {\r\n        this.info = info;\r\n    }\r\n\r\n    public String getInfo()\r\n    {\r\n        return info;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java",
    "content": "package com.ruoyi.common.enums;\r\n\r\n/**\r\n * 操作人类别\r\n * \r\n * @author ruoyi\r\n */\r\npublic enum OperatorType\r\n{\r\n    /**\r\n     * 其它\r\n     */\r\n    OTHER,\r\n\r\n    /**\r\n     * 后台用户\r\n     */\r\n    MANAGE,\r\n\r\n    /**\r\n     * 手机端用户\r\n     */\r\n    MOBILE\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java",
    "content": "package com.ruoyi.common.enums;\r\n\r\n/**\r\n * 用户状态\r\n * \r\n * @author ruoyi\r\n */\r\npublic enum UserStatus\r\n{\r\n    OK(\"0\", \"正常\"), DISABLE(\"1\", \"停用\"), DELETED(\"2\", \"删除\");\r\n\r\n    private final String code;\r\n    private final String info;\r\n\r\n    UserStatus(String code, String info)\r\n    {\r\n        this.code = code;\r\n        this.info = info;\r\n    }\r\n\r\n    public String getCode()\r\n    {\r\n        return code;\r\n    }\r\n\r\n    public String getInfo()\r\n    {\r\n        return info;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java",
    "content": "package com.ruoyi.common.exception;\r\n\r\n/**\r\n * 演示模式异常\r\n * \r\n * @author ruoyi\r\n */\r\npublic class DemoModeException extends RuntimeException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public DemoModeException()\r\n    {\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java",
    "content": "package com.ruoyi.common.exception;\r\n\r\n/**\r\n * 全局异常\r\n * \r\n * @author ruoyi\r\n */\r\npublic class GlobalException extends RuntimeException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * 错误提示\r\n     */\r\n    private String message;\r\n\r\n    /**\r\n     * 错误明细，内部调试错误\r\n     *\r\n     * 和 {@link CommonResult#getDetailMessage()} 一致的设计\r\n     */\r\n    private String detailMessage;\r\n\r\n    /**\r\n     * 空构造方法，避免反序列化问题\r\n     */\r\n    public GlobalException()\r\n    {\r\n    }\r\n\r\n    public GlobalException(String message)\r\n    {\r\n        this.message = message;\r\n    }\r\n\r\n    public String getDetailMessage()\r\n    {\r\n        return detailMessage;\r\n    }\r\n\r\n    public GlobalException setDetailMessage(String detailMessage)\r\n    {\r\n        this.detailMessage = detailMessage;\r\n        return this;\r\n    }\r\n\r\n    @Override\r\n    public String getMessage()\r\n    {\r\n        return message;\r\n    }\r\n\r\n    public GlobalException setMessage(String message)\r\n    {\r\n        this.message = message;\r\n        return this;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java",
    "content": "package com.ruoyi.common.exception;\r\n\r\n/**\r\n * 业务异常\r\n * \r\n * @author ruoyi\r\n */\r\npublic final class ServiceException extends RuntimeException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * 错误提示\r\n     */\r\n    private String message;\r\n\r\n    /**\r\n     * 错误明细，内部调试错误\r\n     *\r\n     * 和 {@link CommonResult#getDetailMessage()} 一致的设计\r\n     */\r\n    private String detailMessage;\r\n\r\n    /**\r\n     * 空构造方法，避免反序列化问题\r\n     */\r\n    public ServiceException()\r\n    {\r\n    }\r\n\r\n    public ServiceException(String message)\r\n    {\r\n        this.message = message;\r\n    }\r\n\r\n    public String getDetailMessage()\r\n    {\r\n        return detailMessage;\r\n    }\r\n\r\n    public ServiceException setDetailMessage(String detailMessage)\r\n    {\r\n        this.detailMessage = detailMessage;\r\n        return this;\r\n    }\r\n\r\n    @Override\r\n    public String getMessage()\r\n    {\r\n        return message;\r\n    }\r\n\r\n    public ServiceException setMessage(String message)\r\n    {\r\n        this.message = message;\r\n        return this;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java",
    "content": "package com.ruoyi.common.exception;\r\n\r\n/**\r\n * 工具类异常\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UtilException extends RuntimeException\r\n{\r\n    private static final long serialVersionUID = 8247610319171014183L;\r\n\r\n    public UtilException(Throwable e)\r\n    {\r\n        super(e.getMessage(), e);\r\n    }\r\n\r\n    public UtilException(String message)\r\n    {\r\n        super(message);\r\n    }\r\n\r\n    public UtilException(String message, Throwable throwable)\r\n    {\r\n        super(message, throwable);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java",
    "content": "package com.ruoyi.common.exception.base;\r\n\r\nimport com.ruoyi.common.utils.MessageUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 基础异常\r\n * \r\n * @author ruoyi\r\n */\r\npublic class BaseException extends RuntimeException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /**\r\n     * 所属模块\r\n     */\r\n    private String module;\r\n\r\n    /**\r\n     * 错误码\r\n     */\r\n    private String code;\r\n\r\n    /**\r\n     * 错误码对应的参数\r\n     */\r\n    private Object[] args;\r\n\r\n    /**\r\n     * 错误消息\r\n     */\r\n    private String defaultMessage;\r\n\r\n    public BaseException(String module, String code, Object[] args, String defaultMessage)\r\n    {\r\n        this.module = module;\r\n        this.code = code;\r\n        this.args = args;\r\n        this.defaultMessage = defaultMessage;\r\n    }\r\n\r\n    public BaseException(String module, String code, Object[] args)\r\n    {\r\n        this(module, code, args, null);\r\n    }\r\n\r\n    public BaseException(String module, String defaultMessage)\r\n    {\r\n        this(module, null, null, defaultMessage);\r\n    }\r\n\r\n    public BaseException(String code, Object[] args)\r\n    {\r\n        this(null, code, args, null);\r\n    }\r\n\r\n    public BaseException(String defaultMessage)\r\n    {\r\n        this(null, null, null, defaultMessage);\r\n    }\r\n\r\n    @Override\r\n    public String getMessage()\r\n    {\r\n        String message = null;\r\n        if (!StringUtils.isEmpty(code))\r\n        {\r\n            message = MessageUtils.message(code, args);\r\n        }\r\n        if (message == null)\r\n        {\r\n            message = defaultMessage;\r\n        }\r\n        return message;\r\n    }\r\n\r\n    public String getModule()\r\n    {\r\n        return module;\r\n    }\r\n\r\n    public String getCode()\r\n    {\r\n        return code;\r\n    }\r\n\r\n    public Object[] getArgs()\r\n    {\r\n        return args;\r\n    }\r\n\r\n    public String getDefaultMessage()\r\n    {\r\n        return defaultMessage;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java",
    "content": "package com.ruoyi.common.exception.file;\n\nimport com.ruoyi.common.exception.base.BaseException;\n\n/**\n * 文件信息异常类\n * \n * @author ruoyi\n */\npublic class FileException extends BaseException\n{\n    private static final long serialVersionUID = 1L;\n\n    public FileException(String code, Object[] args)\n    {\n        super(\"file\", code, args, null);\n    }\n\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java",
    "content": "package com.ruoyi.common.exception.file;\r\n\r\n/**\r\n * 文件名称超长限制异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class FileNameLengthLimitExceededException extends FileException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public FileNameLengthLimitExceededException(int defaultFileNameLength)\r\n    {\r\n        super(\"upload.filename.exceed.length\", new Object[] { defaultFileNameLength });\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java",
    "content": "package com.ruoyi.common.exception.file;\n\n/**\n * 文件名大小限制异常类\n * \n * @author ruoyi\n */\npublic class FileSizeLimitExceededException extends FileException\n{\n    private static final long serialVersionUID = 1L;\n\n    public FileSizeLimitExceededException(long defaultMaxSize)\n    {\n        super(\"upload.exceed.maxSize\", new Object[] { defaultMaxSize });\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java",
    "content": "package com.ruoyi.common.exception.file;\n\nimport java.io.PrintStream;\nimport java.io.PrintWriter;\n\n/**\n * 文件上传异常类\n * \n * @author ruoyi\n */\npublic class FileUploadException extends Exception\n{\n\n    private static final long serialVersionUID = 1L;\n\n    private final Throwable cause;\n\n    public FileUploadException()\n    {\n        this(null, null);\n    }\n\n    public FileUploadException(final String msg)\n    {\n        this(msg, null);\n    }\n\n    public FileUploadException(String msg, Throwable cause)\n    {\n        super(msg);\n        this.cause = cause;\n    }\n\n    @Override\n    public void printStackTrace(PrintStream stream)\n    {\n        super.printStackTrace(stream);\n        if (cause != null)\n        {\n            stream.println(\"Caused by:\");\n            cause.printStackTrace(stream);\n        }\n    }\n\n    @Override\n    public void printStackTrace(PrintWriter writer)\n    {\n        super.printStackTrace(writer);\n        if (cause != null)\n        {\n            writer.println(\"Caused by:\");\n            cause.printStackTrace(writer);\n        }\n    }\n\n    @Override\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java",
    "content": "package com.ruoyi.common.exception.file;\r\n\r\nimport java.util.Arrays;\r\n\r\n/**\r\n * 文件上传无效扩展名异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class InvalidExtensionException extends FileUploadException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private String[] allowedExtension;\r\n    private String extension;\r\n    private String filename;\r\n\r\n    public InvalidExtensionException(String[] allowedExtension, String extension, String filename)\r\n    {\r\n        super(\"文件[\" + filename + \"]后缀[\" + extension + \"]不正确，请上传\" + Arrays.toString(allowedExtension) + \"格式\");\r\n        this.allowedExtension = allowedExtension;\r\n        this.extension = extension;\r\n        this.filename = filename;\r\n    }\r\n\r\n    public String[] getAllowedExtension()\r\n    {\r\n        return allowedExtension;\r\n    }\r\n\r\n    public String getExtension()\r\n    {\r\n        return extension;\r\n    }\r\n\r\n    public String getFilename()\r\n    {\r\n        return filename;\r\n    }\r\n\r\n    public static class InvalidImageExtensionException extends InvalidExtensionException\r\n    {\r\n        private static final long serialVersionUID = 1L;\r\n\r\n        public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)\r\n        {\r\n            super(allowedExtension, extension, filename);\r\n        }\r\n    }\r\n\r\n    public static class InvalidFlashExtensionException extends InvalidExtensionException\r\n    {\r\n        private static final long serialVersionUID = 1L;\r\n\r\n        public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)\r\n        {\r\n            super(allowedExtension, extension, filename);\r\n        }\r\n    }\r\n\r\n    public static class InvalidMediaExtensionException extends InvalidExtensionException\r\n    {\r\n        private static final long serialVersionUID = 1L;\r\n\r\n        public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)\r\n        {\r\n            super(allowedExtension, extension, filename);\r\n        }\r\n    }\r\n    \r\n    public static class InvalidVideoExtensionException extends InvalidExtensionException\r\n    {\r\n        private static final long serialVersionUID = 1L;\r\n\r\n        public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)\r\n        {\r\n            super(allowedExtension, extension, filename);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java",
    "content": "package com.ruoyi.common.exception.job;\r\n\r\n/**\r\n * 计划策略异常\r\n * \r\n * @author ruoyi\r\n */\r\npublic class TaskException extends Exception\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    private Code code;\r\n\r\n    public TaskException(String msg, Code code)\r\n    {\r\n        this(msg, code, null);\r\n    }\r\n\r\n    public TaskException(String msg, Code code, Exception nestedEx)\r\n    {\r\n        super(msg, nestedEx);\r\n        this.code = code;\r\n    }\r\n\r\n    public Code getCode()\r\n    {\r\n        return code;\r\n    }\r\n\r\n    public enum Code\r\n    {\r\n        TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java",
    "content": "package com.ruoyi.common.exception.user;\n\n/**\n * 黑名单IP异常类\n * \n * @author ruoyi\n */\npublic class BlackListException extends UserException\n{\n    private static final long serialVersionUID = 1L;\n\n    public BlackListException()\n    {\n        super(\"login.blocked\", null);\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 验证码错误异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class CaptchaException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public CaptchaException()\r\n    {\r\n        super(\"user.jcaptcha.error\", null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/RoleBlockedException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 角色锁定异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class RoleBlockedException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public RoleBlockedException()\r\n    {\r\n        super(\"role.blocked\", null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserBlockedException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 用户锁定异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserBlockedException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public UserBlockedException()\r\n    {\r\n        super(\"user.blocked\", null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserDeleteException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 用户账号已被删除\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserDeleteException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public UserDeleteException()\r\n    {\r\n        super(\"user.password.delete\", null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\nimport com.ruoyi.common.exception.base.BaseException;\r\n\r\n/**\r\n * 用户信息异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserException extends BaseException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public UserException(String code, Object[] args)\r\n    {\r\n        super(\"user\", code, args, null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 用户不存在异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserNotExistsException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public UserNotExistsException()\r\n    {\r\n        super(\"user.not.exists\", null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 用户密码不正确或不符合规范异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserPasswordNotMatchException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public UserPasswordNotMatchException()\r\n    {\r\n        super(\"user.password.not.match\", null);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitCountException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 用户错误记数异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserPasswordRetryLimitCountException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public UserPasswordRetryLimitCountException(int retryLimitCount)\r\n    {\r\n        super(\"user.password.retry.limit.count\", new Object[] { retryLimitCount });\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java",
    "content": "package com.ruoyi.common.exception.user;\r\n\r\n/**\r\n * 用户错误最大次数异常类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserPasswordRetryLimitExceedException extends UserException\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    public UserPasswordRetryLimitExceedException(int retryLimitCount)\r\n    {\r\n        super(\"user.password.retry.limit.exceed\", new Object[] { retryLimitCount });\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/json/JSON.java",
    "content": "package com.ruoyi.common.json;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\nimport com.fasterxml.jackson.core.JsonGenerationException;\r\nimport com.fasterxml.jackson.core.JsonParseException;\r\nimport com.fasterxml.jackson.databind.JsonMappingException;\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport com.fasterxml.jackson.databind.ObjectWriter;\r\n\r\n/**\r\n * JSON解析处理\r\n * \r\n * @author ruoyi\r\n */\r\npublic class JSON\r\n{\r\n    public static final String DEFAULT_FAIL = \"\\\"Parse failed\\\"\";\r\n    private static final ObjectMapper objectMapper = new ObjectMapper();\r\n    private static final ObjectWriter objectWriter = objectMapper.writerWithDefaultPrettyPrinter();\r\n\r\n    public static void marshal(File file, Object value) throws Exception\r\n    {\r\n        try\r\n        {\r\n            objectWriter.writeValue(file, value);\r\n        }\r\n        catch (JsonGenerationException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n\r\n    public static void marshal(OutputStream os, Object value) throws Exception\r\n    {\r\n        try\r\n        {\r\n            objectWriter.writeValue(os, value);\r\n        }\r\n        catch (JsonGenerationException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n\r\n    public static String marshal(Object value) throws Exception\r\n    {\r\n        try\r\n        {\r\n            return objectWriter.writeValueAsString(value);\r\n        }\r\n        catch (JsonGenerationException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n\r\n    public static byte[] marshalBytes(Object value) throws Exception\r\n    {\r\n        try\r\n        {\r\n            return objectWriter.writeValueAsBytes(value);\r\n        }\r\n        catch (JsonGenerationException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n\r\n    public static <T> T unmarshal(File file, Class<T> valueType) throws Exception\r\n    {\r\n        try\r\n        {\r\n            return objectMapper.readValue(file, valueType);\r\n        }\r\n        catch (JsonParseException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n\r\n    public static <T> T unmarshal(InputStream is, Class<T> valueType) throws Exception\r\n    {\r\n        try\r\n        {\r\n            return objectMapper.readValue(is, valueType);\r\n        }\r\n        catch (JsonParseException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n\r\n    public static <T> T unmarshal(String str, Class<T> valueType) throws Exception\r\n    {\r\n        try\r\n        {\r\n            return objectMapper.readValue(str, valueType);\r\n        }\r\n        catch (JsonParseException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n\r\n    public static <T> T unmarshal(byte[] bytes, Class<T> valueType) throws Exception\r\n    {\r\n        try\r\n        {\r\n            if (bytes == null)\r\n            {\r\n                bytes = new byte[0];\r\n            }\r\n            return objectMapper.readValue(bytes, 0, bytes.length, valueType);\r\n        }\r\n        catch (JsonParseException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (JsonMappingException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new Exception(e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/json/JSONObject.java",
    "content": "package com.ruoyi.common.json;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.StringTokenizer;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 通用消息对象，基于Map实现的可嵌套数据结构。 支持JSON数据结构。\r\n * \r\n * @author ruoyi\r\n */\r\npublic class JSONObject extends LinkedHashMap<String, Object>\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n    private static final Pattern arrayNamePattern = Pattern.compile(\"(\\\\w+)((\\\\[\\\\d+\\\\])+)\");\r\n    private static final ObjectMapper objectMapper = new ObjectMapper();\r\n\r\n    /**\r\n     * 数组结构。\r\n     */\r\n    public static class JSONArray extends ArrayList<Object>\r\n    {\r\n        private static final long serialVersionUID = 1L;\r\n\r\n        public JSONArray()\r\n        {\r\n            super();\r\n        }\r\n\r\n        public JSONArray(int size)\r\n        {\r\n            super(size);\r\n        }\r\n\r\n        @Override\r\n        public String toString()\r\n        {\r\n            try\r\n            {\r\n                return JSON.marshal(this);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                throw new RuntimeException(e);\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public Object set(int index, Object element)\r\n        {\r\n            return super.set(index, transfer(element));\r\n        }\r\n\r\n        @Override\r\n        public boolean add(Object element)\r\n        {\r\n            return super.add(transfer(element));\r\n        }\r\n\r\n        @Override\r\n        public void add(int index, Object element)\r\n        {\r\n            super.add(index, transfer(element));\r\n        }\r\n    }\r\n\r\n    public JSONObject()\r\n    {\r\n        super();\r\n    }\r\n\r\n    public JSONObject(final JSONObject other)\r\n    {\r\n        super(other);\r\n    }\r\n\r\n    @Override\r\n    public String toString()\r\n    {\r\n        try\r\n        {\r\n            return JSON.marshal(this);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 转换为紧凑格式的字符串。\r\n     * \r\n     * @return 返回本对象紧凑格式字符串。\r\n     */\r\n    public String toCompactString()\r\n    {\r\n        try\r\n        {\r\n            return objectMapper.writeValueAsString(this);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的整数值。如果字段不存在，或者无法转换为整数，返回null。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @return 返回指定的整数值，或者null。\r\n     */\r\n    public Integer intValue(final String name)\r\n    {\r\n        return valueAsInt(value(name));\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的整数值。如果字段不存在，或者无法转换为整数，返回defaultValue。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @param defaultValue 查询失败时，返回的值。\r\n     * @return 返回指定的整数值，或者defaultValue。\r\n     */\r\n    public Integer intValue(final String name, final Integer defaultValue)\r\n    {\r\n        return StringUtils.nvl(intValue(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的长整数值。如果字段不存在，或者无法转换为长整数，返回null。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @return 返回指定的长整数值，或者null。\r\n     */\r\n    public Long longValue(final String name)\r\n    {\r\n        return valueAsLong(value(name));\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的长整数值。如果字段不存在，或者无法转换为长整数，返回defaultValue。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @param defaultValue 查询失败时，返回的值。\r\n     * @return 返回指定的长整数值，或者defaultValue。\r\n     */\r\n    public Long longValue(final String name, final Long defaultValue)\r\n    {\r\n        return StringUtils.nvl(longValue(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的布尔值。如果字段不存在，或者无法转换为布尔型，返回null。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @return 返回指定的布尔值，或者null。\r\n     */\r\n    public Boolean boolValue(final String name)\r\n    {\r\n        return valueAsBool(value(name));\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的布尔值。如果字段不存在，或者无法转换为布尔型，返回defaultValue。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @param defaultValue 查询失败时，返回的值。\r\n     * @return 返回指定的布尔值，或者defaultValue。\r\n     */\r\n    public Boolean boolValue(final String name, final Boolean defaultValue)\r\n    {\r\n        return StringUtils.nvl(boolValue(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的字符串值。如果字段不存在，返回null。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @return 返回指定的字符串值，或者null。\r\n     */\r\n    public String strValue(final String name)\r\n    {\r\n        return valueAsStr(value(name));\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的字符串值。如果字段不存在，返回defaultValue。\r\n     * \r\n     * @param name 字段名，支持多级。\r\n     * @param defaultValue 查询失败时，返回的值。\r\n     * @return 返回指定的字符串值，或者defaultValue。\r\n     */\r\n    public String strValue(final String name, final String defaultValue)\r\n    {\r\n        return StringUtils.nvl(strValue(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 获取指定字段的值。\r\n     * \r\n     * @param name 字段名，支持多级，支持数组下标。\r\n     * @return 返回指定字段的值。\r\n     */\r\n    public Object value(final String name)\r\n    {\r\n        final int indexDot = name.indexOf('.');\r\n        if (indexDot >= 0)\r\n        {\r\n            return obj(name.substring(0, indexDot)).value(name.substring(indexDot + 1));\r\n        }\r\n        else\r\n        {\r\n            final Matcher matcher = arrayNamePattern.matcher(name);\r\n            if (matcher.find())\r\n            {\r\n                return endArray(matcher.group(1), matcher.group(2), new EndArrayCallback<Object>()\r\n                {\r\n                    @Override\r\n                    public Object callback(JSONArray arr, int index)\r\n                    {\r\n                        return elementAt(arr, index);\r\n                    }\r\n                });\r\n            }\r\n            else\r\n            {\r\n                return get(name);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 设置指定字段的值。\r\n     * \r\n     * @param name 字段名，支持多级，支持数组下标。\r\n     * @param value 字段值。\r\n     * @return 返回本对象。\r\n     */\r\n    public JSONObject value(final String name, final Object value)\r\n    {\r\n        final int indexDot = name.indexOf('.');\r\n        if (indexDot >= 0)\r\n        {\r\n            obj(name.substring(0, indexDot)).value(name.substring(indexDot + 1), value);\r\n        }\r\n        else\r\n        {\r\n            final Matcher matcher = arrayNamePattern.matcher(name);\r\n            if (matcher.find())\r\n            {\r\n                endArray(matcher.group(1), matcher.group(2), new EndArrayCallback<Void>()\r\n                {\r\n                    @Override\r\n                    public Void callback(JSONArray arr, int index)\r\n                    {\r\n                        elementAt(arr, index, value);\r\n                        return null;\r\n                    }\r\n                });\r\n            }\r\n            else\r\n            {\r\n                set(name, value);\r\n            }\r\n        }\r\n        return this;\r\n    }\r\n\r\n    /**\r\n     * 获取对象（非标量类型）字段。返回的数据是一个结构体。当不存在指定对象时，则为指定的名字创建一个空的MessageObject对象。\r\n     * \r\n     * @param name 字段名。不支持多级名字，支持数组下标。\r\n     * @return 返回指定的对象。如果对象不存在，则为指定的名字创建一个空的MessageObject对象。\r\n     */\r\n    public JSONObject obj(final String name)\r\n    {\r\n        final Matcher matcher = arrayNamePattern.matcher(name);\r\n        if (matcher.find())\r\n        {\r\n            return endArray(matcher.group(1), matcher.group(2), new EndArrayCallback<JSONObject>()\r\n            {\r\n                @Override\r\n                public JSONObject callback(JSONArray arr, int index)\r\n                {\r\n                    return objAt(arr, index);\r\n                }\r\n            });\r\n        }\r\n        else\r\n        {\r\n            JSONObject obj = getObj(name);\r\n            if (obj == null)\r\n            {\r\n                obj = new JSONObject();\r\n                put(name, obj);\r\n            }\r\n            return obj;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取数组字段。将名字对应的对象以数组对象返回，当指定的字段不存在时，创建一个空的数组。\r\n     * \r\n     * @param name 字段名。不支持多级名字，不支持下标。\r\n     * @return 返回一个数组（List）。\r\n     */\r\n    public JSONArray arr(final String name)\r\n    {\r\n        JSONArray arr = getArr(name);\r\n        if (arr == null)\r\n        {\r\n            arr = new JSONArray();\r\n            put(name, arr);\r\n        }\r\n        return arr;\r\n    }\r\n\r\n    /**\r\n     * 获取对象（非标量类型）字段。返回的数据是一个结构体。\r\n     * \r\n     * @param name 字段名。\r\n     * @return 返回指定的对象字段。\r\n     */\r\n    public JSONObject getObj(final String name)\r\n    {\r\n        return (JSONObject) get(name);\r\n    }\r\n\r\n    /**\r\n     * 获取数组类型字段。\r\n     * \r\n     * @param name 字段名。\r\n     * @return 返回数组类型字段。\r\n     */\r\n    public JSONArray getArr(final String name)\r\n    {\r\n        return (JSONArray) get(name);\r\n    }\r\n\r\n    /**\r\n     * 返回字段整数值。如果不存在，返回null。\r\n     * \r\n     * @param name 字段名。\r\n     * @return 返回指定字段整数值。\r\n     */\r\n    public Integer getInt(final String name)\r\n    {\r\n        return valueAsInt(get(name));\r\n    }\r\n\r\n    /**\r\n     * 返回字段整数值。如果不存在，返回defaultValue。\r\n     * \r\n     * @param name 字段名。\r\n     * @param defaultValue 字段不存在时，返回的值。\r\n     * @return 返回指定字段整数值。\r\n     */\r\n    public Integer getInt(final String name, Integer defaultValue)\r\n    {\r\n        return StringUtils.nvl(getInt(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 返回字段长整数值。如果不存在，返回null。\r\n     * \r\n     * @param name 字段名。\r\n     * @return 返回指定字段长整数值。\r\n     */\r\n    public Long getLong(final String name)\r\n    {\r\n        return valueAsLong(get(name));\r\n    }\r\n\r\n    /**\r\n     * 返回字段长整数值。如果不存在，返回defaultValue。\r\n     * \r\n     * @param name 字段名。\r\n     * @param defaultValue 字段不存在时，返回的值。\r\n     * @return 返回指定字段长整数值。\r\n     */\r\n    public Long getLong(final String name, Long defaultValue)\r\n    {\r\n        return StringUtils.nvl(getLong(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 返回字段字符串值。如果不存在，返回null。\r\n     * \r\n     * @param name 字段名。\r\n     * @return 返回指定字段字符串值。\r\n     */\r\n    public String getStr(final String name)\r\n    {\r\n        return valueAsStr(get(name));\r\n    }\r\n\r\n    /**\r\n     * 返回字段字符串值。如果不存在，返回defaultValue。\r\n     * \r\n     * @param name 字段名。\r\n     * @param defaultValue 字段不存在时，返回的值。\r\n     * @return 返回指定字段字符串值。\r\n     */\r\n    public String getStr(final String name, final String defaultValue)\r\n    {\r\n        return StringUtils.nvl(getStr(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 字段值按照布尔类型返回。如果不存在，返回null。\r\n     * \r\n     * @param name 字段名。\r\n     * @return 字段值。\r\n     */\r\n    public Boolean getBool(final String name)\r\n    {\r\n        return valueAsBool(get(name));\r\n    }\r\n\r\n    /**\r\n     * 字段值按照布尔类型返回。如果不存在，返回defaultValue。\r\n     * \r\n     * @param name 字段名。\r\n     * @param defaultValue 字段不存在时，返回的值。\r\n     * @return 字段值。\r\n     */\r\n    public Boolean getBool(final String name, final Boolean defaultValue)\r\n    {\r\n        return StringUtils.nvl(getBool(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 设置字段值\r\n     * \r\n     * @param name 字段名\r\n     * @param value 字段值（标量：数字、字符串、布尔型；结构体：MessageObject）。 如果是Map类型同时非MessageObject类型，则自动转换为MessageObject类型再存入\r\n     *            （此时，再修改Map中的数据，将不会体现到本对象中）。\r\n     * @return 返回本对象\r\n     */\r\n    public JSONObject set(final String name, final Object value)\r\n    {\r\n        put(name, value);\r\n        return this;\r\n    }\r\n\r\n    /**\r\n     * 将本对象转换为Java Bean。\r\n     * \r\n     * @param beanClass Java Bean的类对象。\r\n     * @return 返回转换后的Java Bean。\r\n     */\r\n    public <T> T asBean(Class<T> beanClass)\r\n    {\r\n        try\r\n        {\r\n            return JSON.unmarshal(JSON.marshal(this), beanClass);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 重载基类的方法。如果 value 是 Map 类型，但不是 MessageObject 类型，则创建一个包含内容等同于原 Map 的 MessageObject 作为 value（注意：此后再更改 Map 的内容，将不会反映到\r\n     * MessageObject 中）。 重载此方法的目的是为了使JSON能够正确地解析为MessageObject对象。不建议直接调用此方法，请使用 set(name, value)方法设置字段值。\r\n     */\r\n    @Override\r\n    public Object put(String key, Object value)\r\n    {\r\n        return super.put(key, transfer(value));\r\n    }\r\n\r\n    public static Integer valueAsInt(Object value)\r\n    {\r\n        if (value instanceof Integer)\r\n        {\r\n            return (Integer) value;\r\n        }\r\n        else if (value instanceof Number)\r\n        {\r\n            return ((Number) value).intValue();\r\n        }\r\n        else if (value instanceof String)\r\n        {\r\n            return Integer.valueOf((String) value);\r\n        }\r\n        else if (value instanceof Boolean)\r\n        {\r\n            return ((Boolean) value) ? 1 : 0;\r\n        }\r\n        else\r\n        {\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public static Long valueAsLong(Object value)\r\n    {\r\n        if (value instanceof Long)\r\n        {\r\n            return (Long) value;\r\n        }\r\n        else if (value instanceof Number)\r\n        {\r\n            return ((Number) value).longValue();\r\n        }\r\n        else if (value instanceof String)\r\n        {\r\n            return Long.valueOf((String) value);\r\n        }\r\n        else if (value instanceof Boolean)\r\n        {\r\n            return ((Boolean) value) ? 1L : 0L;\r\n        }\r\n        else\r\n        {\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public static String valueAsStr(Object value)\r\n    {\r\n        if (value instanceof String)\r\n        {\r\n            return (String) value;\r\n        }\r\n        else if (value != null)\r\n        {\r\n            return value.toString();\r\n        }\r\n        else\r\n        {\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public static Boolean valueAsBool(Object value)\r\n    {\r\n        if (value instanceof Boolean)\r\n        {\r\n            return (Boolean) value;\r\n        }\r\n        else if (value instanceof Number)\r\n        {\r\n            return ((Number) value).doubleValue() != 0.0;\r\n        }\r\n        else if (value instanceof String)\r\n        {\r\n            return Boolean.valueOf((String) value);\r\n        }\r\n        else\r\n        {\r\n            return null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 将所有层次中凡是Map类型同时又不是MessageObject的类型，转换为MessageObject类型。\r\n     * \r\n     * @param value 值。\r\n     * @return 返回转换后的值。\r\n     */\r\n    @SuppressWarnings(\"unchecked\")\r\n    private static Object transfer(final Object value)\r\n    {\r\n        if (!(value instanceof JSONObject) && value instanceof Map)\r\n        {\r\n            return toObj((Map<String, Object>) value);\r\n        }\r\n        else if (!(value instanceof JSONArray) && value instanceof Collection)\r\n        {\r\n            return toArr((Collection<Object>) value);\r\n        }\r\n        else\r\n        {\r\n            return value;\r\n        }\r\n    }\r\n\r\n    private static JSONArray toArr(final Collection<Object> list)\r\n    {\r\n        final JSONArray arr = new JSONArray(list.size());\r\n        for (final Object element : list)\r\n        {\r\n            arr.add(element);\r\n        }\r\n        return arr;\r\n    }\r\n\r\n    private static JSONObject toObj(final Map<String, Object> map)\r\n    {\r\n        final JSONObject obj = new JSONObject();\r\n        for (final Map.Entry<String, Object> ent : map.entrySet())\r\n        {\r\n            obj.put(ent.getKey(), transfer(ent.getValue()));\r\n        }\r\n        return obj;\r\n    }\r\n\r\n    /**\r\n     * 将指定下标元素作为数组返回，如果不存在，则在该位置创建一个空的数组。\r\n     * \r\n     * @param arr 当前数组。\r\n     * @param index 下标。\r\n     * @return 返回当前数组指定下标的元素，该元素应该是一个数组。\r\n     */\r\n    private static JSONArray arrayAt(JSONArray arr, int index)\r\n    {\r\n        expand(arr, index);\r\n        if (arr.get(index) == null)\r\n        {\r\n            arr.set(index, new JSONArray());\r\n        }\r\n        return (JSONArray) arr.get(index);\r\n    }\r\n\r\n    /**\r\n     * 将指定下标元素作为结构体返回，如果不存在，则在该位置创建一个空的结构体。\r\n     * \r\n     * @param arr 当前数组。\r\n     * @param index 下标。\r\n     * @return 返回当前数组指定下标元素，该元素是一个结构体。\r\n     */\r\n    private static JSONObject objAt(final JSONArray arr, int index)\r\n    {\r\n        expand(arr, index);\r\n        if (arr.get(index) == null)\r\n        {\r\n            arr.set(index, new JSONObject());\r\n        }\r\n        return (JSONObject) arr.get(index);\r\n    }\r\n\r\n    /**\r\n     * 设置数组指定下标位置的值。\r\n     * \r\n     * @param arr 数组。\r\n     * @param index 下标。\r\n     * @param value 值。\r\n     */\r\n    private static void elementAt(final JSONArray arr, final int index, final Object value)\r\n    {\r\n        expand(arr, index).set(index, value);\r\n    }\r\n\r\n    /**\r\n     * 获取数组指定下标元素的值。\r\n     * \r\n     * @param arr 数组。\r\n     * @param index 下标。\r\n     * @return 值。\r\n     */\r\n    private static Object elementAt(final JSONArray arr, final int index)\r\n    {\r\n        return expand(arr, index).get(index);\r\n    }\r\n\r\n    /**\r\n     * 扩展数组到指定下标，以防止访问时下标越界。\r\n     * \r\n     * @param arr 数组\r\n     * @param index 下标\r\n     * @return 返回传入的数组\r\n     */\r\n    private static JSONArray expand(final JSONArray arr, final int index)\r\n    {\r\n        while (arr.size() <= index)\r\n        {\r\n            arr.add(null);\r\n        }\r\n        return arr;\r\n    }\r\n\r\n    /**\r\n     * 最后数组回调。\r\n     * \r\n     * @author Mike\r\n     *\r\n     * @param <T> 回调返回数据类型。\r\n     */\r\n    private interface EndArrayCallback<T>\r\n    {\r\n        /**\r\n         * 当定位到最后一级数组，将调用本方法。\r\n         * \r\n         * @param arr 最后一级数组对象。\r\n         * @param index 最后一级索引。\r\n         * @return 返回回调的返回值。\r\n         */\r\n        T callback(JSONArray arr, int index);\r\n    }\r\n\r\n    /**\r\n     * 处理多维数组的工具函数（包括一维数组）。多维数组的名字如：arrary[1][2][3]， 则name=array，indexStr=[1][2][3]，在callback中，endArr将是\r\n     * array[1][2]指定的对象，indexe=3。\r\n     * \r\n     * @param name 不带下标的名字，不支持多级名字。\r\n     * @param indexesStr 索引部分的字符串，如：[1][2][3]\r\n     * @param callback 回调函数。\r\n     * @return 返回回调函数的返回值。\r\n     */\r\n    private <T> T endArray(final String name, final String indexesStr, final EndArrayCallback<T> callback)\r\n    {\r\n        JSONArray endArr = arr(name);\r\n        final int[] indexes = parseIndexes(indexesStr);\r\n        int i = 0;\r\n        while (i < indexes.length - 1)\r\n        {\r\n            endArr = arrayAt(endArr, indexes[i++]);\r\n        }\r\n        return callback.callback(endArr, indexes[i]);\r\n    }\r\n\r\n    private static int[] parseIndexes(final String s)\r\n    {\r\n        int[] indexes = null;\r\n        List<Integer> list = new ArrayList<Integer>();\r\n\r\n        final StringTokenizer st = new StringTokenizer(s, \"[]\");\r\n        while (st.hasMoreTokens())\r\n        {\r\n            final int index = Integer.valueOf(st.nextToken());\r\n            if (index < 0)\r\n            {\r\n                throw new RuntimeException(String.format(\"Illegal index %1$d in \\\"%2$s\\\"\", index, s));\r\n            }\r\n\r\n            list.add(index);\r\n        }\r\n\r\n        indexes = new int[list.size()];\r\n        int i = 0;\r\n        for (Integer tmp : list.toArray(new Integer[list.size()]))\r\n        {\r\n            indexes[i++] = tmp;\r\n        }\r\n\r\n        return indexes;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/AddressUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.alibaba.fastjson.JSONObject;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.utils.http.HttpUtils;\r\n\r\n/**\r\n * 获取地址类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class AddressUtils\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);\r\n\r\n    // IP地址查询\r\n    public static final String IP_URL = \"https://whois.pconline.com.cn/ipJson.jsp\";\r\n\r\n    // 未知地址\r\n    public static final String UNKNOWN = \"XX XX\";\r\n\r\n    public static String getRealAddressByIP(String ip)\r\n    {\r\n        // 内网不查询\r\n        if (IpUtils.internalIp(ip))\r\n        {\r\n            return \"内网IP\";\r\n        }\r\n        if (RuoYiConfig.isAddressEnabled())\r\n        {\r\n            try\r\n            {\r\n                String rspStr = HttpUtils.sendGet(IP_URL, \"ip=\" + ip + \"&json=true\", Constants.GBK);\r\n                if (StringUtils.isEmpty(rspStr))\r\n                {\r\n                    log.error(\"获取地理位置异常 {}\", ip);\r\n                    return UNKNOWN;\r\n                }\r\n                JSONObject obj = JSONObject.parseObject(rspStr);\r\n                String region = obj.getString(\"pro\");\r\n                String city = obj.getString(\"city\");\r\n                return String.format(\"%s %s\", region, city);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                log.error(\"获取地理位置异常 {}\", e);\r\n            }\r\n        }\r\n        return UNKNOWN;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\n\r\n/**\r\n * 精确的浮点数运算\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Arith\r\n{\r\n\r\n    /** 默认除法运算精度 */\r\n    private static final int DEF_DIV_SCALE = 10;\r\n\r\n    /** 这个类不能实例化 */\r\n    private Arith()\r\n    {\r\n    }\r\n\r\n    /**\r\n     * 提供精确的加法运算。\r\n     * @param v1 被加数\r\n     * @param v2 加数\r\n     * @return 两个参数的和\r\n     */\r\n    public static double add(double v1, double v2)\r\n    {\r\n        BigDecimal b1 = new BigDecimal(Double.toString(v1));\r\n        BigDecimal b2 = new BigDecimal(Double.toString(v2));\r\n        return b1.add(b2).doubleValue();\r\n    }\r\n\r\n    /**\r\n     * 提供精确的减法运算。\r\n     * @param v1 被减数\r\n     * @param v2 减数\r\n     * @return 两个参数的差\r\n     */\r\n    public static double sub(double v1, double v2)\r\n    {\r\n        BigDecimal b1 = new BigDecimal(Double.toString(v1));\r\n        BigDecimal b2 = new BigDecimal(Double.toString(v2));\r\n        return b1.subtract(b2).doubleValue();\r\n    }\r\n\r\n    /**\r\n     * 提供精确的乘法运算。\r\n     * @param v1 被乘数\r\n     * @param v2 乘数\r\n     * @return 两个参数的积\r\n     */\r\n    public static double mul(double v1, double v2)\r\n    {\r\n        BigDecimal b1 = new BigDecimal(Double.toString(v1));\r\n        BigDecimal b2 = new BigDecimal(Double.toString(v2));\r\n        return b1.multiply(b2).doubleValue();\r\n    }\r\n\r\n    /**\r\n     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到\r\n     * 小数点以后10位，以后的数字四舍五入。\r\n     * @param v1 被除数\r\n     * @param v2 除数\r\n     * @return 两个参数的商\r\n     */\r\n    public static double div(double v1, double v2)\r\n    {\r\n        return div(v1, v2, DEF_DIV_SCALE);\r\n    }\r\n\r\n    /**\r\n     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指\r\n     * 定精度，以后的数字四舍五入。\r\n     * @param v1 被除数\r\n     * @param v2 除数\r\n     * @param scale 表示表示需要精确到小数点以后几位。\r\n     * @return 两个参数的商\r\n     */\r\n    public static double div(double v1, double v2, int scale)\r\n    {\r\n        if (scale < 0)\r\n        {\r\n            throw new IllegalArgumentException(\r\n                    \"The scale must be a positive integer or zero\");\r\n        }\r\n        BigDecimal b1 = new BigDecimal(Double.toString(v1));\r\n        BigDecimal b2 = new BigDecimal(Double.toString(v2));\r\n        if (b1.compareTo(BigDecimal.ZERO) == 0)\r\n        {\r\n            return BigDecimal.ZERO.doubleValue();\r\n        }\r\n        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();\r\n    }\r\n\r\n    /**\r\n     * 提供精确的小数位四舍五入处理。\r\n     * @param v 需要四舍五入的数字\r\n     * @param scale 小数点后保留几位\r\n     * @return 四舍五入后的结果\r\n     */\r\n    public static double round(double v, int scale)\r\n    {\r\n        if (scale < 0)\r\n        {\r\n            throw new IllegalArgumentException(\r\n                    \"The scale must be a positive integer or zero\");\r\n        }\r\n        BigDecimal b = new BigDecimal(Double.toString(v));\r\n        return b.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).doubleValue();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/CacheUtils.java",
    "content": "package com.ruoyi.common.utils;\n\nimport java.util.Iterator;\nimport java.util.Set;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheManager;\nimport org.apache.shiro.cache.ehcache.EhCacheManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport com.ruoyi.common.utils.spring.SpringUtils;\n\n/**\n * Cache工具类\n * \n * @author ruoyi\n */\npublic class CacheUtils\n{\n    private static Logger logger = LoggerFactory.getLogger(CacheUtils.class);\n\n    private static CacheManager cacheManager = SpringUtils.getBean(CacheManager.class);\n\n    private static final String SYS_CACHE = \"sys-cache\";\n\n    /**\n     * 获取SYS_CACHE缓存\n     * \n     * @param key\n     * @return\n     */\n    public static Object get(String key)\n    {\n        return get(SYS_CACHE, key);\n    }\n\n    /**\n     * 获取SYS_CACHE缓存\n     * \n     * @param key\n     * @param defaultValue\n     * @return\n     */\n    public static Object get(String key, Object defaultValue)\n    {\n        Object value = get(key);\n        return value != null ? value : defaultValue;\n    }\n\n    /**\n     * 写入SYS_CACHE缓存\n     * \n     * @param key\n     * @return\n     */\n    public static void put(String key, Object value)\n    {\n        put(SYS_CACHE, key, value);\n    }\n\n    /**\n     * 从SYS_CACHE缓存中移除\n     * \n     * @param key\n     * @return\n     */\n    public static void remove(String key)\n    {\n        remove(SYS_CACHE, key);\n    }\n\n    /**\n     * 获取缓存\n     * \n     * @param cacheName\n     * @param key\n     * @return\n     */\n    public static Object get(String cacheName, String key)\n    {\n        return getCache(cacheName).get(getKey(key));\n    }\n\n    /**\n     * 获取缓存\n     * \n     * @param cacheName\n     * @param key\n     * @param defaultValue\n     * @return\n     */\n    public static Object get(String cacheName, String key, Object defaultValue)\n    {\n        Object value = get(cacheName, getKey(key));\n        return value != null ? value : defaultValue;\n    }\n\n    /**\n     * 写入缓存\n     * \n     * @param cacheName\n     * @param key\n     * @param value\n     */\n    public static void put(String cacheName, String key, Object value)\n    {\n        getCache(cacheName).put(getKey(key), value);\n    }\n\n    /**\n     * 从缓存中移除\n     * \n     * @param cacheName\n     * @param key\n     */\n    public static void remove(String cacheName, String key)\n    {\n        getCache(cacheName).remove(getKey(key));\n    }\n\n    /**\n     * 从缓存中移除所有\n     * \n     * @param cacheName\n     */\n    public static void removeAll(String cacheName)\n    {\n        Cache<String, Object> cache = getCache(cacheName);\n        Set<String> keys = cache.keys();\n        for (Iterator<String> it = keys.iterator(); it.hasNext();)\n        {\n            cache.remove(it.next());\n        }\n        logger.info(\"清理缓存： {} => {}\", cacheName, keys);\n    }\n\n    /**\n     * 从缓存中移除指定key\n     * \n     * @param keys\n     */\n    public static void removeByKeys(Set<String> keys)\n    {\n        removeByKeys(SYS_CACHE, keys);\n    }\n\n    /**\n     * 从缓存中移除指定key\n     * \n     * @param cacheName\n     * @param keys\n     */\n    public static void removeByKeys(String cacheName, Set<String> keys)\n    {\n        for (Iterator<String> it = keys.iterator(); it.hasNext();)\n        {\n            remove(it.next());\n        }\n        logger.info(\"清理缓存： {} => {}\", cacheName, keys);\n    }\n\n    /**\n     * 获取缓存键名\n     * \n     * @param key\n     * @return\n     */\n    private static String getKey(String key)\n    {\n        return key;\n    }\n\n    /**\n     * 获得一个Cache，没有则显示日志。\n     * \n     * @param cacheName\n     * @return\n     */\n    public static Cache<String, Object> getCache(String cacheName)\n    {\n        Cache<String, Object> cache = cacheManager.getCache(cacheName);\n        if (cache == null)\n        {\n            throw new RuntimeException(\"当前系统中没有定义“\" + cacheName + \"”这个缓存。\");\n        }\n        return cache;\n    }\n\n    /**\n     * 获取所有缓存\n     * \n     * @return 缓存组\n     */\n    public static String[] getCacheNames()\n    {\n        return ((EhCacheManager) cacheManager).getCacheManager().getCacheNames();\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/CookieUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.net.URLDecoder;\r\nimport java.net.URLEncoder;\r\nimport jakarta.servlet.http.Cookie;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\n\r\n/**\r\n * Cookie工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class CookieUtils\r\n{\r\n    /**\r\n     * 设置 Cookie（生成时间为1天）\r\n     * \r\n     * @param name 名称\r\n     * @param value 值\r\n     */\r\n    public static void setCookie(HttpServletResponse response, String name, String value)\r\n    {\r\n        setCookie(response, name, value, 60 * 60 * 24);\r\n    }\r\n\r\n    /**\r\n     * 设置 Cookie\r\n     * \r\n     * @param name 名称\r\n     * @param value 值\r\n     * @param maxAge 生存时间（单位秒）\r\n     * @param uri 路径\r\n     */\r\n    public static void setCookie(HttpServletResponse response, String name, String value, String path)\r\n    {\r\n        setCookie(response, name, value, path, 60 * 60 * 24);\r\n    }\r\n\r\n    /**\r\n     * 设置 Cookie\r\n     * \r\n     * @param name 名称\r\n     * @param value 值\r\n     * @param maxAge 生存时间（单位秒）\r\n     * @param uri 路径\r\n     */\r\n    public static void setCookie(HttpServletResponse response, String name, String value, int maxAge)\r\n    {\r\n        setCookie(response, name, value, \"/\", maxAge);\r\n    }\r\n\r\n    /**\r\n     * 设置 Cookie\r\n     * \r\n     * @param name 名称\r\n     * @param value 值\r\n     * @param maxAge 生存时间（单位秒）\r\n     * @param uri 路径\r\n     */\r\n    public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge)\r\n    {\r\n        Cookie cookie = new Cookie(name, null);\r\n        cookie.setPath(path);\r\n        cookie.setMaxAge(maxAge);\r\n        try\r\n        {\r\n            cookie.setValue(URLEncoder.encode(value, \"utf-8\"));\r\n        }\r\n        catch (UnsupportedEncodingException e)\r\n        {\r\n            e.printStackTrace();\r\n        }\r\n        response.addCookie(cookie);\r\n    }\r\n\r\n    /**\r\n     * 获得指定Cookie的值\r\n     * \r\n     * @param name 名称\r\n     * @return 值\r\n     */\r\n    public static String getCookie(HttpServletRequest request, String name)\r\n    {\r\n        return getCookie(request, null, name, false);\r\n    }\r\n\r\n    /**\r\n     * 获得指定Cookie的值，并删除。\r\n     * \r\n     * @param name 名称\r\n     * @return 值\r\n     */\r\n    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name)\r\n    {\r\n        return getCookie(request, response, name, true);\r\n    }\r\n\r\n    /**\r\n     * 获得指定Cookie的值\r\n     * \r\n     * @param request 请求对象\r\n     * @param response 响应对象\r\n     * @param name 名字\r\n     * @param isRemove 是否移除\r\n     * @return 值\r\n     */\r\n    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name,\r\n            boolean isRemove)\r\n    {\r\n        String value = null;\r\n        Cookie[] cookies = request.getCookies();\r\n        if (cookies != null)\r\n        {\r\n            for (Cookie cookie : cookies)\r\n            {\r\n                if (cookie.getName().equals(name))\r\n                {\r\n                    try\r\n                    {\r\n                        value = URLDecoder.decode(cookie.getValue(), \"utf-8\");\r\n                    }\r\n                    catch (UnsupportedEncodingException e)\r\n                    {\r\n                        e.printStackTrace();\r\n                    }\r\n                    if (isRemove)\r\n                    {\r\n                        cookie.setMaxAge(0);\r\n                        response.addCookie(cookie);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        return value;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.lang.management.ManagementFactory;\r\nimport java.text.ParseException;\r\nimport java.text.SimpleDateFormat;\r\nimport java.time.LocalDate;\r\nimport java.time.LocalDateTime;\r\nimport java.time.LocalTime;\r\nimport java.time.ZoneId;\r\nimport java.time.ZonedDateTime;\r\nimport java.util.Date;\r\nimport org.apache.commons.lang3.time.DateFormatUtils;\r\n\r\n/**\r\n * 时间工具类\r\n * \r\n * @author ruoyi\r\n */\r\n@SuppressWarnings(\"deprecation\")\r\npublic class DateUtils extends org.apache.commons.lang3.time.DateUtils\r\n{\r\n    public static String YYYY = \"yyyy\";\r\n\r\n    public static String YYYY_MM = \"yyyy-MM\";\r\n\r\n    public static String YYYY_MM_DD = \"yyyy-MM-dd\";\r\n\r\n    public static String YYYYMMDDHHMMSS = \"yyyyMMddHHmmss\";\r\n\r\n    public static String YYYY_MM_DD_HH_MM_SS = \"yyyy-MM-dd HH:mm:ss\";\r\n\r\n    private static String[] parsePatterns = {\r\n            \"yyyy-MM-dd\", \"yyyy-MM-dd HH:mm:ss\", \"yyyy-MM-dd HH:mm\", \"yyyy-MM\", \r\n            \"yyyy/MM/dd\", \"yyyy/MM/dd HH:mm:ss\", \"yyyy/MM/dd HH:mm\", \"yyyy/MM\",\r\n            \"yyyy.MM.dd\", \"yyyy.MM.dd HH:mm:ss\", \"yyyy.MM.dd HH:mm\", \"yyyy.MM\"};\r\n\r\n    /**\r\n     * 获取当前Date型日期\r\n     * \r\n     * @return Date() 当前日期\r\n     */\r\n    public static Date getNowDate()\r\n    {\r\n        return new Date();\r\n    }\r\n\r\n    /**\r\n     * 获取当前日期, 默认格式为yyyy-MM-dd\r\n     * \r\n     * @return String\r\n     */\r\n    public static String getDate()\r\n    {\r\n        return dateTimeNow(YYYY_MM_DD);\r\n    }\r\n\r\n    public static final String getTime()\r\n    {\r\n        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);\r\n    }\r\n\r\n    public static final String dateTimeNow()\r\n    {\r\n        return dateTimeNow(YYYYMMDDHHMMSS);\r\n    }\r\n\r\n    public static final String dateTimeNow(final String format)\r\n    {\r\n        return parseDateToStr(format, new Date());\r\n    }\r\n\r\n    public static final String dateTime(final Date date)\r\n    {\r\n        return parseDateToStr(YYYY_MM_DD, date);\r\n    }\r\n\r\n    public static final String parseDateToStr(final String format, final Date date)\r\n    {\r\n        return new SimpleDateFormat(format).format(date);\r\n    }\r\n\r\n    public static final Date dateTime(final String format, final String ts)\r\n    {\r\n        try\r\n        {\r\n            return new SimpleDateFormat(format).parse(ts);\r\n        }\r\n        catch (ParseException e)\r\n        {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 日期路径 即年/月/日 如2018/08/08\r\n     */\r\n    public static final String datePath()\r\n    {\r\n        Date now = new Date();\r\n        return DateFormatUtils.format(now, \"yyyy/MM/dd\");\r\n    }\r\n\r\n    /**\r\n     * 日期路径 即年/月/日 如20180808\r\n     */\r\n    public static final String dateTime()\r\n    {\r\n        Date now = new Date();\r\n        return DateFormatUtils.format(now, \"yyyyMMdd\");\r\n    }\r\n\r\n    /**\r\n     * 日期型字符串转化为日期 格式\r\n     */\r\n    public static Date parseDate(Object str)\r\n    {\r\n        if (str == null)\r\n        {\r\n            return null;\r\n        }\r\n        try\r\n        {\r\n            return parseDate(str.toString(), parsePatterns);\r\n        }\r\n        catch (ParseException e)\r\n        {\r\n            return null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取服务器启动时间\r\n     */\r\n    public static Date getServerStartDate()\r\n    {\r\n        long time = ManagementFactory.getRuntimeMXBean().getStartTime();\r\n        return new Date(time);\r\n    }\r\n\r\n    /**\r\n     * 计算相差天数\r\n     */\r\n    public static int differentDaysByMillisecond(Date date1, Date date2)\r\n    {\r\n        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));\r\n    }\r\n\r\n    /**\r\n     * 计算时间差\r\n     *\r\n     * @param endDate 最后时间\r\n     * @param startTime 开始时间\r\n     * @return 时间差（天/小时/分钟）\r\n     */\r\n    public static String timeDistance(Date endDate, Date startTime)\r\n    {\r\n        long nd = 1000 * 24 * 60 * 60;\r\n        long nh = 1000 * 60 * 60;\r\n        long nm = 1000 * 60;\r\n        // long ns = 1000;\r\n        // 获得两个时间的毫秒时间差异\r\n        long diff = endDate.getTime() - startTime.getTime();\r\n        // 计算差多少天\r\n        long day = diff / nd;\r\n        // 计算差多少小时\r\n        long hour = diff % nd / nh;\r\n        // 计算差多少分钟\r\n        long min = diff % nd % nh / nm;\r\n        // 计算差多少秒//输出结果\r\n        // long sec = diff % nd % nh % nm / ns;\r\n        return day + \"天\" + hour + \"小时\" + min + \"分钟\";\r\n    }\r\n\r\n    /**\r\n     * 增加 LocalDateTime ==> Date\r\n     */\r\n    public static Date toDate(LocalDateTime temporalAccessor)\r\n    {\r\n        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());\r\n        return Date.from(zdt.toInstant());\r\n    }\r\n\r\n    /**\r\n     * 增加 LocalDate ==> Date\r\n     */\r\n    public static Date toDate(LocalDate temporalAccessor)\r\n    {\r\n        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));\r\n        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());\r\n        return Date.from(zdt.toInstant());\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java",
    "content": "package com.ruoyi.common.utils;\n\n/**\n * 脱敏工具类\n *\n * @author ruoyi\n */\npublic class DesensitizedUtil\n{\n    /**\n     * 密码的全部字符都用*代替，比如：******\n     *\n     * @param password 密码\n     * @return 脱敏后的密码\n     */\n    public static String password(String password)\n    {\n        if (StringUtils.isBlank(password))\n        {\n            return StringUtils.EMPTY;\n        }\n        return StringUtils.repeat('*', password.length());\n    }\n\n    /**\n     * 车牌中间用*代替，如果是错误的车牌，不处理\n     *\n     * @param carLicense 完整的车牌号\n     * @return 脱敏后的车牌\n     */\n    public static String carLicense(String carLicense)\n    {\n        if (StringUtils.isBlank(carLicense))\n        {\n            return StringUtils.EMPTY;\n        }\n        // 普通车牌\n        if (carLicense.length() == 7)\n        {\n            carLicense = StringUtils.hide(carLicense, 3, 6);\n        }\n        else if (carLicense.length() == 8)\n        {\n            // 新能源车牌\n            carLicense = StringUtils.hide(carLicense, 3, 7);\n        }\n        return carLicense;\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java",
    "content": "package com.ruoyi.common.utils;\n\nimport java.util.List;\nimport org.springframework.stereotype.Component;\nimport com.ruoyi.common.constant.Constants;\nimport com.ruoyi.common.core.domain.entity.SysDictData;\n\n/**\n * 字典工具类\n * \n * @author ruoyi\n */\n@Component\npublic class DictUtils\n{\n    /**\n     * 分隔符\n     */\n    public static final String SEPARATOR = \",\";\n\n    /**\n     * 设置字典缓存\n     * \n     * @param key 参数键\n     * @param dictDatas 字典数据列表\n     */\n    public static void setDictCache(String key, List<SysDictData> dictDatas)\n    {\n        CacheUtils.put(getCacheName(), getCacheKey(key), dictDatas);\n    }\n\n    /**\n     * 获取字典缓存\n     * \n     * @param key 参数键\n     * @return dictDatas 字典数据列表\n     */\n    public static List<SysDictData> getDictCache(String key)\n    {\n        Object cacheObj = CacheUtils.get(getCacheName(), getCacheKey(key));\n        if (StringUtils.isNotNull(cacheObj))\n        {\n            return StringUtils.cast(cacheObj);\n        }\n        return null;\n    }\n\n    /**\n     * 根据字典类型和字典值获取字典标签\n     * \n     * @param dictType 字典类型\n     * @param dictValue 字典值\n     * @return 字典标签\n     */\n    public static String getDictLabel(String dictType, String dictValue)\n    {\n        if (StringUtils.isEmpty(dictValue))\n        {\n            return StringUtils.EMPTY;\n        }\n        return getDictLabel(dictType, dictValue, SEPARATOR);\n    }\n\n    /**\n     * 根据字典类型和字典标签获取字典值\n     * \n     * @param dictType 字典类型\n     * @param dictLabel 字典标签\n     * @return 字典值\n     */\n    public static String getDictValue(String dictType, String dictLabel)\n    {\n        if (StringUtils.isEmpty(dictLabel))\n        {\n            return StringUtils.EMPTY;\n        }\n        return getDictValue(dictType, dictLabel, SEPARATOR);\n    }\n\n    /**\n     * 根据字典类型和字典值获取字典标签\n     * \n     * @param dictType 字典类型\n     * @param dictValue 字典值\n     * @param separator 分隔符\n     * @return 字典标签\n     */\n    public static String getDictLabel(String dictType, String dictValue, String separator)\n    {\n        StringBuilder propertyString = new StringBuilder();\n        List<SysDictData> datas = getDictCache(dictType);\n        if (StringUtils.isNull(datas))\n        {\n            return StringUtils.EMPTY;\n        }\n        if (StringUtils.containsAny(dictValue, separator))\n        {\n            for (SysDictData dict : datas)\n            {\n                for (String value : dictValue.split(separator))\n                {\n                    if (value.equals(dict.getDictValue()))\n                    {\n                        propertyString.append(dict.getDictLabel()).append(separator);\n                        break;\n                    }\n                }\n            }\n        }\n        else\n        {\n            for (SysDictData dict : datas)\n            {\n                if (dictValue.equals(dict.getDictValue()))\n                {\n                    return dict.getDictLabel();\n                }\n            }\n        }\n        return StringUtils.stripEnd(propertyString.toString(), separator);\n    }\n\n    /**\n     * 根据字典类型和字典标签获取字典值\n     * \n     * @param dictType 字典类型\n     * @param dictLabel 字典标签\n     * @param separator 分隔符\n     * @return 字典值\n     */\n    public static String getDictValue(String dictType, String dictLabel, String separator)\n    {\n        StringBuilder propertyString = new StringBuilder();\n        List<SysDictData> datas = getDictCache(dictType);\n        if (StringUtils.isNull(datas))\n        {\n            return StringUtils.EMPTY;\n        }\n        if (StringUtils.containsAny(dictLabel, separator))\n        {\n            for (SysDictData dict : datas)\n            {\n                for (String label : dictLabel.split(separator))\n                {\n                    if (label.equals(dict.getDictLabel()))\n                    {\n                        propertyString.append(dict.getDictValue()).append(separator);\n                        break;\n                    }\n                }\n            }\n        }\n        else\n        {\n            for (SysDictData dict : datas)\n            {\n                if (dictLabel.equals(dict.getDictLabel()))\n                {\n                    return dict.getDictValue();\n                }\n            }\n        }\n        return StringUtils.stripEnd(propertyString.toString(), separator);\n    }\n\n    /**\n     * 根据字典类型获取字典所有值\n     *\n     * @param dictType 字典类型\n     * @return 字典值\n     */\n    public static String getDictValues(String dictType)\n    {\n        StringBuilder propertyString = new StringBuilder();\n        List<SysDictData> datas = getDictCache(dictType);\n        if (StringUtils.isNull(datas))\n        {\n            return StringUtils.EMPTY;\n        }\n        for (SysDictData dict : datas)\n        {\n            propertyString.append(dict.getDictValue()).append(SEPARATOR);\n        }\n        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);\n    }\n\n    /**\n     * 根据字典类型获取字典所有标签\n     *\n     * @param dictType 字典类型\n     * @return 字典值\n     */\n    public static String getDictLabels(String dictType)\n    {\n        StringBuilder propertyString = new StringBuilder();\n        List<SysDictData> datas = getDictCache(dictType);\n        if (StringUtils.isNull(datas))\n        {\n            return StringUtils.EMPTY;\n        }\n        for (SysDictData dict : datas)\n        {\n            propertyString.append(dict.getDictLabel()).append(SEPARATOR);\n        }\n        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);\n    }\n\n    /**\n     * 删除指定字典缓存\n     * \n     * @param key 字典键\n     */\n    public static void removeDictCache(String key)\n    {\n        CacheUtils.remove(getCacheName(), getCacheKey(key));\n    }\n\n    /**\n     * 清空字典缓存\n     */\n    public static void clearDictCache()\n    {\n        CacheUtils.removeAll(getCacheName());\n    }\n\n    /**\n     * 获取cache name\n     * \n     * @return 缓存名\n     */\n    public static String getCacheName()\n    {\n        return Constants.SYS_DICT_CACHE;\n    }\n\n    /**\n     * 设置cache key\n     * \n     * @param configKey 参数键\n     * @return 缓存键key\n     */\n    public static String getCacheKey(String configKey)\n    {\n        return Constants.SYS_DICT_KEY + configKey;\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.io.PrintWriter;\r\nimport java.io.StringWriter;\r\nimport org.apache.commons.lang3.exception.ExceptionUtils;\r\n\r\n/**\r\n * 错误信息处理类。\r\n *\r\n * @author ruoyi\r\n */\r\npublic class ExceptionUtil\r\n{\r\n    /**\r\n     * 获取exception的详细错误信息。\r\n     */\r\n    public static String getExceptionMessage(Throwable e)\r\n    {\r\n        StringWriter sw = new StringWriter();\r\n        e.printStackTrace(new PrintWriter(sw, true));\r\n        return sw.toString();\r\n    }\r\n\r\n    public static String getRootErrorMessage(Exception e)\r\n    {\r\n        Throwable root = ExceptionUtils.getRootCause(e);\r\n        root = (root == null ? e : root);\r\n        if (root == null)\r\n        {\r\n            return \"\";\r\n        }\r\n        String msg = root.getMessage();\r\n        if (msg == null)\r\n        {\r\n            return \"null\";\r\n        }\r\n        return StringUtils.defaultString(msg);\r\n    }\r\n\r\n    /**\r\n     * 检测异常e被触发的原因是不是因为异常cause。\r\n     * \r\n     * @param e 捕获的异常。\r\n     * @param cause 异常触发原因。\r\n     * @return 如果异常e是由cause类异常触发，则返回true；否则返回false。\r\n     */\r\n    public static boolean isCausedBy(final Throwable e, final Class<? extends Throwable> cause)\r\n    {\r\n        if (cause.isAssignableFrom(e.getClass()))\r\n        {\r\n            return true;\r\n        }\r\n        else\r\n        {\r\n            Throwable t = e.getCause();\r\n            while (t != null && t != e)\r\n            {\r\n                if (cause.isAssignableFrom(t.getClass()))\r\n                {\r\n                    return true;\r\n                }\r\n                t = t.getCause();\r\n            }\r\n            return false;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/IpUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.net.InetAddress;\r\nimport java.net.UnknownHostException;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\n\r\n/**\r\n * 获取IP方法\r\n * \r\n * @author ruoyi\r\n */\r\npublic class IpUtils\r\n{\r\n    public final static String REGX_0_255 = \"(25[0-5]|2[0-4]\\\\d|1\\\\d{2}|[1-9]\\\\d|\\\\d)\";\r\n    // 匹配 ip\r\n    public final static String REGX_IP = \"((\" + REGX_0_255 + \"\\\\.){3}\" + REGX_0_255 + \")\";\r\n    public final static String REGX_IP_WILDCARD = \"(((\\\\*\\\\.){3}\\\\*)|(\" + REGX_0_255 + \"(\\\\.\\\\*){3})|(\" + REGX_0_255 + \"\\\\.\" + REGX_0_255 + \")(\\\\.\\\\*){2}\" + \"|((\" + REGX_0_255 + \"\\\\.){3}\\\\*))\";\r\n    // 匹配网段\r\n    public final static String REGX_IP_SEG = \"(\" + REGX_IP + \"\\\\-\" + REGX_IP + \")\";\r\n\r\n    /**\r\n     * 获取客户端IP\r\n     * \r\n     * @param request 请求对象\r\n     * @return IP地址\r\n     */\r\n    public static String getIpAddr(HttpServletRequest request)\r\n    {\r\n        if (request == null)\r\n        {\r\n            return \"unknown\";\r\n        }\r\n        String ip = request.getHeader(\"x-forwarded-for\");\r\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip))\r\n        {\r\n            ip = request.getHeader(\"Proxy-Client-IP\");\r\n        }\r\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip))\r\n        {\r\n            ip = request.getHeader(\"X-Forwarded-For\");\r\n        }\r\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip))\r\n        {\r\n            ip = request.getHeader(\"WL-Proxy-Client-IP\");\r\n        }\r\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip))\r\n        {\r\n            ip = request.getHeader(\"X-Real-IP\");\r\n        }\r\n\r\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip))\r\n        {\r\n            ip = request.getRemoteAddr();\r\n        }\r\n\r\n        return \"0:0:0:0:0:0:0:1\".equals(ip) ? \"127.0.0.1\" : getMultistageReverseProxyIp(ip);\r\n    }\r\n\r\n    /**\r\n     * 检查是否为内部IP地址\r\n     * \r\n     * @param ip IP地址\r\n     * @return 结果\r\n     */\r\n    public static boolean internalIp(String ip)\r\n    {\r\n        byte[] addr = textToNumericFormatV4(ip);\r\n        return internalIp(addr) || \"127.0.0.1\".equals(ip);\r\n    }\r\n\r\n    /**\r\n     * 检查是否为内部IP地址\r\n     * \r\n     * @param addr byte地址\r\n     * @return 结果\r\n     */\r\n    private static boolean internalIp(byte[] addr)\r\n    {\r\n        if (StringUtils.isNull(addr) || addr.length < 2)\r\n        {\r\n            return true;\r\n        }\r\n        final byte b0 = addr[0];\r\n        final byte b1 = addr[1];\r\n        // 10.x.x.x/8\r\n        final byte SECTION_1 = 0x0A;\r\n        // 172.16.x.x/12\r\n        final byte SECTION_2 = (byte) 0xAC;\r\n        final byte SECTION_3 = (byte) 0x10;\r\n        final byte SECTION_4 = (byte) 0x1F;\r\n        // 192.168.x.x/16\r\n        final byte SECTION_5 = (byte) 0xC0;\r\n        final byte SECTION_6 = (byte) 0xA8;\r\n        switch (b0)\r\n        {\r\n            case SECTION_1:\r\n                return true;\r\n            case SECTION_2:\r\n                if (b1 >= SECTION_3 && b1 <= SECTION_4)\r\n                {\r\n                    return true;\r\n                }\r\n            case SECTION_5:\r\n                switch (b1)\r\n                {\r\n                    case SECTION_6:\r\n                        return true;\r\n                }\r\n            default:\r\n                return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 将IPv4地址转换成字节\r\n     * \r\n     * @param text IPv4地址\r\n     * @return byte 字节\r\n     */\r\n    public static byte[] textToNumericFormatV4(String text)\r\n    {\r\n        if (text.length() == 0)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        byte[] bytes = new byte[4];\r\n        String[] elements = text.split(\"\\\\.\", -1);\r\n        try\r\n        {\r\n            long l;\r\n            int i;\r\n            switch (elements.length)\r\n            {\r\n                case 1:\r\n                    l = Long.parseLong(elements[0]);\r\n                    if ((l < 0L) || (l > 4294967295L))\r\n                    {\r\n                        return null;\r\n                    }\r\n                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);\r\n                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);\r\n                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);\r\n                    bytes[3] = (byte) (int) (l & 0xFF);\r\n                    break;\r\n                case 2:\r\n                    l = Integer.parseInt(elements[0]);\r\n                    if ((l < 0L) || (l > 255L))\r\n                    {\r\n                        return null;\r\n                    }\r\n                    bytes[0] = (byte) (int) (l & 0xFF);\r\n                    l = Integer.parseInt(elements[1]);\r\n                    if ((l < 0L) || (l > 16777215L))\r\n                    {\r\n                        return null;\r\n                    }\r\n                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);\r\n                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);\r\n                    bytes[3] = (byte) (int) (l & 0xFF);\r\n                    break;\r\n                case 3:\r\n                    for (i = 0; i < 2; ++i)\r\n                    {\r\n                        l = Integer.parseInt(elements[i]);\r\n                        if ((l < 0L) || (l > 255L))\r\n                        {\r\n                            return null;\r\n                        }\r\n                        bytes[i] = (byte) (int) (l & 0xFF);\r\n                    }\r\n                    l = Integer.parseInt(elements[2]);\r\n                    if ((l < 0L) || (l > 65535L))\r\n                    {\r\n                        return null;\r\n                    }\r\n                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);\r\n                    bytes[3] = (byte) (int) (l & 0xFF);\r\n                    break;\r\n                case 4:\r\n                    for (i = 0; i < 4; ++i)\r\n                    {\r\n                        l = Integer.parseInt(elements[i]);\r\n                        if ((l < 0L) || (l > 255L))\r\n                        {\r\n                            return null;\r\n                        }\r\n                        bytes[i] = (byte) (int) (l & 0xFF);\r\n                    }\r\n                    break;\r\n                default:\r\n                    return null;\r\n            }\r\n        }\r\n        catch (NumberFormatException e)\r\n        {\r\n            return null;\r\n        }\r\n        return bytes;\r\n    }\r\n\r\n    /**\r\n     * 获取IP地址\r\n     * \r\n     * @return 本地IP地址\r\n     */\r\n    public static String getHostIp()\r\n    {\r\n        try\r\n        {\r\n            return InetAddress.getLocalHost().getHostAddress();\r\n        }\r\n        catch (UnknownHostException e)\r\n        {\r\n        }\r\n        return \"127.0.0.1\";\r\n    }\r\n\r\n    /**\r\n     * 获取主机名\r\n     * \r\n     * @return 本地主机名\r\n     */\r\n    public static String getHostName()\r\n    {\r\n        try\r\n        {\r\n            return InetAddress.getLocalHost().getHostName();\r\n        }\r\n        catch (UnknownHostException e)\r\n        {\r\n        }\r\n        return \"未知\";\r\n    }\r\n\r\n    /**\r\n     * 从多级反向代理中获得第一个非unknown IP地址\r\n     *\r\n     * @param ip 获得的IP地址\r\n     * @return 第一个非unknown IP地址\r\n     */\r\n    public static String getMultistageReverseProxyIp(String ip)\r\n    {\r\n        // 多级反向代理检测\r\n        if (ip != null && ip.indexOf(\",\") > 0)\r\n        {\r\n            final String[] ips = ip.trim().split(\",\");\r\n            for (String subIp : ips)\r\n            {\r\n                if (false == isUnknown(subIp))\r\n                {\r\n                    ip = subIp;\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n        return StringUtils.substring(ip, 0, 255);\r\n    }\r\n\r\n    /**\r\n     * 检测给定字符串是否为未知，多用于检测HTTP请求相关\r\n     *\r\n     * @param checkString 被检测的字符串\r\n     * @return 是否未知\r\n     */\r\n    public static boolean isUnknown(String checkString)\r\n    {\r\n        return StringUtils.isBlank(checkString) || \"unknown\".equalsIgnoreCase(checkString);\r\n    }\r\n\r\n    /**\r\n     * 是否为IP\r\n     */\r\n    public static boolean isIP(String ip)\r\n    {\r\n        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);\r\n    }\r\n\r\n    /**\r\n     * 是否为IP，或 *为间隔的通配符地址\r\n     */\r\n    public static boolean isIpWildCard(String ip)\r\n    {\r\n        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);\r\n    }\r\n\r\n    /**\r\n     * 检测参数是否在ip通配符里\r\n     */\r\n    public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)\r\n    {\r\n        String[] s1 = ipWildCard.split(\"\\\\.\");\r\n        String[] s2 = ip.split(\"\\\\.\");\r\n        boolean isMatchedSeg = true;\r\n        for (int i = 0; i < s1.length && !s1[i].equals(\"*\"); i++)\r\n        {\r\n            if (!s1[i].equals(s2[i]))\r\n            {\r\n                isMatchedSeg = false;\r\n                break;\r\n            }\r\n        }\r\n        return isMatchedSeg;\r\n    }\r\n\r\n    /**\r\n     * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串\r\n     */\r\n    public static boolean isIPSegment(String ipSeg)\r\n    {\r\n        return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);\r\n    }\r\n\r\n    /**\r\n     * 判断ip是否在指定网段中\r\n     */\r\n    public static boolean ipIsInNetNoCheck(String iparea, String ip)\r\n    {\r\n        int idx = iparea.indexOf('-');\r\n        String[] sips = iparea.substring(0, idx).split(\"\\\\.\");\r\n        String[] sipe = iparea.substring(idx + 1).split(\"\\\\.\");\r\n        String[] sipt = ip.split(\"\\\\.\");\r\n        long ips = 0L, ipe = 0L, ipt = 0L;\r\n        for (int i = 0; i < 4; ++i)\r\n        {\r\n            ips = ips << 8 | Integer.parseInt(sips[i]);\r\n            ipe = ipe << 8 | Integer.parseInt(sipe[i]);\r\n            ipt = ipt << 8 | Integer.parseInt(sipt[i]);\r\n        }\r\n        if (ips > ipe)\r\n        {\r\n            long t = ips;\r\n            ips = ipe;\r\n            ipe = t;\r\n        }\r\n        return ips <= ipt && ipt <= ipe;\r\n    }\r\n\r\n    /**\r\n     * 校验ip是否符合过滤串规则\r\n     * \r\n     * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`\r\n     * @param ip 校验IP地址\r\n     * @return boolean 结果\r\n     */\r\n    public static boolean isMatchedIp(String filter, String ip)\r\n    {\r\n        if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))\r\n        {\r\n            return false;\r\n        }\r\n        String[] ips = filter.split(\";\");\r\n        for (String iStr : ips)\r\n        {\r\n            if (isIP(iStr) && iStr.equals(ip))\r\n            {\r\n                return true;\r\n            }\r\n            else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))\r\n            {\r\n                return true;\r\n            }\r\n            else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))\r\n            {\r\n                return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.io.PrintWriter;\r\nimport java.io.StringWriter;\r\nimport java.util.Map;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport org.apache.shiro.SecurityUtils;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.json.JSON;\r\n\r\n/**\r\n * 处理并记录日志文件\r\n * \r\n * @author ruoyi\r\n */\r\npublic class LogUtils\r\n{\r\n    public static final Logger ERROR_LOG = LoggerFactory.getLogger(\"sys-error\");\r\n    public static final Logger ACCESS_LOG = LoggerFactory.getLogger(\"sys-access\");\r\n\r\n    /**\r\n     * 记录访问日志 [username][jsessionid][ip][accept][UserAgent][url][params][Referer]\r\n     *\r\n     * @param request\r\n     * @throws Exception\r\n     */\r\n    public static void logAccess(HttpServletRequest request) throws Exception\r\n    {\r\n        String username = getUsername();\r\n        String jsessionId = request.getRequestedSessionId();\r\n        String ip = IpUtils.getIpAddr(request);\r\n        String accept = request.getHeader(\"accept\");\r\n        String userAgent = request.getHeader(\"User-Agent\");\r\n        String url = request.getRequestURI();\r\n        String params = getParams(request);\r\n\r\n        StringBuilder s = new StringBuilder();\r\n        s.append(getBlock(username));\r\n        s.append(getBlock(jsessionId));\r\n        s.append(getBlock(ip));\r\n        s.append(getBlock(accept));\r\n        s.append(getBlock(userAgent));\r\n        s.append(getBlock(url));\r\n        s.append(getBlock(params));\r\n        s.append(getBlock(request.getHeader(\"Referer\")));\r\n        getAccessLog().info(s.toString());\r\n    }\r\n\r\n    /**\r\n     * 记录异常错误 格式 [exception]\r\n     *\r\n     * @param message\r\n     * @param e\r\n     */\r\n    public static void logError(String message, Throwable e)\r\n    {\r\n        String username = getUsername();\r\n        StringBuilder s = new StringBuilder();\r\n        s.append(getBlock(\"exception\"));\r\n        s.append(getBlock(username));\r\n        s.append(getBlock(message));\r\n        ERROR_LOG.error(s.toString(), e);\r\n    }\r\n\r\n    /**\r\n     * 记录页面错误 错误日志记录 [page/eception][username][statusCode][errorMessage][servletName][uri][exceptionName][ip][exception]\r\n     *\r\n     * @param request\r\n     */\r\n    public static void logPageError(HttpServletRequest request)\r\n    {\r\n        String username = getUsername();\r\n\r\n        Integer statusCode = (Integer) request.getAttribute(\"jakarta.servlet.error.status_code\");\r\n        String message = (String) request.getAttribute(\"jakarta.servlet.error.message\");\r\n        String uri = (String) request.getAttribute(\"jakarta.servlet.error.request_uri\");\r\n        Throwable t = (Throwable) request.getAttribute(\"jakarta.servlet.error.exception\");\r\n\r\n        if (statusCode == null)\r\n        {\r\n            statusCode = 0;\r\n        }\r\n\r\n        StringBuilder s = new StringBuilder();\r\n        s.append(getBlock(t == null ? \"page\" : \"exception\"));\r\n        s.append(getBlock(username));\r\n        s.append(getBlock(statusCode));\r\n        s.append(getBlock(message));\r\n        s.append(getBlock(IpUtils.getIpAddr(request)));\r\n\r\n        s.append(getBlock(uri));\r\n        s.append(getBlock(request.getHeader(\"Referer\")));\r\n        StringWriter sw = new StringWriter();\r\n\r\n        while (t != null)\r\n        {\r\n            t.printStackTrace(new PrintWriter(sw));\r\n            t = t.getCause();\r\n        }\r\n        s.append(getBlock(sw.toString()));\r\n        getErrorLog().error(s.toString());\r\n\r\n    }\r\n\r\n    public static String getBlock(Object msg)\r\n    {\r\n        if (msg == null)\r\n        {\r\n            msg = \"\";\r\n        }\r\n        return \"[\" + msg.toString() + \"]\";\r\n    }\r\n\r\n    protected static String getParams(HttpServletRequest request) throws Exception\r\n    {\r\n        Map<String, String[]> params = request.getParameterMap();\r\n        return JSON.marshal(params);\r\n    }\r\n\r\n    protected static String getUsername()\r\n    {\r\n        return (String) SecurityUtils.getSubject().getPrincipal();\r\n    }\r\n\r\n    public static Logger getAccessLog()\r\n    {\r\n        return ACCESS_LOG;\r\n    }\r\n\r\n    public static Logger getErrorLog()\r\n    {\r\n        return ERROR_LOG;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/MapDataUtil.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.Iterator;\r\nimport java.util.Map;\r\nimport java.util.Map.Entry;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\n\r\n/**\r\n * Map通用处理方法\r\n * \r\n * @author ruoyi\r\n */\r\npublic class MapDataUtil\r\n{\r\n    public static Map<String, Object> convertDataMap(HttpServletRequest request)\r\n    {\r\n        Map<String, String[]> properties = request.getParameterMap();\r\n        Map<String, Object> returnMap = new HashMap<String, Object>();\r\n        Iterator<?> entries = properties.entrySet().iterator();\r\n        Map.Entry<?, ?> entry;\r\n        String name = \"\";\r\n        String value = \"\";\r\n        while (entries.hasNext())\r\n        {\r\n            entry = (Entry<?, ?>) entries.next();\r\n            name = (String) entry.getKey();\r\n            Object valueObj = entry.getValue();\r\n            if (null == valueObj)\r\n            {\r\n                value = \"\";\r\n            }\r\n            else if (valueObj instanceof String[])\r\n            {\r\n                String[] values = (String[]) valueObj;\r\n                value = \"\";\r\n                for (int i = 0; i < values.length; i++)\r\n                {\r\n                    value += values[i] + \",\";\r\n                }\r\n                if (value.length() > 0)\r\n                {\r\n                    value = value.substring(0, value.length() - 1);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                value = valueObj.toString();\r\n            }\r\n            returnMap.put(name, value);\r\n        }\r\n        return returnMap;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport org.springframework.context.MessageSource;\r\nimport org.springframework.context.i18n.LocaleContextHolder;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\n\r\n/**\r\n * 获取i18n资源文件\r\n * \r\n * @author ruoyi\r\n */\r\npublic class MessageUtils\r\n{\r\n    /**\r\n     * 根据消息键和参数 获取消息 委托给spring messageSource\r\n     *\r\n     * @param code 消息键\r\n     * @param args 参数\r\n     * @return 获取国际化翻译值\r\n     */\r\n    public static String message(String code, Object... args)\r\n    {\r\n        MessageSource messageSource = SpringUtils.getBean(MessageSource.class);\r\n        return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java",
    "content": "package com.ruoyi.common.utils;\n\nimport com.github.pagehelper.PageHelper;\nimport com.ruoyi.common.core.page.PageDomain;\nimport com.ruoyi.common.core.page.TableSupport;\nimport com.ruoyi.common.utils.sql.SqlUtil;\n\n/**\n * 分页工具类\n * \n * @author ruoyi\n */\npublic class PageUtils extends PageHelper\n{\n    /**\n     * 设置请求分页数据\n     */\n    public static void startPage()\n    {\n        PageDomain pageDomain = TableSupport.buildPageRequest();\n        Integer pageNum = pageDomain.getPageNum();\n        Integer pageSize = pageDomain.getPageSize();\n        String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());\n        Boolean reasonable = pageDomain.getReasonable();\n        PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);\n    }\n\n    /**\n     * 清理分页的线程变量\n     */\n    public static void clearPage()\n    {\n        PageHelper.clearPage();\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.io.IOException;\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.net.URLDecoder;\r\nimport java.net.URLEncoder;\r\nimport java.security.SecureRandom;\r\nimport java.util.Base64;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport jakarta.servlet.http.HttpSession;\r\nimport org.springframework.web.context.request.RequestAttributes;\r\nimport org.springframework.web.context.request.RequestContextHolder;\r\nimport org.springframework.web.context.request.ServletRequestAttributes;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.core.text.Convert;\r\n\r\n/**\r\n * 客户端工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class ServletUtils\r\n{\r\n    /**\r\n     * 定义移动端请求的所有可能类型\r\n     */\r\n    private final static String[] agent = { \"Android\", \"iPhone\", \"iPod\", \"iPad\", \"Windows Phone\", \"MQQBrowser\" };\r\n\r\n    private static final SecureRandom secureRandom = new SecureRandom();\r\n\r\n    /**\r\n     * 获取String参数\r\n     */\r\n    public static String getParameter(String name)\r\n    {\r\n        return getRequest().getParameter(name);\r\n    }\r\n\r\n    /**\r\n     * 获取String参数\r\n     */\r\n    public static String getParameter(String name, String defaultValue)\r\n    {\r\n        return Convert.toStr(getRequest().getParameter(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 获取Integer参数\r\n     */\r\n    public static Integer getParameterToInt(String name)\r\n    {\r\n        return Convert.toInt(getRequest().getParameter(name));\r\n    }\r\n\r\n    /**\r\n     * 获取Integer参数\r\n     */\r\n    public static Integer getParameterToInt(String name, Integer defaultValue)\r\n    {\r\n        return Convert.toInt(getRequest().getParameter(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 获取Boolean参数\r\n     */\r\n    public static Boolean getParameterToBool(String name)\r\n    {\r\n        return Convert.toBool(getRequest().getParameter(name));\r\n    }\r\n\r\n    /**\r\n     * 获取Boolean参数\r\n     */\r\n    public static Boolean getParameterToBool(String name, Boolean defaultValue)\r\n    {\r\n        return Convert.toBool(getRequest().getParameter(name), defaultValue);\r\n    }\r\n\r\n    /**\r\n     * 获取request\r\n     */\r\n    public static HttpServletRequest getRequest()\r\n    {\r\n        return getRequestAttributes().getRequest();\r\n    }\r\n\r\n    /**\r\n     * 获取response\r\n     */\r\n    public static HttpServletResponse getResponse()\r\n    {\r\n        return getRequestAttributes().getResponse();\r\n    }\r\n\r\n    /**\r\n     * 获取session\r\n     */\r\n    public static HttpSession getSession()\r\n    {\r\n        return getRequest().getSession();\r\n    }\r\n\r\n    public static ServletRequestAttributes getRequestAttributes()\r\n    {\r\n        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();\r\n        return (ServletRequestAttributes) attributes;\r\n    }\r\n\r\n    /**\r\n     * 将字符串渲染到客户端\r\n     * \r\n     * @param response 渲染对象\r\n     * @param string 待渲染的字符串\r\n     * @return null\r\n     */\r\n    public static String renderString(HttpServletResponse response, String string)\r\n    {\r\n        try\r\n        {\r\n            response.setContentType(\"application/json\");\r\n            response.setCharacterEncoding(\"utf-8\");\r\n            response.getWriter().print(string);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            e.printStackTrace();\r\n        }\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * 是否是Ajax异步请求\r\n     * \r\n     * @param request\r\n     */\r\n    public static boolean isAjaxRequest(HttpServletRequest request)\r\n    {\r\n        String accept = request.getHeader(\"accept\");\r\n        if (accept != null && accept.contains(\"application/json\"))\r\n        {\r\n            return true;\r\n        }\r\n\r\n        String xRequestedWith = request.getHeader(\"X-Requested-With\");\r\n        if (xRequestedWith != null && xRequestedWith.contains(\"XMLHttpRequest\"))\r\n        {\r\n            return true;\r\n        }\r\n\r\n        String uri = request.getRequestURI();\r\n        if (StringUtils.inStringIgnoreCase(uri, \".json\", \".xml\"))\r\n        {\r\n            return true;\r\n        }\r\n\r\n        String ajax = request.getParameter(\"__ajax\");\r\n        return StringUtils.inStringIgnoreCase(ajax, \"json\", \"xml\");\r\n    }\r\n\r\n    /**\r\n     * 判断User-Agent 是不是来自于手机\r\n     */\r\n    public static boolean checkAgentIsMobile(String ua)\r\n    {\r\n        boolean flag = false;\r\n        if (!ua.contains(\"Windows NT\") || (ua.contains(\"Windows NT\") && ua.contains(\"compatible; MSIE 9.0;\")))\r\n        {\r\n            // 排除 苹果桌面系统\r\n            if (!ua.contains(\"Windows NT\") && !ua.contains(\"Macintosh\"))\r\n            {\r\n                for (String item : agent)\r\n                {\r\n                    if (ua.contains(item))\r\n                    {\r\n                        flag = true;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        return flag;\r\n    }\r\n\r\n    /**\r\n     * 内容编码\r\n     * \r\n     * @param str 内容\r\n     * @return 编码后的内容\r\n     */\r\n    public static String urlEncode(String str)\r\n    {\r\n        try\r\n        {\r\n            return URLEncoder.encode(str, Constants.UTF8);\r\n        }\r\n        catch (UnsupportedEncodingException e)\r\n        {\r\n            return StringUtils.EMPTY;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 内容解码\r\n     * \r\n     * @param str 内容\r\n     * @return 解码后的内容\r\n     */\r\n    public static String urlDecode(String str)\r\n    {\r\n        try\r\n        {\r\n            return URLDecoder.decode(str, Constants.UTF8);\r\n        }\r\n        catch (UnsupportedEncodingException e)\r\n        {\r\n            return StringUtils.EMPTY;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 生成CSRF Token\r\n     * \r\n     * @return 解码后的内容\r\n     */\r\n    public static String generateToken()\r\n    {\r\n        byte[] bytes = new byte[32];\r\n        secureRandom.nextBytes(bytes);\r\n        return Base64.getEncoder().encodeToString(bytes);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/ShiroUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport org.apache.shiro.SecurityUtils;\r\nimport org.apache.shiro.crypto.SecureRandomNumberGenerator;\r\nimport org.apache.shiro.session.Session;\r\nimport org.apache.shiro.subject.Subject;\r\nimport org.apache.shiro.subject.PrincipalCollection;\r\nimport org.apache.shiro.subject.SimplePrincipalCollection;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.utils.bean.BeanUtils;\r\n\r\n/**\r\n * shiro 工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class ShiroUtils\r\n{\r\n    public static Subject getSubject()\r\n    {\r\n        return SecurityUtils.getSubject();\r\n    }\r\n\r\n    public static Session getSession()\r\n    {\r\n        return SecurityUtils.getSubject().getSession();\r\n    }\r\n\r\n    public static void logout()\r\n    {\r\n        getSubject().logout();\r\n    }\r\n\r\n    public static SysUser getSysUser()\r\n    {\r\n        SysUser user = null;\r\n        Object obj = getSubject().getPrincipal();\r\n        if (StringUtils.isNotNull(obj))\r\n        {\r\n            user = new SysUser();\r\n            BeanUtils.copyBeanProp(user, obj);\r\n        }\r\n        return user;\r\n    }\r\n\r\n    public static void setSysUser(SysUser user)\r\n    {\r\n        Subject subject = getSubject();\r\n        PrincipalCollection principalCollection = subject.getPrincipals();\r\n        String realmName = principalCollection.getRealmNames().iterator().next();\r\n        PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(user, realmName);\r\n        // 重新加载Principal\r\n        subject.runAs(newPrincipalCollection);\r\n    }\r\n\r\n    public static Long getUserId()\r\n    {\r\n        return getSysUser().getUserId().longValue();\r\n    }\r\n\r\n    public static String getLoginName()\r\n    {\r\n        return getSysUser().getLoginName();\r\n    }\r\n\r\n    public static String getIp()\r\n    {\r\n        return StringUtils.substring(getSubject().getSession().getHost(), 0, 128);\r\n    }\r\n\r\n    public static String getSessionId()\r\n    {\r\n        return String.valueOf(getSubject().getSession().getId());\r\n    }\r\n\r\n    /**\r\n     * 是否为管理员\r\n     * \r\n     * @return 结果\r\n     */\r\n    public static boolean isAdmin()\r\n    {\r\n        return isAdmin(getUserId());\r\n    }\r\n\r\n    /**\r\n     * 是否为管理员\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    public static boolean isAdmin(Long userId)\r\n    {\r\n        return userId != null && 1L == userId;\r\n    }\r\n\r\n    /**\r\n     * 生成随机盐\r\n     */\r\n    public static String randomSalt()\r\n    {\r\n        // 一个Byte占两个字节，此处生成的3字节，字符串长度为6\r\n        SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();\r\n        String hex = secureRandom.nextBytes(3).toHex();\r\n        return hex;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java",
    "content": "package com.ruoyi.common.utils;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.HashSet;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.Set;\r\nimport org.apache.commons.lang3.Strings;\r\nimport org.springframework.util.AntPathMatcher;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.core.text.StrFormatter;\r\n\r\n/**\r\n * 字符串工具类\r\n * \r\n * @author ruoyi\r\n */\r\n@SuppressWarnings(\"deprecation\")\r\npublic class StringUtils extends org.apache.commons.lang3.StringUtils\r\n{\r\n    /** 空字符串 */\r\n    private static final String NULLSTR = \"\";\r\n\r\n    /** 下划线 */\r\n    private static final char SEPARATOR = '_';\r\n\r\n    /** 星号 */\r\n    private static final char ASTERISK = '*';\r\n\r\n    /**\r\n     * 获取参数不为空值\r\n     * \r\n     * @param value defaultValue 要判断的value\r\n     * @return value 返回值\r\n     */\r\n    public static <T> T nvl(T value, T defaultValue)\r\n    {\r\n        return value != null ? value : defaultValue;\r\n    }\r\n\r\n    /**\r\n     * * 判断一个Collection是否为空， 包含List，Set，Queue\r\n     * \r\n     * @param coll 要判断的Collection\r\n     * @return true：为空 false：非空\r\n     */\r\n    public static boolean isEmpty(Collection<?> coll)\r\n    {\r\n        return isNull(coll) || coll.isEmpty();\r\n    }\r\n\r\n    /**\r\n     * * 判断一个Collection是否非空，包含List，Set，Queue\r\n     * \r\n     * @param coll 要判断的Collection\r\n     * @return true：非空 false：空\r\n     */\r\n    public static boolean isNotEmpty(Collection<?> coll)\r\n    {\r\n        return !isEmpty(coll);\r\n    }\r\n\r\n    /**\r\n     * * 判断一个对象数组是否为空\r\n     * \r\n     * @param objects 要判断的对象数组\r\n     ** @return true：为空 false：非空\r\n     */\r\n    public static boolean isEmpty(Object[] objects)\r\n    {\r\n        return isNull(objects) || (objects.length == 0);\r\n    }\r\n\r\n    /**\r\n     * * 判断一个对象数组是否非空\r\n     * \r\n     * @param objects 要判断的对象数组\r\n     * @return true：非空 false：空\r\n     */\r\n    public static boolean isNotEmpty(Object[] objects)\r\n    {\r\n        return !isEmpty(objects);\r\n    }\r\n\r\n    /**\r\n     * * 判断一个Map是否为空\r\n     * \r\n     * @param map 要判断的Map\r\n     * @return true：为空 false：非空\r\n     */\r\n    public static boolean isEmpty(Map<?, ?> map)\r\n    {\r\n        return isNull(map) || map.isEmpty();\r\n    }\r\n\r\n    /**\r\n     * * 判断一个Map是否为空\r\n     * \r\n     * @param map 要判断的Map\r\n     * @return true：非空 false：空\r\n     */\r\n    public static boolean isNotEmpty(Map<?, ?> map)\r\n    {\r\n        return !isEmpty(map);\r\n    }\r\n\r\n    /**\r\n     * * 判断一个字符串是否为空串\r\n     * \r\n     * @param str String\r\n     * @return true：为空 false：非空\r\n     */\r\n    public static boolean isEmpty(String str)\r\n    {\r\n        return isNull(str) || NULLSTR.equals(str.trim());\r\n    }\r\n\r\n    /**\r\n     * * 判断一个字符串是否为非空串\r\n     * \r\n     * @param str String\r\n     * @return true：非空串 false：空串\r\n     */\r\n    public static boolean isNotEmpty(String str)\r\n    {\r\n        return !isEmpty(str);\r\n    }\r\n\r\n    /**\r\n     * * 判断一个对象是否为空\r\n     * \r\n     * @param object Object\r\n     * @return true：为空 false：非空\r\n     */\r\n    public static boolean isNull(Object object)\r\n    {\r\n        return object == null;\r\n    }\r\n\r\n    /**\r\n     * * 判断一个对象是否非空\r\n     * \r\n     * @param object Object\r\n     * @return true：非空 false：空\r\n     */\r\n    public static boolean isNotNull(Object object)\r\n    {\r\n        return !isNull(object);\r\n    }\r\n\r\n    /**\r\n     * * 判断一个对象是否是数组类型（Java基本型别的数组）\r\n     * \r\n     * @param object 对象\r\n     * @return true：是数组 false：不是数组\r\n     */\r\n    public static boolean isArray(Object object)\r\n    {\r\n        return isNotNull(object) && object.getClass().isArray();\r\n    }\r\n\r\n    /**\r\n     * 去空格\r\n     */\r\n    public static String trim(String str)\r\n    {\r\n        return (str == null ? \"\" : str.trim());\r\n    }\r\n\r\n    /**\r\n     * 替换指定字符串的指定区间内字符为\"*\"\r\n     *\r\n     * @param str 字符串\r\n     * @param startInclude 开始位置（包含）\r\n     * @param endExclude 结束位置（不包含）\r\n     * @return 替换后的字符串\r\n     */\r\n    public static String hide(CharSequence str, int startInclude, int endExclude)\r\n    {\r\n        if (isEmpty(str))\r\n        {\r\n            return NULLSTR;\r\n        }\r\n        final int strLength = str.length();\r\n        if (startInclude > strLength)\r\n        {\r\n            return NULLSTR;\r\n        }\r\n        if (endExclude > strLength)\r\n        {\r\n            endExclude = strLength;\r\n        }\r\n        if (startInclude > endExclude)\r\n        {\r\n            // 如果起始位置大于结束位置，不替换\r\n            return NULLSTR;\r\n        }\r\n        final char[] chars = new char[strLength];\r\n        for (int i = 0; i < strLength; i++)\r\n        {\r\n            if (i >= startInclude && i < endExclude)\r\n            {\r\n                chars[i] = ASTERISK;\r\n            }\r\n            else\r\n            {\r\n                chars[i] = str.charAt(i);\r\n            }\r\n        }\r\n        return new String(chars);\r\n    }\r\n\r\n    /**\r\n     * 截取字符串\r\n     * \r\n     * @param str 字符串\r\n     * @param start 开始\r\n     * @return 结果\r\n     */\r\n    public static String substring(final String str, int start)\r\n    {\r\n        if (str == null)\r\n        {\r\n            return NULLSTR;\r\n        }\r\n\r\n        if (start < 0)\r\n        {\r\n            start = str.length() + start;\r\n        }\r\n\r\n        if (start < 0)\r\n        {\r\n            start = 0;\r\n        }\r\n        if (start > str.length())\r\n        {\r\n            return NULLSTR;\r\n        }\r\n\r\n        return str.substring(start);\r\n    }\r\n\r\n    /**\r\n     * 截取字符串\r\n     * \r\n     * @param str 字符串\r\n     * @param start 开始\r\n     * @param end 结束\r\n     * @return 结果\r\n     */\r\n    public static String substring(final String str, int start, int end)\r\n    {\r\n        if (str == null)\r\n        {\r\n            return NULLSTR;\r\n        }\r\n\r\n        if (end < 0)\r\n        {\r\n            end = str.length() + end;\r\n        }\r\n        if (start < 0)\r\n        {\r\n            start = str.length() + start;\r\n        }\r\n\r\n        if (end > str.length())\r\n        {\r\n            end = str.length();\r\n        }\r\n\r\n        if (start > end)\r\n        {\r\n            return NULLSTR;\r\n        }\r\n\r\n        if (start < 0)\r\n        {\r\n            start = 0;\r\n        }\r\n        if (end < 0)\r\n        {\r\n            end = 0;\r\n        }\r\n\r\n        return str.substring(start, end);\r\n    }\r\n\r\n    /**\r\n     * 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串\r\n     * \r\n     * @param str 要截取的字符串\r\n     * @param open 起始字符串\r\n     * @param close 结束字符串\r\n     * @return 截取结果\r\n     */\r\n    public static String substringBetweenLast(final String str, final String open, final String close)\r\n    {\r\n        if (isEmpty(str) || isEmpty(open) || isEmpty(close))\r\n        {\r\n            return NULLSTR;\r\n        }\r\n        final int start = str.indexOf(open);\r\n        if (start != INDEX_NOT_FOUND)\r\n        {\r\n            final int end = str.lastIndexOf(close);\r\n            if (end != INDEX_NOT_FOUND)\r\n            {\r\n                return str.substring(start + open.length(), end);\r\n            }\r\n        }\r\n        return NULLSTR;\r\n    }\r\n\r\n    /**\r\n     * 格式化文本, {} 表示占位符<br>\r\n     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>\r\n     * 如果想输出 {} 使用 \\\\转义 { 即可，如果想输出 {} 之前的 \\ 使用双转义符 \\\\\\\\ 即可<br>\r\n     * 例：<br>\r\n     * 通常使用：format(\"this is {} for {}\", \"a\", \"b\") -> this is a for b<br>\r\n     * 转义{}： format(\"this is \\\\{} for {}\", \"a\", \"b\") -> this is \\{} for a<br>\r\n     * 转义\\： format(\"this is \\\\\\\\{} for {}\", \"a\", \"b\") -> this is \\a for b<br>\r\n     * \r\n     * @param template 文本模板，被替换的部分用 {} 表示\r\n     * @param params 参数值\r\n     * @return 格式化后的文本\r\n     */\r\n    public static String format(String template, Object... params)\r\n    {\r\n        if (isEmpty(params) || isEmpty(template))\r\n        {\r\n            return template;\r\n        }\r\n        return StrFormatter.format(template, params);\r\n    }\r\n\r\n    /**\r\n     * 是否为http(s)://开头\r\n     * \r\n     * @param link 链接\r\n     * @return 结果\r\n     */\r\n    public static boolean ishttp(String link)\r\n    {\r\n        return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);\r\n    }\r\n\r\n    /**\r\n     * 字符串转set\r\n     * \r\n     * @param str 字符串\r\n     * @param sep 分隔符\r\n     * @return set集合\r\n     */\r\n    public static final Set<String> str2Set(String str, String sep)\r\n    {\r\n        return new HashSet<String>(str2List(str, sep, true, false));\r\n    }\r\n\r\n    /**\r\n     * 字符串转list\r\n     * \r\n     * @param str 字符串\r\n     * @param sep 分隔符\r\n     * @return list集合\r\n     */\r\n    public static final List<String> str2List(String str, String sep)\r\n    {\r\n        return str2List(str, sep, true, false);\r\n    }\r\n\r\n    /**\r\n     * 字符串转list\r\n     * \r\n     * @param str 字符串\r\n     * @param sep 分隔符\r\n     * @param filterBlank 过滤纯空白\r\n     * @param trim 去掉首尾空白\r\n     * @return list集合\r\n     */\r\n    public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)\r\n    {\r\n        List<String> list = new ArrayList<String>();\r\n        if (StringUtils.isEmpty(str))\r\n        {\r\n            return list;\r\n        }\r\n\r\n        // 过滤空白字符串\r\n        if (filterBlank && StringUtils.isBlank(str))\r\n        {\r\n            return list;\r\n        }\r\n        String[] split = str.split(sep);\r\n        for (String string : split)\r\n        {\r\n            if (filterBlank && StringUtils.isBlank(string))\r\n            {\r\n                continue;\r\n            }\r\n            if (trim)\r\n            {\r\n                string = string.trim();\r\n            }\r\n            list.add(string);\r\n        }\r\n\r\n        return list;\r\n    }\r\n\r\n    /**\r\n     * 检查子字符串是否存在\r\n     *\r\n     * @param seq 检查的字符串\r\n     * @param searchSeq 查找的字符串\r\n     * @return 结果\r\n     */\r\n    public static boolean contains(final CharSequence seq, final CharSequence searchSeq)\r\n    {\r\n        return Strings.CS.contains(seq, searchSeq);\r\n    }\r\n\r\n    /**\r\n     * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value\r\n     *\r\n     * @param collection 给定的集合\r\n     * @param array 给定的数组\r\n     * @return boolean 结果\r\n     */\r\n    public static boolean containsAny(Collection<String> collection, String... array)\r\n    {\r\n        if (isEmpty(collection) || isEmpty(array))\r\n        {\r\n            return false;\r\n        }\r\n        else\r\n        {\r\n            for (String str : array)\r\n            {\r\n                if (collection.contains(str))\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写\r\n     *\r\n     * @param cs 指定字符串\r\n     * @param searchCharSequences 需要检查的字符串数组\r\n     * @return 是否包含任意一个字符串\r\n     */\r\n    public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)\r\n    {\r\n        if (isEmpty(cs) || isEmpty(searchCharSequences))\r\n        {\r\n            return false;\r\n        }\r\n        for (CharSequence testStr : searchCharSequences)\r\n        {\r\n            if (containsIgnoreCase(cs, testStr))\r\n            {\r\n                return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 检查是否包含要搜索的字符串，忽略大小写\r\n     *\r\n     * @param str 要检查的字符串\r\n     * @param searchStr 要查找的字符串\r\n     * @return 如果包含要搜索的字符串（忽略大小写）则返回true，如果不包含或返回false\r\n     */\r\n    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr)\r\n    {\r\n        return Strings.CI.contains(str, searchStr);\r\n    }\r\n\r\n    /**\r\n     * 检查字符串是否以任意前缀开始\r\n     *\r\n     * @param sequence 要检查的字符串\r\n     * @param searchStrings 区分大小写的字符串前缀数组\r\n     * @return 结果\r\n     */\r\n    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings)\r\n    {\r\n        return Strings.CS.startsWithAny(sequence, searchStrings);\r\n    }\r\n\r\n    /**\r\n     * 比较两个字符串是否相同\r\n     *\r\n     * @param cs1 第一个字符串\r\n     * @param cs2 第二个字符串\r\n     * @return 如果给定对象与字符串相等，则返回 true；否则返回 false\r\n     */\r\n    public static boolean equals(final CharSequence cs1, final CharSequence cs2)\r\n    {\r\n        return Strings.CS.equals(cs1, cs2);\r\n    }\r\n\r\n    /**\r\n     * 替换字符串中所有匹配的字符\r\n     *\r\n     * @param text 要搜索和替换的文本\r\n     * @param searchString 要搜索的字符串\r\n     * @param replacement  用于替换的字符串\r\n     * @return 处理完所有替换后的文本\r\n     */\r\n    public static String replace(final String text, final String searchString, final String replacement)\r\n    {\r\n        return Strings.CS.replace(text, searchString, replacement);\r\n    }\r\n\r\n    /**\r\n     * 查找字符串首次出现位置的索引\r\n     *\r\n     * @param seq 要检查的字符串\r\n     * @param searchSeq 要查找的字符串\r\n     * @return 返回指定字符在字符串中第一次出现处的索引，如果此字符串中没有这样的字符，则返回 -1\r\n     */\r\n    public static int indexOf(final CharSequence seq, final CharSequence searchSeq)\r\n    {\r\n        return Strings.CS.indexOf(seq, searchSeq);\r\n    }\r\n\r\n    /**\r\n     * 检查字符串是否以指定的后缀结尾\r\n     *\r\n     * @param str 要检查的字符\r\n     * @param suffix 要检查的后缀\r\n     * @return 若参数与该字符串末尾相符 true;否则 false\r\n     */\r\n    public static boolean endsWith(final CharSequence str, final CharSequence suffix)\r\n    {\r\n        return Strings.CS.endsWith(str, suffix);\r\n    }\r\n\r\n    /**\r\n     * 将给定的字符串与数组进行比较\r\n     *\r\n     * @param string 要比较的字符串\r\n     * @param searchStrings 字符串数组\r\n     * @return 如果字符串等于（区分大小写）{@code searchStrings}中的任意其他元素，则返回true；如果{@code searchStrings}为null或不包含匹配项，则返回false\r\n     */\r\n    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings)\r\n    {\r\n        return Strings.CS.equalsAny(string, searchStrings);\r\n    }\r\n\r\n    /**\r\n     * 检查一个字符串是否以任意提供的区分大小写的后缀结尾。\r\n     *\r\n     * @param sequence 要检查的字符串\r\n     * @param searchStrings 要查找的区分大小写的字符串数组\r\n     * @return 如果输入参数{@code sequence}为null且未提供任何{@code searchStrings}，或者输入{@code sequence}以任意提供的区分大小写的{@code searchStrings}结尾，则返回{@code true}。\r\n     */\r\n    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings)\r\n    {\r\n        return Strings.CS.endsWithAny(sequence, searchStrings);\r\n    }\r\n\r\n    /**\r\n     * 不区分大小写地检查字符序列是否以指定的后缀结尾\r\n     *\r\n     * @param str 要检查的字符序列\r\n     * @param suffix 要查找的后缀\r\n     * @return 如果字符序列以该后缀结尾（不区分大小写），或两者均为{@code null}，则返回{@code true}\r\n     */\r\n    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix)\r\n    {\r\n        return Strings.CI.endsWith(str, suffix);\r\n    }\r\n\r\n    /**\r\n     * 指定范围内查找字符串,忽略大小写\r\n     *\r\n     * @param str 要检查的字符串\r\n     * @param searchStr 要查找的字符串\r\n     * @return 搜索字符串的第一个索引，如果未找到匹配项则返回 -1\r\n     */\r\n    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr)\r\n    {\r\n        return Strings.CI.indexOf(str, searchStr);\r\n    }\r\n\r\n    /**\r\n     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},\r\n     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.\r\n     *\r\n     * @param string to compare, may be {@code null}.\r\n     * @param searchStrings a vararg of strings, may be {@code null}.\r\n     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};\r\n     */\r\n    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings)\r\n    {\r\n        return Strings.CI.equalsAny(string, searchStrings);\r\n    }\r\n\r\n    /**\r\n     * 驼峰转下划线命名\r\n     */\r\n    public static String toUnderScoreCase(String str)\r\n    {\r\n        if (str == null)\r\n        {\r\n            return null;\r\n        }\r\n        StringBuilder sb = new StringBuilder();\r\n        // 前置字符是否大写\r\n        boolean preCharIsUpperCase = true;\r\n        // 当前字符是否大写\r\n        boolean curreCharIsUpperCase = true;\r\n        // 下一字符是否大写\r\n        boolean nexteCharIsUpperCase = true;\r\n        for (int i = 0; i < str.length(); i++)\r\n        {\r\n            char c = str.charAt(i);\r\n            if (i > 0)\r\n            {\r\n                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));\r\n            }\r\n            else\r\n            {\r\n                preCharIsUpperCase = false;\r\n            }\r\n\r\n            curreCharIsUpperCase = Character.isUpperCase(c);\r\n\r\n            if (i < (str.length() - 1))\r\n            {\r\n                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));\r\n            }\r\n\r\n            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)\r\n            {\r\n                sb.append(SEPARATOR);\r\n            }\r\n            else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)\r\n            {\r\n                sb.append(SEPARATOR);\r\n            }\r\n            sb.append(Character.toLowerCase(c));\r\n        }\r\n\r\n        return sb.toString();\r\n    }\r\n\r\n    /**\r\n     * 是否包含字符串\r\n     * \r\n     * @param str 验证字符串\r\n     * @param strs 字符串组\r\n     * @return 包含返回true\r\n     */\r\n    public static boolean inStringIgnoreCase(String str, String... strs)\r\n    {\r\n        if (str != null && strs != null)\r\n        {\r\n            for (String s : strs)\r\n            {\r\n                if (str.equalsIgnoreCase(trim(s)))\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 删除最后一个字符串\r\n     *\r\n     * @param str 输入字符串\r\n     * @param spit 以什么类型结尾的\r\n     * @return 截取后的字符串\r\n     */\r\n    public static String lastStringDel(String str, String spit)\r\n    {\r\n        if (!StringUtils.isEmpty(str) && str.endsWith(spit))\r\n        {\r\n            return str.subSequence(0, str.length() - 1).toString();\r\n        }\r\n        return str;\r\n    }\r\n\r\n    /**\r\n     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。 例如：HELLO_WORLD->HelloWorld\r\n     * \r\n     * @param name 转换前的下划线大写方式命名的字符串\r\n     * @return 转换后的驼峰式命名的字符串\r\n     */\r\n    public static String convertToCamelCase(String name)\r\n    {\r\n        StringBuilder result = new StringBuilder();\r\n        // 快速检查\r\n        if (name == null || name.isEmpty())\r\n        {\r\n            // 没必要转换\r\n            return \"\";\r\n        }\r\n        else if (!name.contains(\"_\"))\r\n        {\r\n            // 不含下划线，仅将首字母大写\r\n            return name.substring(0, 1).toUpperCase() + name.substring(1);\r\n        }\r\n        // 用下划线将原始字符串分割\r\n        String[] camels = name.split(\"_\");\r\n        for (String camel : camels)\r\n        {\r\n            // 跳过原始字符串中开头、结尾的下换线或双重下划线\r\n            if (camel.isEmpty())\r\n            {\r\n                continue;\r\n            }\r\n            // 首字母大写\r\n            result.append(camel.substring(0, 1).toUpperCase());\r\n            result.append(camel.substring(1).toLowerCase());\r\n        }\r\n        return result.toString();\r\n    }\r\n\r\n    /**\r\n     * 驼峰式命名法\r\n     * 例如：user_name->userName\r\n     */\r\n    public static String toCamelCase(String s)\r\n    {\r\n        if (s == null)\r\n        {\r\n            return null;\r\n        }\r\n        if (s.indexOf(SEPARATOR) == -1)\r\n        {\r\n            return s;\r\n        }\r\n        s = s.toLowerCase();\r\n        StringBuilder sb = new StringBuilder(s.length());\r\n        boolean upperCase = false;\r\n        for (int i = 0; i < s.length(); i++)\r\n        {\r\n            char c = s.charAt(i);\r\n\r\n            if (c == SEPARATOR)\r\n            {\r\n                upperCase = true;\r\n            }\r\n            else if (upperCase)\r\n            {\r\n                sb.append(Character.toUpperCase(c));\r\n                upperCase = false;\r\n            }\r\n            else\r\n            {\r\n                sb.append(c);\r\n            }\r\n        }\r\n        return sb.toString();\r\n    }\r\n\r\n    /**\r\n     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串\r\n     * \r\n     * @param str 指定字符串\r\n     * @param strs 需要检查的字符串数组\r\n     * @return 是否匹配\r\n     */\r\n    public static boolean matches(String str, List<String> strs)\r\n    {\r\n        if (isEmpty(str) || isEmpty(strs))\r\n        {\r\n            return false;\r\n        }\r\n        for (String pattern : strs)\r\n        {\r\n            if (isMatch(pattern, str))\r\n            {\r\n                return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 判断url是否与规则配置: \r\n     * ? 表示单个字符; \r\n     * * 表示一层路径内的任意字符串，不可跨层级; \r\n     * ** 表示任意层路径;\r\n     * \r\n     * @param pattern 匹配规则\r\n     * @param url 需要匹配的url\r\n     * @return\r\n     */\r\n    public static boolean isMatch(String pattern, String url)\r\n    {\r\n        AntPathMatcher matcher = new AntPathMatcher();\r\n        return matcher.match(pattern, url);\r\n    }\r\n\r\n    @SuppressWarnings(\"unchecked\")\r\n    public static <T> T cast(Object obj)\r\n    {\r\n        return (T) obj;\r\n    }\r\n\r\n    /**\r\n     * 数字左边补齐0，使之达到指定长度。注意，如果数字转换为字符串后，长度大于size，则只保留 最后size个字符。\r\n     * \r\n     * @param num 数字对象\r\n     * @param size 字符串指定长度\r\n     * @return 返回数字的字符串格式，该字符串为指定长度。\r\n     */\r\n    public static final String padl(final Number num, final int size)\r\n    {\r\n        return padl(num.toString(), size, '0');\r\n    }\r\n\r\n    /**\r\n     * 字符串左补齐。如果原始字符串s长度大于size，则只保留最后size个字符。\r\n     * \r\n     * @param s 原始字符串\r\n     * @param size 字符串指定长度\r\n     * @param c 用于补齐的字符\r\n     * @return 返回指定长度的字符串，由原字符串左补齐或截取得到。\r\n     */\r\n    public static final String padl(final String s, final int size, final char c)\r\n    {\r\n        final StringBuilder sb = new StringBuilder(size);\r\n        if (s != null)\r\n        {\r\n            final int len = s.length();\r\n            if (s.length() <= size)\r\n            {\r\n                for (int i = size - len; i > 0; i--)\r\n                {\r\n                    sb.append(c);\r\n                }\r\n                sb.append(s);\r\n            }\r\n            else\r\n            {\r\n                return s.substring(len - size, len);\r\n            }\r\n        }\r\n        else\r\n        {\r\n            for (int i = size; i > 0; i--)\r\n            {\r\n                sb.append(c);\r\n            }\r\n        }\r\n        return sb.toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java",
    "content": "package com.ruoyi.common.utils;\n\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 线程相关工具类.\n * \n * @author ruoyi\n */\npublic class Threads\n{\n    private static final Logger logger = LoggerFactory.getLogger(Threads.class);\n\n    /**\n     * sleep等待,单位为毫秒\n     */\n    public static void sleep(long milliseconds)\n    {\n        try\n        {\n            Thread.sleep(milliseconds);\n        }\n        catch (InterruptedException e)\n        {\n            return;\n        }\n    }\n\n    /**\n     * 停止线程池\n     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.\n     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.\n     * 如果仍人超時，則強制退出.\n     * 另对在shutdown时线程本身被调用中断做了处理.\n     */\n    public static void shutdownAndAwaitTermination(ExecutorService pool)\n    {\n        if (pool != null && !pool.isShutdown())\n        {\n            pool.shutdown();\n            try\n            {\n                if (!pool.awaitTermination(120, TimeUnit.SECONDS))\n                {\n                    pool.shutdownNow();\n                    if (!pool.awaitTermination(120, TimeUnit.SECONDS))\n                    {\n                        logger.info(\"Pool did not terminate\");\n                    }\n                }\n            }\n            catch (InterruptedException ie)\n            {\n                pool.shutdownNow();\n                Thread.currentThread().interrupt();\n            }\n        }\n    }\n\n    /**\n     * 打印线程异常信息\n     */\n    public static void printException(Runnable r, Throwable t)\n    {\n        if (t == null && r instanceof Future<?>)\n        {\n            try\n            {\n                Future<?> future = (Future<?>) r;\n                if (future.isDone())\n                {\n                    future.get();\n                }\n            }\n            catch (CancellationException ce)\n            {\n                t = ce;\n            }\n            catch (ExecutionException ee)\n            {\n                t = ee.getCause();\n            }\n            catch (InterruptedException ie)\n            {\n                Thread.currentThread().interrupt();\n            }\n        }\n        if (t != null)\n        {\n            logger.error(t.getMessage(), t);\n        }\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java",
    "content": "package com.ruoyi.common.utils.bean;\r\n\r\nimport java.lang.reflect.Method;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\n\r\n/**\r\n * Bean 工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class BeanUtils extends org.springframework.beans.BeanUtils\r\n{\r\n    /** Bean方法名中属性名开始的下标 */\r\n    private static final int BEAN_METHOD_PROP_INDEX = 3;\r\n\r\n    /** * 匹配getter方法的正则表达式 */\r\n    private static final Pattern GET_PATTERN = Pattern.compile(\"get(\\\\p{javaUpperCase}\\\\w*)\");\r\n\r\n    /** * 匹配setter方法的正则表达式 */\r\n    private static final Pattern SET_PATTERN = Pattern.compile(\"set(\\\\p{javaUpperCase}\\\\w*)\");\r\n\r\n    /**\r\n     * Bean属性复制工具方法。\r\n     * \r\n     * @param dest 目标对象\r\n     * @param src 源对象\r\n     */\r\n    public static void copyBeanProp(Object dest, Object src)\r\n    {\r\n        try\r\n        {\r\n            copyProperties(src, dest);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            e.printStackTrace();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取对象的setter方法。\r\n     * \r\n     * @param obj 对象\r\n     * @return 对象的setter方法列表\r\n     */\r\n    public static List<Method> getSetterMethods(Object obj)\r\n    {\r\n        // setter方法列表\r\n        List<Method> setterMethods = new ArrayList<Method>();\r\n\r\n        // 获取所有方法\r\n        Method[] methods = obj.getClass().getMethods();\r\n\r\n        // 查找setter方法\r\n\r\n        for (Method method : methods)\r\n        {\r\n            Matcher m = SET_PATTERN.matcher(method.getName());\r\n            if (m.matches() && (method.getParameterTypes().length == 1))\r\n            {\r\n                setterMethods.add(method);\r\n            }\r\n        }\r\n        // 返回setter方法列表\r\n        return setterMethods;\r\n    }\r\n\r\n    /**\r\n     * 获取对象的getter方法。\r\n     * \r\n     * @param obj 对象\r\n     * @return 对象的getter方法列表\r\n     */\r\n\r\n    public static List<Method> getGetterMethods(Object obj)\r\n    {\r\n        // getter方法列表\r\n        List<Method> getterMethods = new ArrayList<Method>();\r\n        // 获取所有方法\r\n        Method[] methods = obj.getClass().getMethods();\r\n        // 查找getter方法\r\n        for (Method method : methods)\r\n        {\r\n            Matcher m = GET_PATTERN.matcher(method.getName());\r\n            if (m.matches() && (method.getParameterTypes().length == 0))\r\n            {\r\n                getterMethods.add(method);\r\n            }\r\n        }\r\n        // 返回getter方法列表\r\n        return getterMethods;\r\n    }\r\n\r\n    /**\r\n     * 检查Bean方法名中的属性名是否相等。<br>\r\n     * 如getName()和setName()属性名一样，getName()和setAge()属性名不一样。\r\n     * \r\n     * @param m1 方法名1\r\n     * @param m2 方法名2\r\n     * @return 属性名一样返回true，否则返回false\r\n     */\r\n\r\n    public static boolean isMethodPropEquals(String m1, String m2)\r\n    {\r\n        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java",
    "content": "package com.ruoyi.common.utils.bean;\r\n\r\nimport java.util.Set;\r\nimport jakarta.validation.ConstraintViolation;\r\nimport jakarta.validation.ConstraintViolationException;\r\nimport jakarta.validation.Validator;\r\n\r\n/**\r\n * bean对象属性验证\r\n * \r\n * @author ruoyi\r\n */\r\npublic class BeanValidators\r\n{\r\n    public static void validateWithException(Validator validator, Object object, Class<?>... groups)\r\n            throws ConstraintViolationException\r\n    {\r\n        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);\r\n        if (!constraintViolations.isEmpty())\r\n        {\r\n            throw new ConstraintViolationException(constraintViolations);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java",
    "content": "package com.ruoyi.common.utils.file;\r\n\r\nimport java.io.File;\r\nimport org.apache.commons.lang3.StringUtils;\r\n\r\n/**\r\n * 文件类型工具类\r\n *\r\n * @author ruoyi\r\n */\r\npublic class FileTypeUtils\r\n{\r\n    /**\r\n     * 获取文件类型\r\n     * <p>\r\n     * 例如: ruoyi.txt, 返回: txt\r\n     * \r\n     * @param file 文件名\r\n     * @return 后缀（不含\".\")\r\n     */\r\n    public static String getFileType(File file)\r\n    {\r\n        if (null == file)\r\n        {\r\n            return StringUtils.EMPTY;\r\n        }\r\n        return getFileType(file.getName());\r\n    }\r\n\r\n    /**\r\n     * 获取文件类型\r\n     * <p>\r\n     * 例如: ruoyi.txt, 返回: txt\r\n     *\r\n     * @param fileName 文件名\r\n     * @return 后缀（不含\".\")\r\n     */\r\n    public static String getFileType(String fileName)\r\n    {\r\n        int separatorIndex = fileName.lastIndexOf(\".\");\r\n        if (separatorIndex < 0)\r\n        {\r\n            return \"\";\r\n        }\r\n        return fileName.substring(separatorIndex + 1).toLowerCase();\r\n    }\r\n\r\n    /**\r\n     * 获取文件类型\r\n     * \r\n     * @param photoByte 文件字节码\r\n     * @return 后缀（不含\".\")\r\n     */\r\n    public static String getFileExtendName(byte[] photoByte)\r\n    {\r\n        String strFileExtendName = \"JPG\";\r\n        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)\r\n                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))\r\n        {\r\n            strFileExtendName = \"GIF\";\r\n        }\r\n        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))\r\n        {\r\n            strFileExtendName = \"JPG\";\r\n        }\r\n        else if ((photoByte[0] == 66) && (photoByte[1] == 77))\r\n        {\r\n            strFileExtendName = \"BMP\";\r\n        }\r\n        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))\r\n        {\r\n            strFileExtendName = \"PNG\";\r\n        }\r\n        return strFileExtendName;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java",
    "content": "package com.ruoyi.common.utils.file;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.nio.file.Paths;\r\nimport java.util.Objects;\r\nimport org.apache.commons.io.FilenameUtils;\r\nimport org.springframework.web.multipart.MultipartFile;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;\r\nimport com.ruoyi.common.exception.file.FileSizeLimitExceededException;\r\nimport com.ruoyi.common.exception.file.InvalidExtensionException;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.uuid.IdUtils;\r\nimport com.ruoyi.common.utils.uuid.Seq;\r\n\r\n/**\r\n * 文件上传工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class FileUploadUtils\r\n{\r\n    /**\r\n     * 默认大小 50M\r\n     */\r\n    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;\r\n\r\n    /**\r\n     * 默认的文件名最大长度 100\r\n     */\r\n    public static final int DEFAULT_FILE_NAME_LENGTH = 100;\r\n\r\n    /**\r\n     * 默认上传的地址\r\n     */\r\n    private static String defaultBaseDir = RuoYiConfig.getProfile();\r\n\r\n    public static void setDefaultBaseDir(String defaultBaseDir)\r\n    {\r\n        FileUploadUtils.defaultBaseDir = defaultBaseDir;\r\n    }\r\n\r\n    public static String getDefaultBaseDir()\r\n    {\r\n        return defaultBaseDir;\r\n    }\r\n\r\n    /**\r\n     * 以默认配置进行文件上传\r\n     *\r\n     * @param file 上传的文件\r\n     * @return 文件名称\r\n     * @throws Exception\r\n     */\r\n    public static final String upload(MultipartFile file) throws IOException\r\n    {\r\n        try\r\n        {\r\n            return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new IOException(e.getMessage(), e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 根据文件路径上传\r\n     *\r\n     * @param baseDir 相对应用的基目录\r\n     * @param file 上传的文件\r\n     * @return 文件名称\r\n     * @throws IOException\r\n     */\r\n    public static final String upload(String baseDir, MultipartFile file) throws IOException\r\n    {\r\n        try\r\n        {\r\n            return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new IOException(e.getMessage(), e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 文件上传\r\n     *\r\n     * @param baseDir 相对应用的基目录\r\n     * @param file 上传的文件\r\n     * @param allowedExtension 上传文件类型\r\n     * @return 返回上传成功的文件名\r\n     * @throws FileSizeLimitExceededException 如果超出最大大小\r\n     * @throws FileNameLengthLimitExceededException 文件名太长\r\n     * @throws IOException 比如读写文件出错时\r\n     * @throws InvalidExtensionException 文件校验异常\r\n     */\r\n    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)\r\n            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,\r\n            InvalidExtensionException\r\n    {\r\n        return upload(baseDir, file, allowedExtension, false);\r\n    }\r\n    \r\n    /**\r\n     * 文件上传\r\n     *\r\n     * @param baseDir 相对应用的基目录\r\n     * @param file 上传的文件\r\n     * @param useCustomNaming 系统自定义文件名\r\n     * @param allowedExtension 上传文件类型\r\n     * @return 返回上传成功的文件名\r\n     * @throws FileSizeLimitExceededException 如果超出最大大小\r\n     * @throws FileNameLengthLimitExceededException 文件名太长\r\n     * @throws IOException 比如读写文件出错时\r\n     * @throws InvalidExtensionException 文件校验异常\r\n     */\r\n    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension, boolean useCustomNaming)\r\n            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,\r\n            InvalidExtensionException\r\n    {\r\n        int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();\r\n        if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)\r\n        {\r\n            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);\r\n        }\r\n\r\n        assertAllowed(file, allowedExtension);\r\n\r\n        String fileName = useCustomNaming ? uuidFilename(file) : extractFilename(file);\r\n\r\n        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();\r\n        file.transferTo(Paths.get(absPath));\r\n        return getPathFileName(baseDir, fileName);\r\n    }\r\n\r\n    /**\r\n     * 编码文件名(日期格式目录 + 原文件名 + 序列值 + 后缀)\r\n     */\r\n    public static final String extractFilename(MultipartFile file)\r\n    {\r\n        return StringUtils.format(\"{}/{}_{}.{}\", DateUtils.datePath(), FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));\r\n    }\r\n\r\n    /**\r\n     * 编编码文件名(日期格式目录 + UUID + 后缀)\r\n     */\r\n    public static final String uuidFilename(MultipartFile file)\r\n    {\r\n        return StringUtils.format(\"{}/{}.{}\", DateUtils.datePath(), IdUtils.fastSimpleUUID(), getExtension(file));\r\n    }\r\n\r\n    public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException\r\n    {\r\n        File desc = new File(uploadDir + File.separator + fileName);\r\n\r\n        if (!desc.exists())\r\n        {\r\n            if (!desc.getParentFile().exists())\r\n            {\r\n                desc.getParentFile().mkdirs();\r\n            }\r\n        }\r\n        return desc;\r\n    }\r\n\r\n    public static final String getPathFileName(String uploadDir, String fileName) throws IOException\r\n    {\r\n        int dirLastIndex = RuoYiConfig.getProfile().length() + 1;\r\n        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);\r\n        return Constants.RESOURCE_PREFIX + \"/\" + currentDir + \"/\" + fileName;\r\n    }\r\n\r\n    /**\r\n     * 文件大小校验\r\n     *\r\n     * @param file 上传的文件\r\n     * @return\r\n     * @throws FileSizeLimitExceededException 如果超出最大大小\r\n     * @throws InvalidExtensionException\r\n     */\r\n    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)\r\n            throws FileSizeLimitExceededException, InvalidExtensionException\r\n    {\r\n        long size = file.getSize();\r\n        if (size > DEFAULT_MAX_SIZE)\r\n        {\r\n            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);\r\n        }\r\n\r\n        String fileName = file.getOriginalFilename();\r\n        String extension = getExtension(file);\r\n        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))\r\n        {\r\n            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)\r\n            {\r\n                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,\r\n                        fileName);\r\n            }\r\n            else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)\r\n            {\r\n                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,\r\n                        fileName);\r\n            }\r\n            else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)\r\n            {\r\n                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,\r\n                        fileName);\r\n            }\r\n            else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)\r\n            {\r\n                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,\r\n                        fileName);\r\n            }\r\n            else\r\n            {\r\n                throw new InvalidExtensionException(allowedExtension, extension, fileName);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 判断MIME类型是否是允许的MIME类型\r\n     *\r\n     * @param extension\r\n     * @param allowedExtension\r\n     * @return\r\n     */\r\n    public static final boolean isAllowedExtension(String extension, String[] allowedExtension)\r\n    {\r\n        for (String str : allowedExtension)\r\n        {\r\n            if (str.equalsIgnoreCase(extension))\r\n            {\r\n                return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 获取文件名的后缀\r\n     * \r\n     * @param file 表单文件\r\n     * @return 后缀名\r\n     */\r\n    public static final String getExtension(MultipartFile file)\r\n    {\r\n        String extension = FilenameUtils.getExtension(file.getOriginalFilename());\r\n        if (StringUtils.isEmpty(extension))\r\n        {\r\n            extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));\r\n        }\r\n        return extension;\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java",
    "content": "package com.ruoyi.common.utils.file;\r\n\r\nimport java.io.File;\r\nimport java.io.FileInputStream;\r\nimport java.io.FileNotFoundException;\r\nimport java.io.FileOutputStream;\r\nimport java.io.IOException;\r\nimport java.io.OutputStream;\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.net.URLEncoder;\r\nimport java.nio.charset.StandardCharsets;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport org.apache.commons.io.FilenameUtils;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.apache.commons.lang3.ArrayUtils;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.uuid.IdUtils;\r\n\r\n/**\r\n * 文件处理工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class FileUtils\r\n{\r\n    public static String FILENAME_PATTERN = \"[a-zA-Z0-9_\\\\-\\\\|\\\\.\\\\u4e00-\\\\u9fa5]+\";\r\n\r\n    /**\r\n     * 输出指定文件的byte数组\r\n     * \r\n     * @param filePath 文件路径\r\n     * @param os 输出流\r\n     * @return\r\n     */\r\n    public static void writeBytes(String filePath, OutputStream os) throws IOException\r\n    {\r\n        FileInputStream fis = null;\r\n        try\r\n        {\r\n            File file = new File(filePath);\r\n            if (!file.exists())\r\n            {\r\n                throw new FileNotFoundException(filePath);\r\n            }\r\n            fis = new FileInputStream(file);\r\n            byte[] b = new byte[1024];\r\n            int length;\r\n            while ((length = fis.read(b)) > 0)\r\n            {\r\n                os.write(b, 0, length);\r\n            }\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw e;\r\n        }\r\n        finally\r\n        {\r\n            IOUtils.close(os);\r\n            IOUtils.close(fis);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 写数据到文件中\r\n     *\r\n     * @param data 数据\r\n     * @return 目标文件\r\n     * @throws IOException IO异常\r\n     */\r\n    public static String writeImportBytes(byte[] data) throws IOException\r\n    {\r\n        return writeBytes(data, RuoYiConfig.getImportPath());\r\n    }\r\n\r\n    /**\r\n     * 写数据到文件中\r\n     *\r\n     * @param data 数据\r\n     * @param uploadDir 目标文件\r\n     * @return 目标文件\r\n     * @throws IOException IO异常\r\n     */\r\n    public static String writeBytes(byte[] data, String uploadDir) throws IOException\r\n    {\r\n        FileOutputStream fos = null;\r\n        String pathName = \"\";\r\n        try\r\n        {\r\n            String extension = getFileExtendName(data);\r\n            pathName = DateUtils.datePath() + \"/\" + IdUtils.fastUUID() + \".\" + extension;\r\n            File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);\r\n            fos = new FileOutputStream(file);\r\n            fos.write(data);\r\n        }\r\n        finally\r\n        {\r\n            IOUtils.close(fos);\r\n        }\r\n        return FileUploadUtils.getPathFileName(uploadDir, pathName);\r\n    }\r\n\r\n    /**\r\n     * 移除路径中的请求前缀片段\r\n     * \r\n     * @param filePath 文件路径\r\n     * @return 移除后的文件路径\r\n     */\r\n    public static String stripPrefix(String filePath)\r\n    {\r\n        return StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX);\r\n    }\r\n\r\n    /**\r\n     * 删除文件\r\n     * \r\n     * @param filePath 文件\r\n     * @return\r\n     */\r\n    public static boolean deleteFile(String filePath)\r\n    {\r\n        boolean flag = false;\r\n        File file = new File(filePath);\r\n        // 路径为文件且不为空则进行删除\r\n        if (file.isFile() && file.exists())\r\n        {\r\n            flag = file.delete();\r\n        }\r\n        return flag;\r\n    }\r\n\r\n    /**\r\n     * 文件名称验证\r\n     * \r\n     * @param filename 文件名称\r\n     * @return true 正常 false 非法\r\n     */\r\n    public static boolean isValidFilename(String filename)\r\n    {\r\n        return filename.matches(FILENAME_PATTERN);\r\n    }\r\n\r\n    /**\r\n     * 检查文件是否可下载\r\n     * \r\n     * @param resource 需要下载的文件\r\n     * @return true 正常 false 非法\r\n     */\r\n    public static boolean checkAllowDownload(String resource)\r\n    {\r\n        // 禁止目录上跳级别\r\n        if (StringUtils.contains(resource, \"..\"))\r\n        {\r\n            return false;\r\n        }\r\n\r\n        // 检查允许下载的文件规则\r\n        if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))\r\n        {\r\n            return true;\r\n        }\r\n\r\n        // 不在允许下载的文件规则\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 下载文件名重新编码\r\n     * \r\n     * @param request 请求对象\r\n     * @param fileName 文件名\r\n     * @return 编码后的文件名\r\n     */\r\n    public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException\r\n    {\r\n        final String agent = request.getHeader(\"USER-AGENT\");\r\n        String filename = fileName;\r\n        if (agent.contains(\"MSIE\"))\r\n        {\r\n            // IE浏览器\r\n            filename = URLEncoder.encode(filename, \"utf-8\");\r\n            filename = filename.replace(\"+\", \" \");\r\n        }\r\n        else if (agent.contains(\"Firefox\"))\r\n        {\r\n            // 火狐浏览器\r\n            filename = new String(fileName.getBytes(), \"ISO8859-1\");\r\n        }\r\n        else if (agent.contains(\"Chrome\"))\r\n        {\r\n            // google浏览器\r\n            filename = URLEncoder.encode(filename, \"utf-8\");\r\n        }\r\n        else\r\n        {\r\n            // 其它浏览器\r\n            filename = URLEncoder.encode(filename, \"utf-8\");\r\n        }\r\n        return filename;\r\n    }\r\n\r\n    /**\r\n     * 下载文件名重新编码\r\n     *\r\n     * @param response 响应对象\r\n     * @param realFileName 真实文件名\r\n     * @return\r\n     */\r\n    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException\r\n    {\r\n        String percentEncodedFileName = percentEncode(realFileName);\r\n\r\n        StringBuilder contentDispositionValue = new StringBuilder();\r\n        contentDispositionValue.append(\"attachment; filename=\")\r\n                .append(percentEncodedFileName)\r\n                .append(\";\")\r\n                .append(\"filename*=\")\r\n                .append(\"utf-8''\")\r\n                .append(percentEncodedFileName);\r\n\r\n        response.setHeader(\"Content-disposition\", contentDispositionValue.toString());\r\n    }\r\n\r\n    /**\r\n     * 百分号编码工具方法\r\n     *\r\n     * @param s 需要百分号编码的字符串\r\n     * @return 百分号编码后的字符串\r\n     */\r\n    public static String percentEncode(String s) throws UnsupportedEncodingException\r\n    {\r\n        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());\r\n        return encode.replaceAll(\"\\\\+\", \"%20\");\r\n    }\r\n\r\n    /**\r\n     * 获取图像后缀\r\n     * \r\n     * @param photoByte 图像数据\r\n     * @return 后缀名\r\n     */\r\n    public static String getFileExtendName(byte[] photoByte)\r\n    {\r\n        String strFileExtendName = \"jpg\";\r\n        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)\r\n                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))\r\n        {\r\n            strFileExtendName = \"gif\";\r\n        }\r\n        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))\r\n        {\r\n            strFileExtendName = \"jpg\";\r\n        }\r\n        else if ((photoByte[0] == 66) && (photoByte[1] == 77))\r\n        {\r\n            strFileExtendName = \"bmp\";\r\n        }\r\n        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))\r\n        {\r\n            strFileExtendName = \"png\";\r\n        }\r\n        return strFileExtendName;\r\n    }\r\n\r\n    /**\r\n     * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png\r\n     * \r\n     * @param fileName 路径名称\r\n     * @return 没有文件路径的名称\r\n     */\r\n    public static String getName(String fileName)\r\n    {\r\n        if (fileName == null)\r\n        {\r\n            return null;\r\n        }\r\n        int lastUnixPos = fileName.lastIndexOf('/');\r\n        int lastWindowsPos = fileName.lastIndexOf('\\\\');\r\n        int index = Math.max(lastUnixPos, lastWindowsPos);\r\n        return fileName.substring(index + 1);\r\n    }\r\n\r\n    /**\r\n     * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi\r\n     * \r\n     * @param fileName 路径名称\r\n     * @return 没有文件路径和后缀的名称\r\n     */\r\n    public static String getNameNotSuffix(String fileName)\r\n    {\r\n        if (fileName == null)\r\n        {\r\n            return null;\r\n        }\r\n        String baseName = FilenameUtils.getBaseName(fileName);\r\n        return baseName;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java",
    "content": "package com.ruoyi.common.utils.file;\r\n\r\nimport java.io.ByteArrayInputStream;\r\nimport java.io.FileInputStream;\r\nimport java.io.InputStream;\r\nimport java.net.URL;\r\nimport java.net.URLConnection;\r\nimport java.util.Arrays;\r\nimport org.apache.poi.util.IOUtils;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 图片处理工具类\r\n *\r\n * @author ruoyi\r\n */\r\npublic class ImageUtils\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);\r\n\r\n    public static byte[] getImage(String imagePath)\r\n    {\r\n        InputStream is = getFile(imagePath);\r\n        try\r\n        {\r\n            return IOUtils.toByteArray(is);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"图片加载异常 {}\", e);\r\n            return null;\r\n        }\r\n        finally\r\n        {\r\n            IOUtils.closeQuietly(is);\r\n        }\r\n    }\r\n\r\n    public static InputStream getFile(String imagePath)\r\n    {\r\n        try\r\n        {\r\n            byte[] result = readFile(imagePath);\r\n            result = Arrays.copyOf(result, result.length);\r\n            return new ByteArrayInputStream(result);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"获取图片异常 {}\", e);\r\n        }\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * 读取文件为字节数据\r\n     * \r\n     * @param url 地址\r\n     * @return 字节数据\r\n     */\r\n    public static byte[] readFile(String url)\r\n    {\r\n        InputStream in = null;\r\n        try\r\n        {\r\n            if (url.startsWith(\"http\"))\r\n            {\r\n                // 网络地址\r\n                URL urlObj = new URL(url);\r\n                URLConnection urlConnection = urlObj.openConnection();\r\n                urlConnection.setConnectTimeout(30 * 1000);\r\n                urlConnection.setReadTimeout(60 * 1000);\r\n                urlConnection.setDoInput(true);\r\n                in = urlConnection.getInputStream();\r\n            }\r\n            else\r\n            {\r\n                // 本机地址\r\n                String localPath = RuoYiConfig.getProfile();\r\n                String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);\r\n                in = new FileInputStream(downloadPath);\r\n            }\r\n            return IOUtils.toByteArray(in);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"获取文件路径异常 {}\", e);\r\n            return null;\r\n        }\r\n        finally\r\n        {\r\n            IOUtils.closeQuietly(in);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java",
    "content": "package com.ruoyi.common.utils.file;\n\n/**\n * 媒体类型工具类\n * \n * @author ruoyi\n */\npublic class MimeTypeUtils\n{\n    public static final String IMAGE_PNG = \"image/png\";\n\n    public static final String IMAGE_JPG = \"image/jpg\";\n\n    public static final String IMAGE_JPEG = \"image/jpeg\";\n\n    public static final String IMAGE_BMP = \"image/bmp\";\n\n    public static final String IMAGE_GIF = \"image/gif\";\n\n    public static final String[] IMAGE_EXTENSION = { \"bmp\", \"gif\", \"jpg\", \"jpeg\", \"png\" };\n\n    public static final String[] FLASH_EXTENSION = { \"swf\", \"flv\" };\n\n    public static final String[] MEDIA_EXTENSION = { \"swf\", \"flv\", \"mp3\", \"wav\", \"wma\", \"wmv\", \"mid\", \"avi\", \"mpg\",\n            \"asf\", \"rm\", \"rmvb\" };\n\n    public static final String[] VIDEO_EXTENSION = { \"mp4\", \"avi\", \"rmvb\" };\n\n    public static final String[] DEFAULT_ALLOWED_EXTENSION = {\n            // 图片\n            \"bmp\", \"gif\", \"jpg\", \"jpeg\", \"png\",\n            // word excel powerpoint\n            \"doc\", \"docx\", \"xls\", \"xlsx\", \"ppt\", \"pptx\", \"html\", \"htm\", \"txt\",\n            // 压缩文件\n            \"rar\", \"zip\", \"gz\", \"bz2\",\n            // 视频格式\n            \"mp4\", \"avi\", \"rmvb\",\n            // pdf\n            \"pdf\" };\n\n    public static String getExtension(String prefix)\n    {\n        switch (prefix)\n        {\n            case IMAGE_PNG:\n                return \"png\";\n            case IMAGE_JPG:\n                return \"jpg\";\n            case IMAGE_JPEG:\n                return \"jpeg\";\n            case IMAGE_BMP:\n                return \"bmp\";\n            case IMAGE_GIF:\n                return \"gif\";\n            default:\n                return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java",
    "content": "package com.ruoyi.common.utils.html;\n\nimport com.ruoyi.common.utils.StringUtils;\n\n/**\n * 转义和反转义工具类\n * \n * @author ruoyi\n */\npublic class EscapeUtil\n{\n    public static final String RE_HTML_MARK = \"(<[^<]*?>)|(<[\\\\s]*?/[^<]*?>)|(<[^<]*?/[\\\\s]*?>)\";\n\n    private static final char[][] TEXT = new char[64][];\n\n    static\n    {\n        for (int i = 0; i < 64; i++)\n        {\n            TEXT[i] = new char[] { (char) i };\n        }\n\n        // special HTML characters\n        TEXT['\\''] = \"&#039;\".toCharArray(); // 单引号\n        TEXT['\"'] = \"&#34;\".toCharArray(); // 双引号\n        TEXT['&'] = \"&#38;\".toCharArray(); // &符\n        TEXT['<'] = \"&#60;\".toCharArray(); // 小于号\n        TEXT['>'] = \"&#62;\".toCharArray(); // 大于号\n    }\n\n    /**\n     * 转义文本中的HTML字符为安全的字符\n     * \n     * @param text 被转义的文本\n     * @return 转义后的文本\n     */\n    public static String escape(String text)\n    {\n        return encode(text);\n    }\n\n    /**\n     * 还原被转义的HTML特殊字符\n     * \n     * @param content 包含转义符的HTML内容\n     * @return 转换后的字符串\n     */\n    public static String unescape(String content)\n    {\n        return decode(content);\n    }\n\n    /**\n     * 清除所有HTML标签，但是不删除标签内的内容\n     * \n     * @param content 文本\n     * @return 清除标签后的文本\n     */\n    public static String clean(String content)\n    {\n        return new HTMLFilter().filter(content);\n    }\n\n    /**\n     * Escape编码\n     * \n     * @param text 被编码的文本\n     * @return 编码后的字符\n     */\n    private static String encode(String text)\n    {\n        if (StringUtils.isEmpty(text))\n        {\n            return StringUtils.EMPTY;\n        }\n\n        final StringBuilder tmp = new StringBuilder(text.length() * 6);\n        char c;\n        for (int i = 0; i < text.length(); i++)\n        {\n            c = text.charAt(i);\n            if (c < 256)\n            {\n                tmp.append(\"%\");\n                if (c < 16)\n                {\n                    tmp.append(\"0\");\n                }\n                tmp.append(Integer.toString(c, 16));\n            }\n            else\n            {\n                tmp.append(\"%u\");\n                if (c <= 0xfff)\n                {\n                    // issue#I49JU8@Gitee\n                    tmp.append(\"0\");\n                }\n                tmp.append(Integer.toString(c, 16));\n            }\n        }\n        return tmp.toString();\n    }\n\n    /**\n     * Escape解码\n     * \n     * @param content 被转义的内容\n     * @return 解码后的字符串\n     */\n    public static String decode(String content)\n    {\n        if (StringUtils.isEmpty(content))\n        {\n            return content;\n        }\n\n        StringBuilder tmp = new StringBuilder(content.length());\n        int lastPos = 0, pos = 0;\n        char ch;\n        while (lastPos < content.length())\n        {\n            pos = content.indexOf(\"%\", lastPos);\n            if (pos == lastPos)\n            {\n                if (content.charAt(pos + 1) == 'u')\n                {\n                    ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);\n                    tmp.append(ch);\n                    lastPos = pos + 6;\n                }\n                else\n                {\n                    ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);\n                    tmp.append(ch);\n                    lastPos = pos + 3;\n                }\n            }\n            else\n            {\n                if (pos == -1)\n                {\n                    tmp.append(content.substring(lastPos));\n                    lastPos = content.length();\n                }\n                else\n                {\n                    tmp.append(content.substring(lastPos, pos));\n                    lastPos = pos;\n                }\n            }\n        }\n        return tmp.toString();\n    }\n\n    public static void main(String[] args)\n    {\n        String html = \"<script>alert(1);</script>\";\n        String escape = EscapeUtil.escape(html);\n        // String html = \"<scr<script>ipt>alert(\\\"XSS\\\")</scr<script>ipt>\";\n        // String html = \"<123\";\n        // String html = \"123>\";\n        System.out.println(\"clean: \" + EscapeUtil.clean(html));\n        System.out.println(\"escape: \" + escape);\n        System.out.println(\"unescape: \" + EscapeUtil.unescape(escape));\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java",
    "content": "package com.ruoyi.common.utils.html;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * HTML过滤器，用于去除XSS漏洞隐患。\n *\n * @author ruoyi\n */\npublic final class HTMLFilter\n{\n    /**\n     * regex flag union representing /si modifiers in php\n     **/\n    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;\n    private static final Pattern P_COMMENTS = Pattern.compile(\"<!--(.*?)-->\", Pattern.DOTALL);\n    private static final Pattern P_COMMENT = Pattern.compile(\"^!--(.*)--$\", REGEX_FLAGS_SI);\n    private static final Pattern P_TAGS = Pattern.compile(\"<(.*?)>\", Pattern.DOTALL);\n    private static final Pattern P_END_TAG = Pattern.compile(\"^/([a-z0-9]+)\", REGEX_FLAGS_SI);\n    private static final Pattern P_START_TAG = Pattern.compile(\"^([a-z0-9]+)(.*?)(/?)$\", REGEX_FLAGS_SI);\n    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile(\"([a-z0-9]+)=([\\\"'])(.*?)\\\\2\", REGEX_FLAGS_SI);\n    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile(\"([a-z0-9]+)(=)([^\\\"\\\\s']+)\", REGEX_FLAGS_SI);\n    private static final Pattern P_PROTOCOL = Pattern.compile(\"^([^:]+):\", REGEX_FLAGS_SI);\n    private static final Pattern P_ENTITY = Pattern.compile(\"&#(\\\\d+);?\");\n    private static final Pattern P_ENTITY_UNICODE = Pattern.compile(\"&#x([0-9a-f]+);?\");\n    private static final Pattern P_ENCODE = Pattern.compile(\"%([0-9a-f]{2});?\");\n    private static final Pattern P_VALID_ENTITIES = Pattern.compile(\"&([^&;]*)(?=(;|&|$))\");\n    private static final Pattern P_VALID_QUOTES = Pattern.compile(\"(>|^)([^<]+?)(<|$)\", Pattern.DOTALL);\n    private static final Pattern P_END_ARROW = Pattern.compile(\"^>\");\n    private static final Pattern P_BODY_TO_END = Pattern.compile(\"<([^>]*?)(?=<|$)\");\n    private static final Pattern P_XML_CONTENT = Pattern.compile(\"(^|>)([^<]*?)(?=>)\");\n    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile(\"<([^>]*?)(?=<|$)\");\n    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile(\"(^|>)([^<]*?)(?=>)\");\n    private static final Pattern P_AMP = Pattern.compile(\"&\");\n    private static final Pattern P_QUOTE = Pattern.compile(\"\\\"\");\n    private static final Pattern P_LEFT_ARROW = Pattern.compile(\"<\");\n    private static final Pattern P_RIGHT_ARROW = Pattern.compile(\">\");\n    private static final Pattern P_BOTH_ARROWS = Pattern.compile(\"<>\");\n\n    // @xxx could grow large... maybe use sesat's ReferenceMap\n    private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();\n    private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();\n\n    /**\n     * set of allowed html elements, along with allowed attributes for each element\n     **/\n    private final Map<String, List<String>> vAllowed;\n    /**\n     * counts of open tags for each (allowable) html element\n     **/\n    private final Map<String, Integer> vTagCounts = new HashMap<>();\n\n    /**\n     * html elements which must always be self-closing (e.g. \"<img />\")\n     **/\n    private final String[] vSelfClosingTags;\n    /**\n     * html elements which must always have separate opening and closing tags (e.g. \"<b></b>\")\n     **/\n    private final String[] vNeedClosingTags;\n    /**\n     * set of disallowed html elements\n     **/\n    private final String[] vDisallowed;\n    /**\n     * attributes which should be checked for valid protocols\n     **/\n    private final String[] vProtocolAtts;\n    /**\n     * allowed protocols\n     **/\n    private final String[] vAllowedProtocols;\n    /**\n     * tags which should be removed if they contain no content (e.g. \"<b></b>\" or \"<b />\")\n     **/\n    private final String[] vRemoveBlanks;\n    /**\n     * entities allowed within html markup\n     **/\n    private final String[] vAllowedEntities;\n    /**\n     * flag determining whether comments are allowed in input String.\n     */\n    private final boolean stripComment;\n    private final boolean encodeQuotes;\n    /**\n     * flag determining whether to try to make tags when presented with \"unbalanced\" angle brackets (e.g. \"<b text </b>\"\n     * becomes \"<b> text </b>\"). If set to false, unbalanced angle brackets will be html escaped.\n     */\n    private final boolean alwaysMakeTags;\n\n    /**\n     * Default constructor.\n     */\n    public HTMLFilter()\n    {\n        vAllowed = new HashMap<>();\n\n        final ArrayList<String> a_atts = new ArrayList<>();\n        a_atts.add(\"href\");\n        a_atts.add(\"target\");\n        vAllowed.put(\"a\", a_atts);\n\n        final ArrayList<String> img_atts = new ArrayList<>();\n        img_atts.add(\"src\");\n        img_atts.add(\"width\");\n        img_atts.add(\"height\");\n        img_atts.add(\"alt\");\n        vAllowed.put(\"img\", img_atts);\n\n        final ArrayList<String> no_atts = new ArrayList<>();\n        vAllowed.put(\"b\", no_atts);\n        vAllowed.put(\"strong\", no_atts);\n        vAllowed.put(\"i\", no_atts);\n        vAllowed.put(\"em\", no_atts);\n\n        vSelfClosingTags = new String[] { \"img\" };\n        vNeedClosingTags = new String[] { \"a\", \"b\", \"strong\", \"i\", \"em\" };\n        vDisallowed = new String[] {};\n        vAllowedProtocols = new String[] { \"http\", \"mailto\", \"https\" }; // no ftp.\n        vProtocolAtts = new String[] { \"src\", \"href\" };\n        vRemoveBlanks = new String[] { \"a\", \"b\", \"strong\", \"i\", \"em\" };\n        vAllowedEntities = new String[] { \"amp\", \"gt\", \"lt\", \"quot\" };\n        stripComment = true;\n        encodeQuotes = true;\n        alwaysMakeTags = false;\n    }\n\n    /**\n     * Map-parameter configurable constructor.\n     *\n     * @param conf map containing configuration. keys match field names.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public HTMLFilter(final Map<String, Object> conf)\n    {\n\n        assert conf.containsKey(\"vAllowed\") : \"configuration requires vAllowed\";\n        assert conf.containsKey(\"vSelfClosingTags\") : \"configuration requires vSelfClosingTags\";\n        assert conf.containsKey(\"vNeedClosingTags\") : \"configuration requires vNeedClosingTags\";\n        assert conf.containsKey(\"vDisallowed\") : \"configuration requires vDisallowed\";\n        assert conf.containsKey(\"vAllowedProtocols\") : \"configuration requires vAllowedProtocols\";\n        assert conf.containsKey(\"vProtocolAtts\") : \"configuration requires vProtocolAtts\";\n        assert conf.containsKey(\"vRemoveBlanks\") : \"configuration requires vRemoveBlanks\";\n        assert conf.containsKey(\"vAllowedEntities\") : \"configuration requires vAllowedEntities\";\n\n        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get(\"vAllowed\"));\n        vSelfClosingTags = (String[]) conf.get(\"vSelfClosingTags\");\n        vNeedClosingTags = (String[]) conf.get(\"vNeedClosingTags\");\n        vDisallowed = (String[]) conf.get(\"vDisallowed\");\n        vAllowedProtocols = (String[]) conf.get(\"vAllowedProtocols\");\n        vProtocolAtts = (String[]) conf.get(\"vProtocolAtts\");\n        vRemoveBlanks = (String[]) conf.get(\"vRemoveBlanks\");\n        vAllowedEntities = (String[]) conf.get(\"vAllowedEntities\");\n        stripComment = conf.containsKey(\"stripComment\") ? (Boolean) conf.get(\"stripComment\") : true;\n        encodeQuotes = conf.containsKey(\"encodeQuotes\") ? (Boolean) conf.get(\"encodeQuotes\") : true;\n        alwaysMakeTags = conf.containsKey(\"alwaysMakeTags\") ? (Boolean) conf.get(\"alwaysMakeTags\") : true;\n    }\n\n    private void reset()\n    {\n        vTagCounts.clear();\n    }\n\n    // ---------------------------------------------------------------\n    // my versions of some PHP library functions\n    public static String chr(final int decimal)\n    {\n        return String.valueOf((char) decimal);\n    }\n\n    public static String htmlSpecialChars(final String s)\n    {\n        String result = s;\n        result = regexReplace(P_AMP, \"&amp;\", result);\n        result = regexReplace(P_QUOTE, \"&quot;\", result);\n        result = regexReplace(P_LEFT_ARROW, \"&lt;\", result);\n        result = regexReplace(P_RIGHT_ARROW, \"&gt;\", result);\n        return result;\n    }\n\n    // ---------------------------------------------------------------\n\n    /**\n     * given a user submitted input String, filter out any invalid or restricted html.\n     *\n     * @param input text (i.e. submitted by a user) than may contain html\n     * @return \"clean\" version of input, with only valid, whitelisted html elements allowed\n     */\n    public String filter(final String input)\n    {\n        reset();\n        String s = input;\n\n        s = escapeComments(s);\n\n        s = balanceHTML(s);\n\n        s = checkTags(s);\n\n        s = processRemoveBlanks(s);\n\n        // s = validateEntities(s);\n\n        return s;\n    }\n\n    public boolean isAlwaysMakeTags()\n    {\n        return alwaysMakeTags;\n    }\n\n    public boolean isStripComments()\n    {\n        return stripComment;\n    }\n\n    private String escapeComments(final String s)\n    {\n        final Matcher m = P_COMMENTS.matcher(s);\n        final StringBuffer buf = new StringBuffer();\n        if (m.find())\n        {\n            final String match = m.group(1); // (.*?)\n            m.appendReplacement(buf, Matcher.quoteReplacement(\"<!--\" + htmlSpecialChars(match) + \"-->\"));\n        }\n        m.appendTail(buf);\n\n        return buf.toString();\n    }\n\n    private String balanceHTML(String s)\n    {\n        if (alwaysMakeTags)\n        {\n            //\n            // try and form html\n            //\n            s = regexReplace(P_END_ARROW, \"\", s);\n            // 不追加结束标签\n            s = regexReplace(P_BODY_TO_END, \"<$1>\", s);\n            s = regexReplace(P_XML_CONTENT, \"$1<$2\", s);\n\n        }\n        else\n        {\n            //\n            // escape stray brackets\n            //\n            s = regexReplace(P_STRAY_LEFT_ARROW, \"&lt;$1\", s);\n            s = regexReplace(P_STRAY_RIGHT_ARROW, \"$1$2&gt;<\", s);\n\n            //\n            // the last regexp causes '<>' entities to appear\n            // (we need to do a lookahead assertion so that the last bracket can\n            // be used in the next pass of the regexp)\n            //\n            s = regexReplace(P_BOTH_ARROWS, \"\", s);\n        }\n\n        return s;\n    }\n\n    private String checkTags(String s)\n    {\n        Matcher m = P_TAGS.matcher(s);\n\n        final StringBuffer buf = new StringBuffer();\n        while (m.find())\n        {\n            String replaceStr = m.group(1);\n            replaceStr = processTag(replaceStr);\n            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));\n        }\n        m.appendTail(buf);\n\n        // these get tallied in processTag\n        // (remember to reset before subsequent calls to filter method)\n        final StringBuilder sBuilder = new StringBuilder(buf.toString());\n        for (String key : vTagCounts.keySet())\n        {\n            for (int ii = 0; ii < vTagCounts.get(key); ii++)\n            {\n                sBuilder.append(\"</\").append(key).append(\">\");\n            }\n        }\n        s = sBuilder.toString();\n\n        return s;\n    }\n\n    private String processRemoveBlanks(final String s)\n    {\n        String result = s;\n        for (String tag : vRemoveBlanks)\n        {\n            if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))\n            {\n                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile(\"<\" + tag + \"(\\\\s[^>]*)?></\" + tag + \">\"));\n            }\n            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), \"\", result);\n            if (!P_REMOVE_SELF_BLANKS.containsKey(tag))\n            {\n                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile(\"<\" + tag + \"(\\\\s[^>]*)?/>\"));\n            }\n            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), \"\", result);\n        }\n\n        return result;\n    }\n\n    private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)\n    {\n        Matcher m = regex_pattern.matcher(s);\n        return m.replaceAll(replacement);\n    }\n\n    private String processTag(final String s)\n    {\n        // ending tags\n        Matcher m = P_END_TAG.matcher(s);\n        if (m.find())\n        {\n            final String name = m.group(1).toLowerCase();\n            if (allowed(name))\n            {\n                if (false == inArray(name, vSelfClosingTags))\n                {\n                    if (vTagCounts.containsKey(name))\n                    {\n                        vTagCounts.put(name, vTagCounts.get(name) - 1);\n                        return \"</\" + name + \">\";\n                    }\n                }\n            }\n        }\n\n        // starting tags\n        m = P_START_TAG.matcher(s);\n        if (m.find())\n        {\n            final String name = m.group(1).toLowerCase();\n            final String body = m.group(2);\n            String ending = m.group(3);\n\n            // debug( \"in a starting tag, name='\" + name + \"'; body='\" + body + \"'; ending='\" + ending + \"'\" );\n            if (allowed(name))\n            {\n                final StringBuilder params = new StringBuilder();\n\n                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);\n                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);\n                final List<String> paramNames = new ArrayList<>();\n                final List<String> paramValues = new ArrayList<>();\n                while (m2.find())\n                {\n                    paramNames.add(m2.group(1)); // ([a-z0-9]+)\n                    paramValues.add(m2.group(3)); // (.*?)\n                }\n                while (m3.find())\n                {\n                    paramNames.add(m3.group(1)); // ([a-z0-9]+)\n                    paramValues.add(m3.group(3)); // ([^\\\"\\\\s']+)\n                }\n\n                String paramName, paramValue;\n                for (int ii = 0; ii < paramNames.size(); ii++)\n                {\n                    paramName = paramNames.get(ii).toLowerCase();\n                    paramValue = paramValues.get(ii);\n\n                    // debug( \"paramName='\" + paramName + \"'\" );\n                    // debug( \"paramValue='\" + paramValue + \"'\" );\n                    // debug( \"allowed? \" + vAllowed.get( name ).contains( paramName ) );\n\n                    if (allowedAttribute(name, paramName))\n                    {\n                        if (inArray(paramName, vProtocolAtts))\n                        {\n                            paramValue = processParamProtocol(paramValue);\n                        }\n                        params.append(' ').append(paramName).append(\"=\\\"\").append(paramValue).append(\"\\\"\");\n                    }\n                }\n\n                if (inArray(name, vSelfClosingTags))\n                {\n                    ending = \" /\";\n                }\n\n                if (inArray(name, vNeedClosingTags))\n                {\n                    ending = \"\";\n                }\n\n                if (ending == null || ending.length() < 1)\n                {\n                    if (vTagCounts.containsKey(name))\n                    {\n                        vTagCounts.put(name, vTagCounts.get(name) + 1);\n                    }\n                    else\n                    {\n                        vTagCounts.put(name, 1);\n                    }\n                }\n                else\n                {\n                    ending = \" /\";\n                }\n                return \"<\" + name + params + ending + \">\";\n            }\n            else\n            {\n                return \"\";\n            }\n        }\n\n        // comments\n        m = P_COMMENT.matcher(s);\n        if (!stripComment && m.find())\n        {\n            return \"<\" + m.group() + \">\";\n        }\n\n        return \"\";\n    }\n\n    private String processParamProtocol(String s)\n    {\n        s = decodeEntities(s);\n        final Matcher m = P_PROTOCOL.matcher(s);\n        if (m.find())\n        {\n            final String protocol = m.group(1);\n            if (!inArray(protocol, vAllowedProtocols))\n            {\n                // bad protocol, turn into local anchor link instead\n                s = \"#\" + s.substring(protocol.length() + 1);\n                if (s.startsWith(\"#//\"))\n                {\n                    s = \"#\" + s.substring(3);\n                }\n            }\n        }\n\n        return s;\n    }\n\n    private String decodeEntities(String s)\n    {\n        StringBuffer buf = new StringBuffer();\n\n        Matcher m = P_ENTITY.matcher(s);\n        while (m.find())\n        {\n            final String match = m.group(1);\n            final int decimal = Integer.decode(match).intValue();\n            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));\n        }\n        m.appendTail(buf);\n        s = buf.toString();\n\n        buf = new StringBuffer();\n        m = P_ENTITY_UNICODE.matcher(s);\n        while (m.find())\n        {\n            final String match = m.group(1);\n            final int decimal = Integer.valueOf(match, 16).intValue();\n            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));\n        }\n        m.appendTail(buf);\n        s = buf.toString();\n\n        buf = new StringBuffer();\n        m = P_ENCODE.matcher(s);\n        while (m.find())\n        {\n            final String match = m.group(1);\n            final int decimal = Integer.valueOf(match, 16).intValue();\n            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));\n        }\n        m.appendTail(buf);\n        s = buf.toString();\n\n        s = validateEntities(s);\n        return s;\n    }\n\n    private String validateEntities(final String s)\n    {\n        StringBuffer buf = new StringBuffer();\n\n        // validate entities throughout the string\n        Matcher m = P_VALID_ENTITIES.matcher(s);\n        while (m.find())\n        {\n            final String one = m.group(1); // ([^&;]*)\n            final String two = m.group(2); // (?=(;|&|$))\n            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));\n        }\n        m.appendTail(buf);\n\n        return encodeQuotes(buf.toString());\n    }\n\n    private String encodeQuotes(final String s)\n    {\n        if (encodeQuotes)\n        {\n            StringBuffer buf = new StringBuffer();\n            Matcher m = P_VALID_QUOTES.matcher(s);\n            while (m.find())\n            {\n                final String one = m.group(1); // (>|^)\n                final String two = m.group(2); // ([^<]+?)\n                final String three = m.group(3); // (<|$)\n                // 不替换双引号为&quot;，防止json格式无效 regexReplace(P_QUOTE, \"&quot;\", two)\n                m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));\n            }\n            m.appendTail(buf);\n            return buf.toString();\n        }\n        else\n        {\n            return s;\n        }\n    }\n\n    private String checkEntity(final String preamble, final String term)\n    {\n\n        return \";\".equals(term) && isValidEntity(preamble) ? '&' + preamble : \"&amp;\" + preamble;\n    }\n\n    private boolean isValidEntity(final String entity)\n    {\n        return inArray(entity, vAllowedEntities);\n    }\n\n    private static boolean inArray(final String s, final String[] array)\n    {\n        for (String item : array)\n        {\n            if (item != null && item.equals(s))\n            {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private boolean allowed(final String name)\n    {\n        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);\n    }\n\n    private boolean allowedAttribute(final String name, final String paramName)\n    {\n        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));\n    }\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java",
    "content": "package com.ruoyi.common.utils.http;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.InputStreamReader;\r\nimport java.io.PrintWriter;\r\nimport java.net.ConnectException;\r\nimport java.net.SocketTimeoutException;\r\nimport java.net.URL;\r\nimport java.net.URLConnection;\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.security.cert.X509Certificate;\r\nimport javax.net.ssl.HostnameVerifier;\r\nimport javax.net.ssl.HttpsURLConnection;\r\nimport javax.net.ssl.SSLContext;\r\nimport javax.net.ssl.SSLSession;\r\nimport javax.net.ssl.TrustManager;\r\nimport javax.net.ssl.X509TrustManager;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport org.springframework.http.MediaType;\r\n\r\n/**\r\n * 通用http发送方法\r\n * \r\n * @author ruoyi\r\n */\r\npublic class HttpUtils\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);\r\n\r\n    /**\r\n     * 向指定 URL 发送GET方法的请求\r\n     *\r\n     * @param url 发送请求的 URL\r\n     * @return 所代表远程资源的响应结果\r\n     */\r\n    public static String sendGet(String url)\r\n    {\r\n        return sendGet(url, StringUtils.EMPTY);\r\n    }\r\n\r\n    /**\r\n     * 向指定 URL 发送GET方法的请求\r\n     *\r\n     * @param url 发送请求的 URL\r\n     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。\r\n     * @return 所代表远程资源的响应结果\r\n     */\r\n    public static String sendGet(String url, String param)\r\n    {\r\n        return sendGet(url, param, Constants.UTF8);\r\n    }\r\n\r\n    /**\r\n     * 向指定 URL 发送GET方法的请求\r\n     *\r\n     * @param url 发送请求的 URL\r\n     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。\r\n     * @param contentType 编码类型\r\n     * @return 所代表远程资源的响应结果\r\n     */\r\n    public static String sendGet(String url, String param, String contentType)\r\n    {\r\n        StringBuilder result = new StringBuilder();\r\n        BufferedReader in = null;\r\n        try\r\n        {\r\n            String urlNameString = StringUtils.isNotBlank(param) ? url + \"?\" + param : url;\r\n            log.info(\"sendGet - {}\", urlNameString);\r\n            URL realUrl = new URL(urlNameString);\r\n            URLConnection connection = realUrl.openConnection();\r\n            connection.setRequestProperty(\"accept\", \"*/*\");\r\n            connection.setRequestProperty(\"connection\", \"Keep-Alive\");\r\n            connection.setRequestProperty(\"user-agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\");\r\n            connection.connect();\r\n            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));\r\n            String line;\r\n            while ((line = in.readLine()) != null)\r\n            {\r\n                result.append(line);\r\n            }\r\n            log.info(\"recv - {}\", result);\r\n        }\r\n        catch (ConnectException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendGet ConnectException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (SocketTimeoutException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendGet SocketTimeoutException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendGet IOException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"调用HttpsUtil.sendGet Exception, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        finally\r\n        {\r\n            try\r\n            {\r\n                if (in != null)\r\n                {\r\n                    in.close();\r\n                }\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                log.error(\"调用in.close Exception, url=\" + url + \",param=\" + param, ex);\r\n            }\r\n        }\r\n        return result.toString();\r\n    }\r\n\r\n    /**\r\n     * 向指定 URL 发送POST方法的请求\r\n     *\r\n     * @param url 发送请求的 URL\r\n     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。\r\n     * @return 所代表远程资源的响应结果\r\n     */\r\n    public static String sendPost(String url, String param)\r\n    {\r\n        return sendPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);\r\n    }\r\n\r\n    /**\r\n     * 向指定 URL 发送POST方法的请求\r\n     * \r\n     * @param url 发送请求的 URL\r\n     * @param param 请求参数\r\n     * @param contentType 内容类型\r\n     * @return 所代表远程资源的响应结果\r\n     */\r\n    public static String sendPost(String url, String param, String contentType)\r\n    {\r\n        PrintWriter out = null;\r\n        BufferedReader in = null;\r\n        StringBuilder result = new StringBuilder();\r\n        try\r\n        {\r\n            log.info(\"sendPost - {}\", url);\r\n            URL realUrl = new URL(url);\r\n            URLConnection conn = realUrl.openConnection();\r\n            conn.setRequestProperty(\"accept\", \"*/*\");\r\n            conn.setRequestProperty(\"connection\", \"Keep-Alive\");\r\n            conn.setRequestProperty(\"user-agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\");\r\n            conn.setRequestProperty(\"Accept-Charset\", \"utf-8\");\r\n            conn.setRequestProperty(\"Content-Type\", contentType);\r\n            conn.setDoOutput(true);\r\n            conn.setDoInput(true);\r\n            out = new PrintWriter(conn.getOutputStream());\r\n            out.print(param);\r\n            out.flush();\r\n            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));\r\n            String line;\r\n            while ((line = in.readLine()) != null)\r\n            {\r\n                result.append(line);\r\n            }\r\n            log.info(\"recv - {}\", result);\r\n        }\r\n        catch (ConnectException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendPost ConnectException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (SocketTimeoutException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendPost SocketTimeoutException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendPost IOException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"调用HttpsUtil.sendPost Exception, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        finally\r\n        {\r\n            try\r\n            {\r\n                if (out != null)\r\n                {\r\n                    out.close();\r\n                }\r\n                if (in != null)\r\n                {\r\n                    in.close();\r\n                }\r\n            }\r\n            catch (IOException ex)\r\n            {\r\n                log.error(\"调用in.close Exception, url=\" + url + \",param=\" + param, ex);\r\n            }\r\n        }\r\n        return result.toString();\r\n    }\r\n\r\n    public static String sendSSLPost(String url, String param)\r\n    {\r\n        return sendSSLPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);\r\n    }\r\n\r\n    public static String sendSSLPost(String url, String param, String contentType)\r\n    {\r\n        StringBuilder result = new StringBuilder();\r\n        String urlNameString = url + \"?\" + param;\r\n        try\r\n        {\r\n            log.info(\"sendSSLPost - {}\", urlNameString);\r\n            SSLContext sc = SSLContext.getInstance(\"SSL\");\r\n            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());\r\n            URL console = new URL(urlNameString);\r\n            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();\r\n            conn.setRequestProperty(\"accept\", \"*/*\");\r\n            conn.setRequestProperty(\"connection\", \"Keep-Alive\");\r\n            conn.setRequestProperty(\"user-agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\");\r\n            conn.setRequestProperty(\"Accept-Charset\", \"utf-8\");\r\n            conn.setRequestProperty(\"Content-Type\", contentType);\r\n            conn.setDoOutput(true);\r\n            conn.setDoInput(true);\r\n\r\n            conn.setSSLSocketFactory(sc.getSocketFactory());\r\n            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());\r\n            conn.connect();\r\n            InputStream is = conn.getInputStream();\r\n            BufferedReader br = new BufferedReader(new InputStreamReader(is));\r\n            String ret = \"\";\r\n            while ((ret = br.readLine()) != null)\r\n            {\r\n                if (ret != null && !\"\".equals(ret.trim()))\r\n                {\r\n                    result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));\r\n                }\r\n            }\r\n            log.info(\"recv - {}\", result);\r\n            conn.disconnect();\r\n            br.close();\r\n        }\r\n        catch (ConnectException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendSSLPost ConnectException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (SocketTimeoutException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendSSLPost SocketTimeoutException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            log.error(\"调用HttpUtils.sendSSLPost IOException, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"调用HttpsUtil.sendSSLPost Exception, url=\" + url + \",param=\" + param, e);\r\n        }\r\n        return result.toString();\r\n    }\r\n\r\n    private static class TrustAnyTrustManager implements X509TrustManager\r\n    {\r\n        @Override\r\n        public void checkClientTrusted(X509Certificate[] chain, String authType)\r\n        {\r\n        }\r\n\r\n        @Override\r\n        public void checkServerTrusted(X509Certificate[] chain, String authType)\r\n        {\r\n        }\r\n\r\n        @Override\r\n        public X509Certificate[] getAcceptedIssuers()\r\n        {\r\n            return new X509Certificate[] {};\r\n        }\r\n    }\r\n\r\n    private static class TrustAnyHostnameVerifier implements HostnameVerifier\r\n    {\r\n        @Override\r\n        public boolean verify(String hostname, SSLSession session)\r\n        {\r\n            return true;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/http/UserAgentUtils.java",
    "content": "package com.ruoyi.common.utils.http;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport com.ruoyi.common.utils.StringUtils;\nimport nl.basjes.parse.useragent.UserAgent;\nimport nl.basjes.parse.useragent.UserAgentAnalyzer;\n\n/**\n * UserAgent解析工具类\n * \n * @author ruoyi\n */\npublic class UserAgentUtils\n{\n    public static final String UNKNOWN = \"\";\n\n    // 浏览器正则表达式模式\n    private static final Pattern CHROME_PATTERN = Pattern.compile(\"Chrome/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern FIREFOX_PATTERN = Pattern.compile(\"Firefox/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern EDGE_PATTERN = Pattern.compile(\"Edg(?:e)?/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern SAFARI_PATTERN = Pattern.compile(\"Version/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern OPERA_PATTERN = Pattern.compile(\"Opera/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern IE_PATTERN = Pattern.compile(\"(?:MSIE |Trident/.*rv:)(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern SAMSUNG_PATTERN = Pattern.compile(\"SamsungBrowser/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern UC_PATTERN = Pattern.compile(\"UCBrowser/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern QQ_PATTERN = Pattern.compile(\"QQBrowser/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern WECHAT_PATTERN = Pattern.compile(\"MicroMessenger/(\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern BAIDU_PATTERN = Pattern.compile(\"baidubrowser/(\\\\d+)(?:\\\\.\\\\d+)*\");\n\n    // 操作系统正则表达式模式\n    private static final Pattern WINDOWS_PATTERN = Pattern.compile(\"Windows NT (\\\\d+\\\\.\\\\d+)\");\n    private static final Pattern MACOS_PATTERN = Pattern.compile(\"Mac OS X (\\\\d+[_\\\\d]*)\");\n    private static final Pattern ANDROID_PATTERN = Pattern.compile(\"Android (\\\\d+)(?:\\\\.\\\\d+)*\");\n    private static final Pattern IOS_PATTERN = Pattern.compile(\"OS[\\\\s_](\\\\d+)(?:_\\\\d+)*\");\n    private static final Pattern LINUX_PATTERN = Pattern.compile(\"Linux\");\n    private static final Pattern CHROMEOS_PATTERN = Pattern.compile(\"CrOS\");\n\n    private static final UserAgentAnalyzer userAgentAnalyzer = UserAgentAnalyzer\n            .newBuilder().hideMatcherLoadStats()\n            .withCache(5000)\n            .showMinimalVersion()\n            .withField(UserAgent.AGENT_NAME_VERSION)\n            .withField(UserAgent.OPERATING_SYSTEM_NAME_VERSION)\n            .build();\n\n    /**\n     * 获取客户端浏览器\n     */\n    public static String getBrowser(String userAgent)\n    {\n        UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent);\n        String agentNameVersion = iua.get(UserAgent.AGENT_NAME_VERSION).getValue();\n        if (StringUtils.isBlank(agentNameVersion) || agentNameVersion.contains(\"??\"))\n        {\n            return formatBrowser(userAgent);\n        }\n        return agentNameVersion;\n    }\n\n    /**\n     * 获取客户端操作系统\n     */\n    public static String getOperatingSystem(String userAgent)\n    {\n        UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent);\n        String operatingSystemNameVersion = iua.get(UserAgent.OPERATING_SYSTEM_NAME_VERSION).getValue();\n        if (StringUtils.isBlank(operatingSystemNameVersion) || operatingSystemNameVersion.contains(\"??\"))\n        {\n            return formatOperatingSystem(userAgent);\n        }\n        return operatingSystemNameVersion;\n    }\n\n    /**\n     * 全面浏览器检测\n     */\n    private static String formatBrowser(String browser)\n    {\n        // Chrome系列浏览器\n        Matcher chromeMatcher = CHROME_PATTERN.matcher(browser);\n        if (chromeMatcher.find() && (browser.contains(\"Chrome\") || browser.contains(\"CriOS\")))\n        {\n            return \"Chrome\" + chromeMatcher.group(1);\n        }\n        // Firefox\n        Matcher firefoxMatcher = FIREFOX_PATTERN.matcher(browser);\n        if (firefoxMatcher.find())\n        {\n            return \"Firefox\" + firefoxMatcher.group(1);\n        }\n        // Edge浏览器\n        Matcher edgeMatcher = EDGE_PATTERN.matcher(browser);\n        if (edgeMatcher.find())\n        {\n            return \"Edge\" + edgeMatcher.group(1);\n        }\n        // Safari浏览器（需排除Chrome）\n        Matcher safariMatcher = SAFARI_PATTERN.matcher(browser);\n        if (safariMatcher.find() && !browser.contains(\"Chrome\"))\n        {\n            return \"Safari\" + safariMatcher.group(1);\n        }\n        // 微信内置浏览器\n        Matcher wechatMatcher = WECHAT_PATTERN.matcher(browser);\n        if (wechatMatcher.find())\n        {\n            return \"WeChat\" + wechatMatcher.group(1);\n        }\n        // UC浏览器\n        Matcher ucMatcher = UC_PATTERN.matcher(browser);\n        if (ucMatcher.find())\n        {\n            return \"UC Browser\" + ucMatcher.group(1);\n        }\n        // QQ浏览器\n        Matcher qqMatcher = QQ_PATTERN.matcher(browser);\n        if (qqMatcher.find())\n        {\n            return \"QQ Browser\" + qqMatcher.group(1);\n        }\n        // 百度浏览器\n        Matcher baiduMatcher = BAIDU_PATTERN.matcher(browser);\n        if (baiduMatcher.find())\n        {\n            return \"Baidu Browser\" + baiduMatcher.group(1);\n        }\n        // Samsung浏览器\n        Matcher samsungMatcher = SAMSUNG_PATTERN.matcher(browser);\n        if (samsungMatcher.find())\n        {\n            return \"Samsung Browser\" + samsungMatcher.group(1);\n        }\n        // Opera浏览器\n        Matcher operaMatcher = OPERA_PATTERN.matcher(browser);\n        if (operaMatcher.find())\n        {\n            return \"Opera\" + operaMatcher.group(1);\n        }\n        // IE浏览器\n        Matcher ieMatcher = IE_PATTERN.matcher(browser);\n        if (ieMatcher.find())\n        {\n            return \"Internet Explorer\" + ieMatcher.group(1);\n        }\n        return UNKNOWN;\n    }\n\n    /**\n     * 检测操作系统\n     */\n    private static String formatOperatingSystem(String operatingSystem)\n    {\n        // Windows系统\n        Matcher windowsMatcher = WINDOWS_PATTERN.matcher(operatingSystem);\n        if (windowsMatcher.find())\n        {\n            return \"Windows\" + getWindowsVersionDisplay(windowsMatcher.group(1));\n        }\n        // macOS系统\n        Matcher macMatcher = MACOS_PATTERN.matcher(operatingSystem);\n        if (macMatcher.find())\n        {\n            String version = macMatcher.group(1).replace(\"_\", \".\");\n            return \"macOS\" + extractMajorVersion(version);\n        }\n        // Android系统\n        Matcher androidMatcher = ANDROID_PATTERN.matcher(operatingSystem);\n        if (androidMatcher.find())\n        {\n            return \"Android\" + extractMajorVersion(androidMatcher.group(1));\n        }\n        // iOS系统\n        Matcher iosMatcher = IOS_PATTERN.matcher(operatingSystem);\n        if (iosMatcher.find() && (operatingSystem.contains(\"iPhone\") || operatingSystem.contains(\"iPad\")))\n        {\n            return \"iOS\" + extractMajorVersion(iosMatcher.group(1));\n        }\n        // Linux系统\n        if (LINUX_PATTERN.matcher(operatingSystem).find() && !operatingSystem.contains(\"Android\"))\n        {\n            return \"Linux\";\n        }\n        // Chrome OS\n        if (CHROMEOS_PATTERN.matcher(operatingSystem).find())\n        {\n            return \"Chrome OS\";\n        }\n        return UNKNOWN;\n    }\n\n    /**\n     * 提取优化的主版本号\n     */\n    private static String extractMajorVersion(String fullVersion)\n    {\n        if (StringUtils.isEmpty(fullVersion))\n        {\n            return StringUtils.EMPTY;\n        }\n        try\n        {\n            // 清理版本号中的非数字字符\n            String cleanVersion = fullVersion.replaceAll(\"[^0-9.]\", \"\");\n            String[] parts = cleanVersion.split(\"\\\\.\");\n            if (parts.length > 0)\n            {\n                String firstPart = parts[0];\n                if (firstPart.matches(\"\\\\d+\"))\n                {\n                    int version = Integer.parseInt(firstPart);\n\n                    // 处理三位数版本号（如142 -> 14）\n                    if (version >= 100)\n                    {\n                        return String.valueOf(version / 10);\n                    }\n                    return firstPart;\n                }\n            }\n        }\n        catch (NumberFormatException e)\n        {\n            // 版本号解析失败，返回原始值\n        }\n        return fullVersion;\n    }\n\n    /**\n     * Windows版本号显示优化\n     */\n    private static String getWindowsVersionDisplay(String version)\n    {\n        switch (version)\n        {\n            case \"10.0\":\n                return \"10\";\n            case \"6.3\":\n                return \"8.1\";\n            case \"6.2\":\n                return \"8\";\n            case \"6.1\":\n                return \"7\";\n            case \"6.0\":\n                return \"Vista\";\n            case \"5.1\":\n                return \"XP\";\n            case \"5.0\":\n                return \"2000\";\n            default:\n                return extractMajorVersion(version);\n        }\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java",
    "content": "package com.ruoyi.common.utils.poi;\n\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.Workbook;\n\n/**\n * Excel数据格式处理适配器\n * \n * @author ruoyi\n */\npublic interface ExcelHandlerAdapter\n{\n    /**\n     * 格式化\n     * \n     * @param value 单元格数据值\n     * @param args excel注解args参数组\n     * @param cell 单元格对象\n     * @param wb 工作簿对象\n     *\n     * @return 处理后的值\n     */\n    Object format(Object value, String[] args, Cell cell, Workbook wb);\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java",
    "content": "package com.ruoyi.common.utils.poi;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.math.BigDecimal;\nimport java.text.DecimalFormat;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.stream.Collectors;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.RegExUtils;\nimport org.apache.commons.lang3.reflect.FieldUtils;\nimport org.apache.poi.hssf.usermodel.HSSFClientAnchor;\nimport org.apache.poi.hssf.usermodel.HSSFPicture;\nimport org.apache.poi.hssf.usermodel.HSSFPictureData;\nimport org.apache.poi.hssf.usermodel.HSSFShape;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ooxml.POIXMLDocumentPart;\nimport org.apache.poi.ss.usermodel.BorderStyle;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.CellType;\nimport org.apache.poi.ss.usermodel.ClientAnchor;\nimport org.apache.poi.ss.usermodel.DataFormat;\nimport org.apache.poi.ss.usermodel.DataValidation;\nimport org.apache.poi.ss.usermodel.DataValidationConstraint;\nimport org.apache.poi.ss.usermodel.DataValidationHelper;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.apache.poi.ss.usermodel.Drawing;\nimport org.apache.poi.ss.usermodel.FillPatternType;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.HorizontalAlignment;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Name;\nimport org.apache.poi.ss.usermodel.PictureData;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.VerticalAlignment;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.ss.usermodel.WorkbookFactory;\nimport org.apache.poi.ss.util.CellRangeAddress;\nimport org.apache.poi.ss.util.CellRangeAddressList;\nimport org.apache.poi.util.IOUtils;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\nimport org.apache.poi.xssf.usermodel.XSSFClientAnchor;\nimport org.apache.poi.xssf.usermodel.XSSFDataValidation;\nimport org.apache.poi.xssf.usermodel.XSSFDrawing;\nimport org.apache.poi.xssf.usermodel.XSSFPicture;\nimport org.apache.poi.xssf.usermodel.XSSFShape;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\nimport org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport com.ruoyi.common.annotation.Excel;\nimport com.ruoyi.common.annotation.Excel.ColumnType;\nimport com.ruoyi.common.annotation.Excel.Type;\nimport com.ruoyi.common.annotation.Excels;\nimport com.ruoyi.common.config.RuoYiConfig;\nimport com.ruoyi.common.core.domain.AjaxResult;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.common.exception.UtilException;\nimport com.ruoyi.common.utils.DateUtils;\nimport com.ruoyi.common.utils.DictUtils;\nimport com.ruoyi.common.utils.StringUtils;\nimport com.ruoyi.common.utils.file.FileTypeUtils;\nimport com.ruoyi.common.utils.file.FileUtils;\nimport com.ruoyi.common.utils.file.ImageUtils;\nimport com.ruoyi.common.utils.reflect.ReflectUtils;\n\n/**\n * Excel相关处理\n * \n * @author ruoyi\n */\npublic class ExcelUtil<T>\n{\n    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);\n\n    public static final String SEPARATOR = \",\";\n\n    public static final String FORMULA_REGEX_STR = \"=|-|\\\\+|@\";\n\n    public static final String[] FORMULA_STR = { \"=\", \"-\", \"+\", \"@\" };\n\n    /**\n     * 用于dictType属性数据存储，避免重复查缓存\n     */\n    public Map<String, String> sysDictMap = new HashMap<String, String>();\n\n    /**\n     * 单元格样式缓存\n     */\n    private Map<String, CellStyle> cellStyleCache = new HashMap<String, CellStyle>();\n\n    /**\n     * Excel sheet最大行数，默认65536\n     */\n    public static final int sheetSize = 65536;\n\n    /**\n     * 工作表名称\n     */\n    private String sheetName;\n\n    /**\n     * 导出类型（EXPORT:导出数据；IMPORT：导入模板）\n     */\n    private Type type;\n\n    /**\n     * 工作薄对象\n     */\n    private Workbook wb;\n\n    /**\n     * 工作表对象\n     */\n    private Sheet sheet;\n\n    /**\n     * 样式列表\n     */\n    private Map<String, CellStyle> styles;\n\n    /**\n     * 导入导出数据列表\n     */\n    private List<T> list;\n\n    /**\n     * 注解列表\n     */\n    private List<Object[]> fields;\n\n    /**\n     * 当前行号\n     */\n    private int rownum;\n\n    /**\n     * 标题\n     */\n    private String title;\n\n    /**\n     * 最大高度\n     */\n    private short maxHeight;\n\n    /**\n     * 合并后最后行数\n     */\n    private int subMergedLastRowNum = 0;\n\n    /**\n     * 合并后开始行数\n     */\n    private int subMergedFirstRowNum = 1;\n\n    /**\n     * 对象的子列表方法\n     */\n    private Map<String, Method> subMethods;\n\n    /**\n     * 对象的子列表属性\n     */\n    private Map<String, List<Field>> subFieldsMap;\n\n    /**\n     * 统计列表\n     */\n    private Map<Integer, Double> statistics = new HashMap<Integer, Double>();\n\n    /**\n     * 实体对象\n     */\n    public Class<T> clazz;\n\n    /**\n     * 需要显示列属性\n     */\n    public String[] includeFields;\n\n    /**\n     * 需要排除列属性\n     */\n    public String[] excludeFields;\n\n    public ExcelUtil(Class<T> clazz)\n    {\n        this.clazz = clazz;\n    }\n\n    /**\n     * 仅在Excel中显示列属性\n     *\n     * @param fields 列属性名 示例[单个\"name\"/多个\"id\",\"name\"]\n     */\n    public void showColumn(String... fields)\n    {\n        this.includeFields = fields;\n    }\n\n    /**\n     * 隐藏Excel中列属性\n     *\n     * @param fields 列属性名 示例[单个\"name\"/多个\"id\",\"name\"]\n     */\n    public void hideColumn(String... fields)\n    {\n        this.excludeFields = fields;\n    }\n\n    public void init(List<T> list, String sheetName, String title, Type type)\n    {\n        if (list == null)\n        {\n            list = new ArrayList<T>();\n        }\n        this.list = list;\n        this.sheetName = sheetName;\n        this.type = type;\n        this.title = title;\n        createExcelField();\n        createWorkbook();\n        createTitle();\n        createSubHead();\n    }\n\n    /**\n     * 创建excel第一行标题\n     */\n    public void createTitle()\n    {\n        if (StringUtils.isNotEmpty(title))\n        {\n            int titleLastCol = this.fields.size() - 1;\n            if (isSubList())\n            {\n                for (List<Field> currentSubFields : subFieldsMap.values())\n                {\n                    titleLastCol = titleLastCol + currentSubFields.size() - 1;\n                }\n            }\n            Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);\n            titleRow.setHeightInPoints(30);\n            Cell titleCell = titleRow.createCell(0);\n            titleCell.setCellStyle(styles.get(\"title\"));\n            titleCell.setCellValue(title);\n            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));\n        }\n    }\n\n    /**\n     * 创建对象的子列表名称\n     */\n    public void createSubHead()\n    {\n        if (isSubList())\n        {\n            Row subRow = sheet.createRow(rownum);\n            int column = 0;\n            for (Object[] objects : fields)\n            {\n                Field field = (Field) objects[0];\n                Excel attr = (Excel) objects[1];\n                CellStyle cellStyle = styles.get(StringUtils.format(\"header_{}_{}\", attr.headerColor(), attr.headerBackgroundColor()));\n                if (Collection.class.isAssignableFrom(field.getType()))\n                {\n                    Cell cell = subRow.createCell(column);\n                    cell.setCellValue(attr.name());\n                    cell.setCellStyle(cellStyle);\n                    int subFieldSize = subFieldsMap != null ? subFieldsMap.get(field.getName()).size() : 0;\n                    if (subFieldSize > 1)\n                    {\n                        CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);\n                        sheet.addMergedRegion(cellAddress);\n                    }\n                    column += subFieldSize;\n                }\n                else\n                {\n                    Cell cell = subRow.createCell(column++);\n                    cell.setCellValue(attr.name());\n                    cell.setCellStyle(cellStyle);\n                }\n            }\n            rownum++;\n        }\n    }\n\n    /**\n     * 对excel表单默认第一个索引名转换成list\n     * \n     * @param is 输入流\n     * @return 转换后集合\n     */\n    public List<T> importExcel(InputStream is)\n    {\n        return importExcel(is, 0);\n    }\n\n    /**\n     * 对excel表单默认第一个索引名转换成list\n     * \n     * @param is 输入流\n     * @param titleNum 标题占用行数\n     * @return 转换后集合\n     */\n    public List<T> importExcel(InputStream is, int titleNum)\n    {\n        List<T> list = null;\n        try\n        {\n            list = importExcel(StringUtils.EMPTY, is, titleNum);\n        }\n        catch (Exception e)\n        {\n            log.error(\"导入Excel异常{}\", e.getMessage());\n            throw new UtilException(e.getMessage());\n        }\n        finally\n        {\n            IOUtils.closeQuietly(is);\n        }\n        return list;\n    }\n\n    /**\n     * 对excel表单指定表格索引名转换成list\n     * \n     * @param sheetName 表格索引名\n     * @param titleNum 标题占用行数\n     * @param is 输入流\n     * @return 转换后集合\n     */\n    public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception\n    {\n        this.type = Type.IMPORT;\n        this.wb = WorkbookFactory.create(is);\n        List<T> list = new ArrayList<T>();\n        // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet\n        Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);\n        if (sheet == null)\n        {\n            throw new IOException(\"文件sheet不存在\");\n        }\n        boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);\n        Map<String, List<PictureData>> pictures = null;\n        if (isXSSFWorkbook)\n        {\n            pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);\n        }\n        else\n        {\n            pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);\n        }\n        // 获取最后一个非空行的行下标，比如总行数为n，则返回的为n-1\n        int rows = sheet.getLastRowNum();\n        if (rows > 0)\n        {\n            // 定义一个map用于存放excel列的序号和field.\n            Map<String, Integer> cellMap = new HashMap<String, Integer>();\n            // 获取表头\n            Row heard = sheet.getRow(titleNum);\n            if (heard == null)\n            {\n                throw new UtilException(\"文件标题行为空，请检查Excel文件格式\");\n            }\n            for (int i = 0; i < heard.getLastCellNum(); i++)\n            {\n                Cell cell = heard.getCell(i);\n                if (StringUtils.isNotNull(cell))\n                {\n                    String value = this.getCellValue(heard, i).toString();\n                    cellMap.put(value, i);\n                }\n            }\n            // 有数据时才处理 得到类的所有field.\n            List<Object[]> fields = this.getFields();\n            Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();\n            for (Object[] objects : fields)\n            {\n                Excel attr = (Excel) objects[1];\n                Integer column = cellMap.get(attr.name());\n                if (column != null)\n                {\n                    fieldsMap.put(column, objects);\n                }\n            }\n            for (int i = titleNum + 1; i <= rows; i++)\n            {\n                // 从第2行开始取数据,默认第一行是表头.\n                Row row = sheet.getRow(i);\n                // 判断当前行是否是空行\n                if (isRowEmpty(row))\n                {\n                    continue;\n                }\n                T entity = null;\n                for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())\n                {\n                    Object val = this.getCellValue(row, entry.getKey());\n\n                    // 如果不存在实例则新建.\n                    entity = (entity == null ? clazz.getDeclaredConstructor().newInstance() : entity);\n                    // 从map中得到对应列的field.\n                    Field field = (Field) entry.getValue()[0];\n                    Excel attr = (Excel) entry.getValue()[1];\n                    // 取得类型,并根据对象类型设置值.\n                    Class<?> fieldType = field.getType();\n                    if (String.class == fieldType)\n                    {\n                        String s = Convert.toStr(val);\n                        if (s.matches(\"^\\\\d+\\\\.0$\"))\n                        {\n                            val = StringUtils.substringBefore(s, \".0\");\n                        }\n                        else\n                        {\n                            String dateFormat = field.getAnnotation(Excel.class).dateFormat();\n                            if (StringUtils.isNotEmpty(dateFormat))\n                            {\n                                val = parseDateToStr(dateFormat, val);\n                            }\n                            else\n                            {\n                                val = Convert.toStr(val);\n                            }\n                        }\n                    }\n                    else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))\n                    {\n                        val = Convert.toInt(val);\n                    }\n                    else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))\n                    {\n                        val = Convert.toLong(val);\n                    }\n                    else if (Double.TYPE == fieldType || Double.class == fieldType)\n                    {\n                        val = Convert.toDouble(val);\n                    }\n                    else if (Float.TYPE == fieldType || Float.class == fieldType)\n                    {\n                        val = Convert.toFloat(val);\n                    }\n                    else if (BigDecimal.class == fieldType)\n                    {\n                        val = Convert.toBigDecimal(val);\n                    }\n                    else if (Date.class == fieldType)\n                    {\n                        if (val instanceof String)\n                        {\n                            val = DateUtils.parseDate(val);\n                        }\n                        else if (val instanceof Double)\n                        {\n                            val = DateUtil.getJavaDate((Double) val);\n                        }\n                    }\n                    else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)\n                    {\n                        val = Convert.toBool(val, false);\n                    }\n                    if (StringUtils.isNotNull(fieldType))\n                    {\n                        String propertyName = field.getName();\n                        if (StringUtils.isNotEmpty(attr.targetAttr()))\n                        {\n                            propertyName = field.getName() + \".\" + attr.targetAttr();\n                        }\n                        if (StringUtils.isNotEmpty(attr.readConverterExp()))\n                        {\n                            val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());\n                        }\n                        else if (StringUtils.isNotEmpty(attr.dictType()))\n                        {\n                            if (!sysDictMap.containsKey(attr.dictType() + val))\n                            {\n                                String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());\n                                sysDictMap.put(attr.dictType() + val, dictValue);\n                            }\n                            val = sysDictMap.get(attr.dictType() + val);\n                        }\n                        else if (!attr.handler().equals(ExcelHandlerAdapter.class))\n                        {\n                            val = dataFormatHandlerAdapter(val, attr, null);\n                        }\n                        else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))\n                        {\n                            StringBuilder propertyString = new StringBuilder();\n                            List<PictureData> images = pictures.get(row.getRowNum() + \"_\" + entry.getKey());\n                            for (PictureData picture : images)\n                            {\n                                byte[] data = picture.getData();\n                                String fileName = FileUtils.writeImportBytes(data);\n                                propertyString.append(fileName).append(SEPARATOR);\n                            }\n                            val = StringUtils.stripEnd(propertyString.toString(), SEPARATOR);\n                        }\n                        ReflectUtils.invokeSetter(entity, propertyName, val);\n                    }\n                }\n                list.add(entity);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param list 导出数据集合\n     * @param sheetName 工作表的名称\n     * @return 结果\n     */\n    public AjaxResult exportExcel(List<T> list, String sheetName)\n    {\n        return exportExcel(list, sheetName, StringUtils.EMPTY);\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param list 导出数据集合\n     * @param sheetName 工作表的名称\n     * @param title 标题\n     * @return 结果\n     */\n    public AjaxResult exportExcel(List<T> list, String sheetName, String title)\n    {\n        this.init(list, sheetName, title, Type.EXPORT);\n        return exportExcel();\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param response 返回数据\n     * @param list 导出数据集合\n     * @param sheetName 工作表的名称\n     * @return 结果\n     */\n    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)\n    {\n        exportExcel(response, list, sheetName, StringUtils.EMPTY);\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param response 返回数据\n     * @param list 导出数据集合\n     * @param sheetName 工作表的名称\n     * @param title 标题\n     * @return 结果\n     */\n    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)\n    {\n        response.setContentType(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\");\n        response.setCharacterEncoding(\"utf-8\");\n        this.init(list, sheetName, title, Type.EXPORT);\n        exportExcel(response);\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param sheetName 工作表的名称\n     * @return 结果\n     */\n    public AjaxResult importTemplateExcel(String sheetName)\n    {\n        return importTemplateExcel(sheetName, StringUtils.EMPTY);\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param sheetName 工作表的名称\n     * @param title 标题\n     * @return 结果\n     */\n    public AjaxResult importTemplateExcel(String sheetName, String title)\n    {\n        this.init(null, sheetName, title, Type.IMPORT);\n        return exportExcel();\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param sheetName 工作表的名称\n     * @return 结果\n     */\n    public void importTemplateExcel(HttpServletResponse response, String sheetName)\n    {\n        importTemplateExcel(response, sheetName, StringUtils.EMPTY);\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @param sheetName 工作表的名称\n     * @param title 标题\n     * @return 结果\n     */\n    public void importTemplateExcel(HttpServletResponse response, String sheetName, String title)\n    {\n        response.setContentType(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\");\n        response.setCharacterEncoding(\"utf-8\");\n        this.init(null, sheetName, title, Type.IMPORT);\n        exportExcel(response);\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @return 结果\n     */\n    public void exportExcel(HttpServletResponse response)\n    {\n        try\n        {\n            writeSheet();\n            wb.write(response.getOutputStream());\n        }\n        catch (Exception e)\n        {\n            log.error(\"导出Excel异常{}\", e.getMessage());\n        }\n        finally\n        {\n            IOUtils.closeQuietly(wb);\n        }\n    }\n\n    /**\n     * 对list数据源将其里面的数据导入到excel表单\n     * \n     * @return 结果\n     */\n    public AjaxResult exportExcel()\n    {\n        OutputStream out = null;\n        try\n        {\n            writeSheet();\n            String filename = encodingFilename(sheetName);\n            out = new FileOutputStream(getAbsoluteFile(filename));\n            wb.write(out);\n            return AjaxResult.success(filename);\n        }\n        catch (Exception e)\n        {\n            log.error(\"导出Excel异常{}\", e.getMessage());\n            throw new UtilException(\"导出Excel失败，请联系网站管理员！\");\n        }\n        finally\n        {\n            IOUtils.closeQuietly(wb);\n            IOUtils.closeQuietly(out);\n        }\n    }\n\n    /**\n     * 创建写入数据到Sheet\n     */\n    public void writeSheet()\n    {\n        // 取出一共有多少个sheet.\n        int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));\n        for (int index = 0; index < sheetNo; index++)\n        {\n            createSheet(sheetNo, index);\n\n            // 产生一行\n            Row row = sheet.createRow(rownum);\n            int column = 0;\n            // 写入各个字段的列头名称\n            for (Object[] os : fields)\n            {\n                Field field = (Field) os[0];\n                Excel excel = (Excel) os[1];\n                if (Collection.class.isAssignableFrom(field.getType()))\n                {\n                    List<Field> currentSubFields = subFieldsMap.get(field.getName());\n                    for (Field subField : currentSubFields)\n                    {\n                        Excel subExcel = subField.getAnnotation(Excel.class);\n                        this.createHeadCell(subExcel, row, column++);\n                    }\n                }\n                else\n                {\n                    this.createHeadCell(excel, row, column++);\n                }\n            }\n            if (Type.EXPORT.equals(type))\n            {\n                fillExcelData(index);\n                addStatisticsRow();\n            }\n        }\n    }\n\n    /**\n     * 填充excel数据\n     * \n     * @param index 序号\n     */\n    @SuppressWarnings(\"unchecked\")\n    public void fillExcelData(int index)\n    {\n        int startNo = index * sheetSize;\n        int endNo = Math.min(startNo + sheetSize, list.size());\n        int currentRowNum = rownum + 1; // 从标题行后开始\n\n        for (int i = startNo; i < endNo; i++)\n        {\n            Row row = sheet.createRow(currentRowNum);\n            T vo = (T) list.get(i);\n            int column = 0;\n            int maxSubListSize = getCurrentMaxSubListSize(vo);\n            for (Object[] os : fields)\n            {\n                Field field = (Field) os[0];\n                Excel excel = (Excel) os[1];\n                if (Collection.class.isAssignableFrom(field.getType()))\n                {\n                    try\n                    {\n                        Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);\n                        List<Field> currentSubFields = subFieldsMap.get(field.getName());\n                        if (subList != null && !subList.isEmpty())\n                        {\n                            int subIndex = 0;\n                            for (Object subVo : subList)\n                            {\n                                Row subRow = sheet.getRow(currentRowNum + subIndex);\n                                if (subRow == null)\n                                {\n                                    subRow = sheet.createRow(currentRowNum + subIndex);\n                                }\n\n                                int subColumn = column;\n                                for (Field subField : currentSubFields)\n                                {\n                                    Excel subExcel = subField.getAnnotation(Excel.class);\n                                    addCell(subExcel, subRow, (T) subVo, subField, subColumn++);\n                                }\n                                subIndex++;\n                            }\n                        }\n                        column += currentSubFields.size();\n                    }\n                    catch (Exception e)\n                    {\n                        log.error(\"填充集合数据失败\", e);\n                    }\n                }\n                else\n                {\n                    // 创建单元格并设置值\n                    addCell(excel, row, vo, field, column);\n                    if (maxSubListSize > 1 && excel.needMerge())\n                    {\n                        sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));\n                    }\n                    column++;\n                }\n            }\n            currentRowNum += maxSubListSize;\n        }\n    }\n\n    /**\n     * 获取子列表最大数\n     */\n    private int getCurrentMaxSubListSize(T vo)\n    {\n        int maxSubListSize = 1;\n        for (Object[] os : fields)\n        {\n            Field field = (Field) os[0];\n            if (Collection.class.isAssignableFrom(field.getType()))\n            {\n                try\n                {\n                    Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);\n                    if (subList != null && !subList.isEmpty())\n                    {\n                        maxSubListSize = Math.max(maxSubListSize, subList.size());\n                    }\n                }\n                catch (Exception e)\n                {\n                    log.error(\"获取集合大小失败\", e);\n                }\n            }\n        }\n        return maxSubListSize;\n    }\n\n    /**\n     * 创建表格样式\n     * \n     * @param wb 工作薄对象\n     * @return 样式列表\n     */\n    private Map<String, CellStyle> createStyles(Workbook wb)\n    {\n        // 写入各条记录,每条记录对应excel表中的一行\n        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();\n        CellStyle style = wb.createCellStyle();\n        style.setAlignment(HorizontalAlignment.CENTER);\n        style.setVerticalAlignment(VerticalAlignment.CENTER);\n        Font titleFont = wb.createFont();\n        titleFont.setFontName(\"Arial\");\n        titleFont.setFontHeightInPoints((short) 16);\n        titleFont.setBold(true);\n        style.setFont(titleFont);\n        DataFormat dataFormat = wb.createDataFormat();\n        style.setDataFormat(dataFormat.getFormat(\"@\"));\n        styles.put(\"title\", style);\n\n        style = wb.createCellStyle();\n        style.setAlignment(HorizontalAlignment.CENTER);\n        style.setVerticalAlignment(VerticalAlignment.CENTER);\n        style.setBorderRight(BorderStyle.THIN);\n        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n        style.setBorderLeft(BorderStyle.THIN);\n        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n        style.setBorderTop(BorderStyle.THIN);\n        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n        style.setBorderBottom(BorderStyle.THIN);\n        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n        Font dataFont = wb.createFont();\n        dataFont.setFontName(\"Arial\");\n        dataFont.setFontHeightInPoints((short) 10);\n        style.setFont(dataFont);\n        styles.put(\"data\", style);\n\n        style = wb.createCellStyle();\n        style.setAlignment(HorizontalAlignment.CENTER);\n        style.setVerticalAlignment(VerticalAlignment.CENTER);\n        style.setDataFormat(dataFormat.getFormat(\"######0.00\"));\n        Font totalFont = wb.createFont();\n        totalFont.setFontName(\"Arial\");\n        totalFont.setFontHeightInPoints((short) 10);\n        style.setFont(totalFont);\n        styles.put(\"total\", style);\n\n        styles.putAll(annotationHeaderStyles(wb, styles));\n\n        styles.putAll(annotationDataStyles(wb));\n\n        return styles;\n    }\n\n    /**\n     * 根据Excel注解创建表格头样式\n     * \n     * @param wb 工作薄对象\n     * @return 自定义样式列表\n     */\n    private Map<String, CellStyle> annotationHeaderStyles(Workbook wb, Map<String, CellStyle> styles)\n    {\n        Map<String, CellStyle> headerStyles = new HashMap<String, CellStyle>();\n        for (Object[] os : fields)\n        {\n            Excel excel = (Excel) os[1];\n            String key = StringUtils.format(\"header_{}_{}\", excel.headerColor(), excel.headerBackgroundColor());\n            if (!headerStyles.containsKey(key))\n            {\n                CellStyle style = wb.createCellStyle();\n                style.cloneStyleFrom(styles.get(\"data\"));\n                style.setAlignment(HorizontalAlignment.CENTER);\n                style.setVerticalAlignment(VerticalAlignment.CENTER);\n                style.setFillForegroundColor(excel.headerBackgroundColor().index);\n                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);\n                Font headerFont = wb.createFont();\n                headerFont.setFontName(\"Arial\");\n                headerFont.setFontHeightInPoints((short) 10);\n                headerFont.setBold(true);\n                headerFont.setColor(excel.headerColor().index);\n                style.setFont(headerFont);\n                // 设置表格头单元格文本形式\n                DataFormat dataFormat = wb.createDataFormat();\n                style.setDataFormat(dataFormat.getFormat(\"@\"));\n                headerStyles.put(key, style);\n            }\n        }\n        return headerStyles;\n    }\n\n    /**\n     * 根据Excel注解创建表格列样式\n     * \n     * @param wb 工作薄对象\n     * @return 自定义样式列表\n     */\n    private Map<String, CellStyle> annotationDataStyles(Workbook wb)\n    {\n        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();\n        for (Object[] os : fields)\n        {\n            Field field = (Field) os[0];\n            Excel excel = (Excel) os[1];\n            if (Collection.class.isAssignableFrom(field.getType()))\n            {\n                ParameterizedType pt = (ParameterizedType) field.getGenericType();\n                Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];\n                List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);\n                for (Field subField : subFields)\n                {\n                    Excel subExcel = subField.getAnnotation(Excel.class);\n                    annotationDataStyles(styles, subField, subExcel);\n                }\n            }\n            else\n            {\n                annotationDataStyles(styles, field, excel);\n            }\n        }\n        return styles;\n    }\n\n    /**\n     * 根据Excel注解创建表格列样式\n     * \n     * @param styles 自定义样式列表\n     * @param field  属性列信息\n     * @param excel  注解信息\n     */\n    public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)\n    {\n        String key = StringUtils.format(\"data_{}_{}_{}_{}_{}\", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());\n        if (!styles.containsKey(key))\n        {\n            CellStyle style = wb.createCellStyle();\n            style.setAlignment(excel.align());\n            style.setVerticalAlignment(VerticalAlignment.CENTER);\n            style.setBorderRight(BorderStyle.THIN);\n            style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n            style.setBorderLeft(BorderStyle.THIN);\n            style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n            style.setBorderTop(BorderStyle.THIN);\n            style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n            style.setBorderBottom(BorderStyle.THIN);\n            style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);\n            style.setFillForegroundColor(excel.backgroundColor().getIndex());\n            style.setWrapText(excel.wrapText());\n            Font dataFont = wb.createFont();\n            dataFont.setFontName(\"Arial\");\n            dataFont.setFontHeightInPoints((short) 10);\n            dataFont.setColor(excel.color().index);\n            style.setFont(dataFont);\n            if (ColumnType.TEXT == excel.cellType())\n            {\n                DataFormat dataFormat = wb.createDataFormat();\n                style.setDataFormat(dataFormat.getFormat(\"@\"));\n            }\n            styles.put(key, style);\n        }\n    }\n\n    /**\n     * 创建单元格\n     */\n    public Cell createHeadCell(Excel attr, Row row, int column)\n    {\n        // 创建列\n        Cell cell = row.createCell(column);\n        // 写入列信息\n        cell.setCellValue(attr.name());\n        setDataValidation(attr, row, column);\n        cell.setCellStyle(styles.get(StringUtils.format(\"header_{}_{}\", attr.headerColor(), attr.headerBackgroundColor())));\n        if (isSubList())\n        {\n            // 填充默认样式，防止合并单元格样式失效\n            sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format(\"data_{}_{}_{}_{}_{}\", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));\n            if (attr.needMerge())\n            {\n                sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));\n            }\n        }\n        return cell;\n    }\n\n    /**\n     * 设置单元格信息\n     * \n     * @param value 单元格值\n     * @param attr 注解相关\n     * @param cell 单元格信息\n     */\n    public void setCellVo(Object value, Excel attr, Cell cell)\n    {\n        if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType())\n        {\n            String cellValue = Convert.toStr(value);\n            // 对于任何以表达式触发字符 =-+@开头的单元格，直接使用tab字符作为前缀，防止CSV注入。\n            if (StringUtils.startsWithAny(cellValue, FORMULA_STR))\n            {\n                cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, \"\\t$0\");\n            }\n            if (value instanceof Collection && StringUtils.equals(\"[]\", cellValue))\n            {\n                cellValue = StringUtils.EMPTY;\n            }\n            cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix());\n        }\n        else if (ColumnType.NUMERIC == attr.cellType())\n        {\n            if (StringUtils.isNotNull(value))\n            {\n                cell.setCellValue(StringUtils.contains(Convert.toStr(value), \".\") ? Convert.toDouble(value) : Convert.toInt(value));\n            }\n        }\n        else if (ColumnType.IMAGE == attr.cellType())\n        {\n            ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);\n            String propertyValue = Convert.toStr(value);\n            if (StringUtils.isNotEmpty(propertyValue))\n            {\n                List<String> imagePaths = StringUtils.str2List(propertyValue, SEPARATOR);\n                for (String imagePath : imagePaths)\n                {\n                    byte[] data = ImageUtils.getImage(imagePath);\n                    getDrawingPatriarch(cell.getSheet()).createPicture(anchor, cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));\n                }\n            }\n        }\n    }\n\n    /**\n     * 获取画布\n     */\n    public static Drawing<?> getDrawingPatriarch(Sheet sheet)\n    {\n        if (sheet.getDrawingPatriarch() == null)\n        {\n            sheet.createDrawingPatriarch();\n        }\n        return sheet.getDrawingPatriarch();\n    }\n\n    /**\n     * 获取图片类型,设置图片插入类型\n     */\n    public int getImageType(byte[] value)\n    {\n        String type = FileTypeUtils.getFileExtendName(value);\n        if (\"JPG\".equalsIgnoreCase(type))\n        {\n            return Workbook.PICTURE_TYPE_JPEG;\n        }\n        else if (\"PNG\".equalsIgnoreCase(type))\n        {\n            return Workbook.PICTURE_TYPE_PNG;\n        }\n        return Workbook.PICTURE_TYPE_JPEG;\n    }\n\n    /**\n     * 创建表格样式\n     */\n    public void setDataValidation(Excel attr, Row row, int column)\n    {\n        if (attr.name().indexOf(\"注：\") >= 0)\n        {\n            sheet.setColumnWidth(column, 6000);\n        }\n        else\n        {\n            // 设置列宽\n            sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));\n        }\n        if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict())\n        {\n            String[] comboArray = attr.combo();\n            if (attr.comboReadDict())\n            {\n                if (!sysDictMap.containsKey(\"combo_\" + attr.dictType()))\n                {\n                    String labels = DictUtils.getDictLabels(attr.dictType());\n                    sysDictMap.put(\"combo_\" + attr.dictType(), labels);\n                }\n                String val = sysDictMap.get(\"combo_\" + attr.dictType());\n                comboArray = StringUtils.split(val, DictUtils.SEPARATOR);\n            }\n            if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255)\n            {\n                // 如果下拉数大于15或字符串长度大于255，则使用一个新sheet存储，避免生成的模板下拉值获取不到\n                setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column);\n            }\n            else\n            {\n                // 提示信息或只能选择不能输入的列内容.\n                setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column);\n            }\n        }\n    }\n\n    /**\n     * 添加单元格\n     */\n    @SuppressWarnings(\"deprecation\")\n    public Cell addCell(Excel attr, Row row, T vo, Field field, int column)\n    {\n        Cell cell = null;\n        try\n        {\n            // 设置行高\n            row.setHeight(maxHeight);\n            // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.\n            if (attr.isExport())\n            {\n                // 创建cell\n                cell = row.createCell(column);\n                if (isSubListValue(vo) && getListCellValue(vo) > 1 && attr.needMerge())\n                {\n                    if (subMergedLastRowNum >= subMergedFirstRowNum)\n                    {\n                        sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));\n                    }\n                }\n                cell.setCellStyle(styles.get(StringUtils.format(\"data_{}_{}_{}_{}_{}\", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));\n\n                // 用于读取对象中的属性\n                Object value = getTargetValue(vo, field, attr);\n                String dateFormat = attr.dateFormat();\n                String readConverterExp = attr.readConverterExp();\n                String separator = attr.separator();\n                String dictType = attr.dictType();\n                if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))\n                {\n                    cell.setCellStyle(createCellStyle(cell.getCellStyle(), dateFormat));\n                    cell.setCellValue(parseDateToStr(dateFormat, value));\n                }\n                else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))\n                {\n                    cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));\n                }\n                else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))\n                {\n                    if (!sysDictMap.containsKey(dictType + value))\n                    {\n                        String lable = convertDictByExp(Convert.toStr(value), dictType, separator);\n                        sysDictMap.put(dictType + value, lable);\n                    }\n                    cell.setCellValue(sysDictMap.get(dictType + value));\n                }\n                else if (value instanceof BigDecimal && -1 != attr.scale())\n                {\n                    cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue());\n                }\n                else if (!attr.handler().equals(ExcelHandlerAdapter.class))\n                {\n                    cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));\n                }\n                else\n                {\n                    // 设置列类型\n                    setCellVo(value, attr, cell);\n                }\n                addStatisticsData(column, Convert.toStr(value), attr);\n            }\n        }\n        catch (Exception e)\n        {\n            log.error(\"导出Excel失败{}\", e);\n        }\n        return cell;\n    }\n\n    /**\n     * 使用自定义格式，同时避免样式污染\n     * \n     * @param cellStyle 从此样式复制\n     * @param format 格式匹配的字符串\n     * @return 格式化后CellStyle对象\n     */\n    private CellStyle createCellStyle(CellStyle cellStyle, String format)\n    {\n        String key = cellStyle.getIndex() + \"|\" + format;\n        CellStyle cached = cellStyleCache.get(key);\n        if (cached != null)\n        {\n            return cached;\n        }\n        CellStyle style = wb.createCellStyle();\n        style.cloneStyleFrom(cellStyle);\n        style.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat(format));\n        cellStyleCache.put(key, style);\n        return style;\n    }\n\n    /**\n     * 设置 POI XSSFSheet 单元格提示或选择框\n     * \n     * @param sheet 表单\n     * @param textlist 下拉框显示的内容\n     * @param promptContent 提示内容\n     * @param firstRow 开始行\n     * @param endRow 结束行\n     * @param firstCol 开始列\n     * @param endCol 结束列\n     */\n    public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow,\n            int firstCol, int endCol)\n    {\n        DataValidationHelper helper = sheet.getDataValidationHelper();\n        DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint(\"DD1\");\n        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);\n        DataValidation dataValidation = helper.createValidation(constraint, regions);\n        if (StringUtils.isNotEmpty(promptContent))\n        {\n            // 如果设置了提示信息则鼠标放上去提示\n            dataValidation.createPromptBox(\"\", promptContent);\n            dataValidation.setShowPromptBox(true);\n        }\n        // 处理Excel兼容性问题\n        if (dataValidation instanceof XSSFDataValidation)\n        {\n            dataValidation.setSuppressDropDownArrow(true);\n            dataValidation.setShowErrorBox(true);\n        }\n        else\n        {\n            dataValidation.setSuppressDropDownArrow(false);\n        }\n        sheet.addValidationData(dataValidation);\n    }\n\n    /**\n     * 设置某些列的值只能输入预制的数据,显示下拉框（兼容超出一定数量的下拉框）.\n     * \n     * @param sheet 要设置的sheet.\n     * @param textlist 下拉框显示的内容\n     * @param promptContent 提示内容\n     * @param firstRow 开始行\n     * @param endRow 结束行\n     * @param firstCol 开始列\n     * @param endCol 结束列\n     */\n    public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol)\n    {\n        String hideSheetName = \"combo_\" + firstCol + \"_\" + endCol;\n        Sheet hideSheet = null;\n        String hideSheetDataName = hideSheetName + \"_data\";\n        Name name = wb.getName(hideSheetDataName);\n        if (name != null)\n        {\n            // 名称已存在，尝试从名称的引用中找到sheet名称\n            String refersToFormula = name.getRefersToFormula();\n            if (StringUtils.isNotEmpty(refersToFormula) && refersToFormula.contains(\"!\"))\n            {\n                String sheetNameFromFormula = refersToFormula.substring(0, refersToFormula.indexOf(\"!\"));\n                hideSheet = wb.getSheet(sheetNameFromFormula);\n            }\n        }\n\n        if (hideSheet == null)\n        {\n            hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据\n            for (int i = 0; i < textlist.length; i++)\n            {\n                hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]);\n            }\n            // 创建名称，可被其他单元格引用\n            name = wb.createName();\n            name.setNameName(hideSheetDataName);\n            name.setRefersToFormula(hideSheetName + \"!$A$1:$A$\" + textlist.length);\n        }\n\n        DataValidationHelper helper = sheet.getDataValidationHelper();\n        // 加载下拉列表内容\n        DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetDataName);\n        // 设置数据有效性加载在哪个单元格上,四个参数分别是：起始行、终止行、起始列、终止列\n        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);\n        // 数据有效性对象\n        DataValidation dataValidation = helper.createValidation(constraint, regions);\n        if (StringUtils.isNotEmpty(promptContent))\n        {\n            // 如果设置了提示信息则鼠标放上去提示\n            dataValidation.createPromptBox(\"\", promptContent);\n            dataValidation.setShowPromptBox(true);\n        }\n        // 处理Excel兼容性问题\n        if (dataValidation instanceof XSSFDataValidation)\n        {\n            dataValidation.setSuppressDropDownArrow(true);\n            dataValidation.setShowErrorBox(true);\n        }\n        else\n        {\n            dataValidation.setSuppressDropDownArrow(false);\n        }\n\n        sheet.addValidationData(dataValidation);\n        // 设置hiddenSheet隐藏\n        wb.setSheetHidden(wb.getSheetIndex(hideSheet), true);\n    }\n\n    /**\n     * 解析导出值 0=男,1=女,2=未知\n     * \n     * @param propertyValue 参数值\n     * @param converterExp 翻译注解\n     * @param separator 分隔符\n     * @return 解析后值\n     */\n    public static String convertByExp(String propertyValue, String converterExp, String separator)\n    {\n        StringBuilder propertyString = new StringBuilder();\n        String[] convertSource = converterExp.split(SEPARATOR);\n        for (String item : convertSource)\n        {\n            String[] itemArray = item.split(\"=\");\n            if (StringUtils.containsAny(propertyValue, separator))\n            {\n                for (String value : propertyValue.split(separator))\n                {\n                    if (itemArray[0].equals(value))\n                    {\n                        propertyString.append(itemArray[1] + separator);\n                        break;\n                    }\n                }\n            }\n            else\n            {\n                if (itemArray[0].equals(propertyValue))\n                {\n                    return itemArray[1];\n                }\n            }\n        }\n        return StringUtils.stripEnd(propertyString.toString(), separator);\n    }\n\n    /**\n     * 反向解析值 男=0,女=1,未知=2\n     * \n     * @param propertyValue 参数值\n     * @param converterExp 翻译注解\n     * @param separator 分隔符\n     * @return 解析后值\n     */\n    public static String reverseByExp(String propertyValue, String converterExp, String separator)\n    {\n        StringBuilder propertyString = new StringBuilder();\n        String[] convertSource = converterExp.split(SEPARATOR);\n        for (String item : convertSource)\n        {\n            String[] itemArray = item.split(\"=\");\n            if (StringUtils.containsAny(propertyValue, separator))\n            {\n                for (String value : propertyValue.split(separator))\n                {\n                    if (itemArray[1].equals(value))\n                    {\n                        propertyString.append(itemArray[0] + separator);\n                        break;\n                    }\n                }\n            }\n            else\n            {\n                if (itemArray[1].equals(propertyValue))\n                {\n                    return itemArray[0];\n                }\n            }\n        }\n        return StringUtils.stripEnd(propertyString.toString(), separator);\n    }\n\n    /**\n     * 解析字典值\n     * \n     * @param dictValue 字典值\n     * @param dictType 字典类型\n     * @param separator 分隔符\n     * @return 字典标签\n     */\n    public static String convertDictByExp(String dictValue, String dictType, String separator)\n    {\n        return DictUtils.getDictLabel(dictType, dictValue, separator);\n    }\n\n    /**\n     * 反向解析值字典值\n     * \n     * @param dictLabel 字典标签\n     * @param dictType 字典类型\n     * @param separator 分隔符\n     * @return 字典值\n     */\n    public static String reverseDictByExp(String dictLabel, String dictType, String separator)\n    {\n        return DictUtils.getDictValue(dictType, dictLabel, separator);\n    }\n\n    /**\n     * 数据处理器\n     * \n     * @param value 数据值\n     * @param excel 数据注解\n     * @return\n     */\n    public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell)\n    {\n        try\n        {\n            Object instance = excel.handler().getDeclaredConstructor().newInstance();\n            Method formatMethod = excel.handler().getMethod(\"format\", new Class[] { Object.class, String[].class, Cell.class, Workbook.class });\n            value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb);\n        }\n        catch (Exception e)\n        {\n            log.error(\"不能格式化数据 \" + excel.handler(), e.getMessage());\n        }\n        return Convert.toStr(value);\n    }\n\n    /**\n     * 合计统计信息\n     */\n    private void addStatisticsData(Integer index, String text, Excel entity)\n    {\n        if (entity != null && entity.isStatistics())\n        {\n            Double temp = 0D;\n            if (!statistics.containsKey(index))\n            {\n                statistics.put(index, temp);\n            }\n            try\n            {\n                temp = Double.valueOf(text);\n            }\n            catch (NumberFormatException e)\n            {\n            }\n            statistics.put(index, statistics.get(index) + temp);\n        }\n    }\n\n    /**\n     * 创建统计行\n     */\n    public void addStatisticsRow()\n    {\n        if (statistics.size() > 0)\n        {\n            Row row = sheet.createRow(sheet.getLastRowNum() + 1);\n            Set<Integer> keys = statistics.keySet();\n            Cell cell = row.createCell(0);\n            cell.setCellStyle(styles.get(\"total\"));\n            cell.setCellValue(\"合计\");\n\n            for (Integer key : keys)\n            {\n                cell = row.createCell(key);\n                cell.setCellStyle(styles.get(\"total\"));\n                cell.setCellValue(statistics.get(key));\n            }\n            statistics.clear();\n        }\n    }\n\n    /**\n     * 编码文件名\n     */\n    public String encodingFilename(String filename)\n    {\n        return UUID.randomUUID() + \"_\" + filename + \".xlsx\";\n    }\n\n    /**\n     * 获取下载路径\n     * \n     * @param filename 文件名称\n     */\n    public String getAbsoluteFile(String filename)\n    {\n        String downloadPath = RuoYiConfig.getDownloadPath() + filename;\n        File desc = new File(downloadPath);\n        if (!desc.getParentFile().exists())\n        {\n            desc.getParentFile().mkdirs();\n        }\n        return downloadPath;\n    }\n\n    /**\n     * 获取bean中的属性值\n     * \n     * @param vo 实体对象\n     * @param field 字段\n     * @param excel 注解\n     * @return 最终的属性值\n     * @throws Exception\n     */\n    private Object getTargetValue(T vo, Field field, Excel excel) throws Exception\n    {\n        field.setAccessible(true);\n        Object o = field.get(vo);\n        if (StringUtils.isNotEmpty(excel.targetAttr()))\n        {\n            String target = excel.targetAttr();\n            if (target.contains(\".\"))\n            {\n                String[] targets = target.split(\"[.]\");\n                for (String name : targets)\n                {\n                    o = getValue(o, name);\n                }\n            }\n            else\n            {\n                o = getValue(o, target);\n            }\n        }\n        return o;\n    }\n\n    /**\n     * 以类的属性的get方法方法形式获取值\n     * \n     * @param o\n     * @param name\n     * @return value\n     * @throws Exception\n     */\n    private Object getValue(Object o, String name) throws Exception\n    {\n        if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name))\n        {\n            Class<?> clazz = o.getClass();\n            Field field = clazz.getDeclaredField(name);\n            field.setAccessible(true);\n            o = field.get(o);\n        }\n        return o;\n    }\n\n    /**\n     * 得到所有定义字段\n     */\n    private void createExcelField()\n    {\n        this.fields = getFields();\n        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());\n        this.maxHeight = getRowHeight();\n    }\n\n    /**\n     * 获取字段注解信息\n     */\n    public List<Object[]> getFields()\n    {\n        List<Object[]> fields = new ArrayList<Object[]>();\n        List<Field> tempFields = new ArrayList<>();\n        subFieldsMap = new HashMap<>();\n        subMethods = new HashMap<>();\n        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));\n        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));\n        if (StringUtils.isNotEmpty(includeFields))\n        {\n            for (Field field : tempFields)\n            {\n                if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))\n                {\n                    addField(fields, field);\n                }\n            }\n        }\n        else if (StringUtils.isNotEmpty(excludeFields))\n        {\n            for (Field field : tempFields)\n            {\n                if (!ArrayUtils.contains(this.excludeFields, field.getName()))\n                {\n                    addField(fields, field);\n                }\n            }\n        }\n        else\n        {\n            for (Field field : tempFields)\n            {\n                addField(fields, field);\n            }\n        }\n        return fields;\n    }\n\n    /**\n     * 添加字段信息\n     */\n    public void addField(List<Object[]> fields, Field field)\n    {\n        // 单注解\n        if (field.isAnnotationPresent(Excel.class))\n        {\n            Excel attr = field.getAnnotation(Excel.class);\n            if (attr != null && (attr.type() == Type.ALL || attr.type() == type))\n            {\n                fields.add(new Object[] { field, attr });\n            }\n            if (Collection.class.isAssignableFrom(field.getType()))\n            {\n                String fieldName = field.getName();\n                subMethods.put(fieldName, getSubMethod(fieldName, clazz));\n                ParameterizedType pt = (ParameterizedType) field.getGenericType();\n                Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];\n                subFieldsMap.put(fieldName, FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class));\n            }\n        }\n\n        // 多注解\n        if (field.isAnnotationPresent(Excels.class))\n        {\n            Excels attrs = field.getAnnotation(Excels.class);\n            Excel[] excels = attrs.value();\n            for (Excel attr : excels)\n            {\n                if (StringUtils.isNotEmpty(includeFields))\n                {\n                    if (ArrayUtils.contains(this.includeFields, field.getName() + \".\" + attr.targetAttr())\n                            && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))\n                    {\n                        fields.add(new Object[] { field, attr });\n                    }\n                }\n                else\n                {\n                    if (!ArrayUtils.contains(this.excludeFields, field.getName() + \".\" + attr.targetAttr())\n                            && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))\n                    {\n                        fields.add(new Object[] { field, attr });\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 根据注解获取最大行高\n     */\n    public short getRowHeight()\n    {\n        double maxHeight = 0;\n        for (Object[] os : this.fields)\n        {\n            Excel excel = (Excel) os[1];\n            maxHeight = Math.max(maxHeight, excel.height());\n        }\n        return (short) (maxHeight * 20);\n    }\n\n    /**\n     * 创建一个工作簿\n     */\n    public void createWorkbook()\n    {\n        this.wb = new SXSSFWorkbook(500);\n        this.sheet = wb.createSheet();\n        wb.setSheetName(0, sheetName);\n        this.styles = createStyles(wb);\n    }\n\n    /**\n     * 创建工作表\n     * \n     * @param sheetNo sheet数量\n     * @param index 序号\n     */\n    public void createSheet(int sheetNo, int index)\n    {\n        // 设置工作表的名称.\n        if (sheetNo > 1 && index > 0)\n        {\n            this.sheet = wb.createSheet();\n            this.createTitle();\n            int actualIndex = wb.getSheetIndex(this.sheet);\n            wb.setSheetName(actualIndex, sheetName + index);\n        }\n    }\n\n    /**\n     * 获取单元格值\n     * \n     * @param row 获取的行\n     * @param column 获取单元格列号\n     * @return 单元格值\n     */\n    public Object getCellValue(Row row, int column)\n    {\n        if (row == null)\n        {\n            return row;\n        }\n        Object val = \"\";\n        try\n        {\n            Cell cell = row.getCell(column);\n            if (StringUtils.isNotNull(cell))\n            {\n                if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA)\n                {\n                    val = cell.getNumericCellValue();\n                    if (DateUtil.isCellDateFormatted(cell))\n                    {\n                        val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换\n                    }\n                    else\n                    {\n                        if ((Double) val % 1 != 0)\n                        {\n                            val = new BigDecimal(val.toString());\n                        }\n                        else\n                        {\n                            val = new DecimalFormat(\"0\").format(val);\n                        }\n                    }\n                }\n                else if (cell.getCellType() == CellType.STRING)\n                {\n                    val = cell.getStringCellValue();\n                }\n                else if (cell.getCellType() == CellType.BOOLEAN)\n                {\n                    val = cell.getBooleanCellValue();\n                }\n                else if (cell.getCellType() == CellType.ERROR)\n                {\n                    val = cell.getErrorCellValue();\n                }\n\n            }\n        }\n        catch (Exception e)\n        {\n            return val;\n        }\n        return val;\n    }\n\n    /**\n     * 判断是否是空行\n     * \n     * @param row 判断的行\n     * @return\n     */\n    private boolean isRowEmpty(Row row)\n    {\n        if (row == null)\n        {\n            return true;\n        }\n        for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++)\n        {\n            Cell cell = row.getCell(i);\n            if (cell != null && cell.getCellType() != CellType.BLANK)\n            {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 获取Excel2003图片\n     *\n     * @param sheet 当前sheet对象\n     * @param workbook 工作簿对象\n     * @return Map key:图片单元格索引（1_1）String，value:图片流PictureData\n     */\n    public static Map<String, List<PictureData>> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook)\n    {\n        Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();\n        List<HSSFPictureData> pictures = workbook.getAllPictures();\n        if (!pictures.isEmpty() && sheet.getDrawingPatriarch() != null)\n        {\n            for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren())\n            {\n                if (shape instanceof HSSFPicture)\n                {\n                    HSSFPicture pic = (HSSFPicture) shape;\n                    HSSFClientAnchor anchor = (HSSFClientAnchor) pic.getAnchor();\n                    String picIndex = anchor.getRow1() + \"_\" + anchor.getCol1();\n                    sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());\n                }\n            }\n        }\n        return sheetIndexPicMap;\n    }\n\n    /**\n     * 获取Excel2007图片\n     *\n     * @param sheet 当前sheet对象\n     * @param workbook 工作簿对象\n     * @return Map key:图片单元格索引（1_1）String，value:图片流PictureData\n     */\n    public static Map<String, List<PictureData>> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook)\n    {\n        Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();\n        for (POIXMLDocumentPart dr : sheet.getRelations())\n        {\n            if (dr instanceof XSSFDrawing)\n            {\n                XSSFDrawing drawing = (XSSFDrawing) dr;\n                for (XSSFShape shape : drawing.getShapes())\n                {\n                    if (shape instanceof XSSFPicture)\n                    {\n                        XSSFPicture pic = (XSSFPicture) shape;\n                        XSSFClientAnchor anchor = pic.getPreferredSize();\n                        CTMarker ctMarker = anchor.getFrom();\n                        String picIndex = ctMarker.getRow() + \"_\" + ctMarker.getCol();\n                        sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());\n                    }\n                }\n            }\n        }\n        return sheetIndexPicMap;\n    }\n\n    /**\n     * 格式化不同类型的日期对象\n     * \n     * @param dateFormat 日期格式\n     * @param val 被格式化的日期对象\n     * @return 格式化后的日期字符\n     */\n    public String parseDateToStr(String dateFormat, Object val)\n    {\n        if (val == null)\n        {\n            return \"\";\n        }\n        String str;\n        if (val instanceof Date)\n        {\n            str = DateUtils.parseDateToStr(dateFormat, (Date) val);\n        }\n        else if (val instanceof LocalDateTime)\n        {\n            str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val));\n        }\n        else if (val instanceof LocalDate)\n        {\n            str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val));\n        }\n        else\n        {\n            str = val.toString();\n        }\n        return str;\n    }\n\n    /**\n     * 是否有对象的子列表\n     */\n    public boolean isSubList()\n    {\n        return !StringUtils.isEmpty(subFieldsMap);\n    }\n\n    /**\n     * 是否有对象的子列表，集合不为空\n     */\n    public boolean isSubListValue(T vo)\n    {\n        return !StringUtils.isEmpty(subFieldsMap) && getListCellValue(vo) > 0;\n    }\n\n    /**\n     * 获取集合的值\n     */\n    public int getListCellValue(Object obj)\n    {\n        Collection<?> value;\n        int max = 0;\n        try\n        {\n            for (String s : subMethods.keySet())\n            {\n                value = (Collection<?>) subMethods.get(s).invoke(obj);\n                if (value.size() > max)\n                {\n                    max = value.size();\n                }\n            }\n        }\n        catch (Exception e)\n        {\n            return 0;\n        }\n        return max;\n    }\n\n    /**\n     * 获取对象的子列表方法\n     * \n     * @param name 名称\n     * @param pojoClass 类对象\n     * @return 子列表方法\n     */\n    public Method getSubMethod(String name, Class<?> pojoClass)\n    {\n        StringBuffer getMethodName = new StringBuffer(\"get\");\n        getMethodName.append(name.substring(0, 1).toUpperCase());\n        getMethodName.append(name.substring(1));\n        Method method = null;\n        try\n        {\n            method = pojoClass.getMethod(getMethodName.toString(), new Class[] {});\n        }\n        catch (Exception e)\n        {\n            log.error(\"获取对象异常{}\", e.getMessage());\n        }\n        return method;\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java",
    "content": "package com.ruoyi.common.utils.reflect;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.math.BigDecimal;\nimport java.util.Date;\nimport org.apache.commons.lang3.Validate;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.common.utils.DateUtils;\nimport com.ruoyi.common.utils.StringUtils;\n\n/**\n * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.\n * \n * @author ruoyi\n */\n@SuppressWarnings(\"rawtypes\")\npublic class ReflectUtils\n{\n    private static final String SETTER_PREFIX = \"set\";\n\n    private static final String GETTER_PREFIX = \"get\";\n\n    private static final String CGLIB_CLASS_SEPARATOR = \"$$\";\n\n    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);\n\n    /**\n     * 调用Getter方法.\n     * 支持多级，如：对象名.对象名.方法\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <E> E invokeGetter(Object obj, String propertyName)\n    {\n        Object object = obj;\n        for (String name : StringUtils.split(propertyName, \".\"))\n        {\n            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);\n            object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});\n        }\n        return (E) object;\n    }\n\n    /**\n     * 调用Setter方法, 仅匹配方法名。\n     * 支持多级，如：对象名.对象名.方法\n     */\n    public static <E> void invokeSetter(Object obj, String propertyName, E value)\n    {\n        Object object = obj;\n        String[] names = StringUtils.split(propertyName, \".\");\n        for (int i = 0; i < names.length; i++)\n        {\n            if (i < names.length - 1)\n            {\n                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);\n                object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});\n            }\n            else\n            {\n                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);\n                invokeMethodByName(object, setterMethodName, new Object[] { value });\n            }\n        }\n    }\n\n    /**\n     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <E> E getFieldValue(final Object obj, final String fieldName)\n    {\n        Field field = getAccessibleField(obj, fieldName);\n        if (field == null)\n        {\n            logger.debug(\"在 [\" + obj.getClass() + \"] 中，没有找到 [\" + fieldName + \"] 字段 \");\n            return null;\n        }\n        E result = null;\n        try\n        {\n            result = (E) field.get(obj);\n        }\n        catch (IllegalAccessException e)\n        {\n            logger.error(\"不可能抛出的异常{}\", e.getMessage());\n        }\n        return result;\n    }\n\n    /**\n     * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.\n     */\n    public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)\n    {\n        Field field = getAccessibleField(obj, fieldName);\n        if (field == null)\n        {\n            // throw new IllegalArgumentException(\"在 [\" + obj.getClass() + \"] 中，没有找到 [\" + fieldName + \"] 字段 \");\n            logger.debug(\"在 [\" + obj.getClass() + \"] 中，没有找到 [\" + fieldName + \"] 字段 \");\n            return;\n        }\n        try\n        {\n            field.set(obj, value);\n        }\n        catch (IllegalAccessException e)\n        {\n            logger.error(\"不可能抛出的异常: {}\", e.getMessage());\n        }\n    }\n\n    /**\n     * 直接调用对象方法, 无视private/protected修饰符.\n     * 用于一次性调用的情况，否则应使用getAccessibleMethod()函数获得Method后反复调用.\n     * 同时匹配方法名+参数类型，\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,\n            final Object[] args)\n    {\n        if (obj == null || methodName == null)\n        {\n            return null;\n        }\n        Method method = getAccessibleMethod(obj, methodName, parameterTypes);\n        if (method == null)\n        {\n            logger.debug(\"在 [\" + obj.getClass() + \"] 中，没有找到 [\" + methodName + \"] 方法 \");\n            return null;\n        }\n        try\n        {\n            return (E) method.invoke(obj, args);\n        }\n        catch (Exception e)\n        {\n            String msg = \"method: \" + method + \", obj: \" + obj + \", args: \" + args + \"\";\n            throw convertReflectionExceptionToUnchecked(msg, e);\n        }\n    }\n\n    /**\n     * 直接调用对象方法, 无视private/protected修饰符，\n     * 用于一次性调用的情况，否则应使用getAccessibleMethodByName()函数获得Method后反复调用.\n     * 只匹配函数名，如果有多个同名函数调用第一个。\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)\n    {\n        Method method = getAccessibleMethodByName(obj, methodName, args.length);\n        if (method == null)\n        {\n            // 如果为空不报错，直接返回空。\n            logger.debug(\"在 [\" + obj.getClass() + \"] 中，没有找到 [\" + methodName + \"] 方法 \");\n            return null;\n        }\n        try\n        {\n            // 类型转换（将参数数据类型转换为目标方法参数类型）\n            Class<?>[] cs = method.getParameterTypes();\n            for (int i = 0; i < cs.length; i++)\n            {\n                if (args[i] != null && !args[i].getClass().equals(cs[i]))\n                {\n                    if (cs[i] == String.class)\n                    {\n                        args[i] = Convert.toStr(args[i]);\n                        if (StringUtils.endsWith((String) args[i], \".0\"))\n                        {\n                            args[i] = StringUtils.substringBefore((String) args[i], \".0\");\n                        }\n                    }\n                    else if (cs[i] == Integer.class)\n                    {\n                        args[i] = Convert.toInt(args[i]);\n                    }\n                    else if (cs[i] == Long.class)\n                    {\n                        args[i] = Convert.toLong(args[i]);\n                    }\n                    else if (cs[i] == Double.class)\n                    {\n                        args[i] = Convert.toDouble(args[i]);\n                    }\n                    else if (cs[i] == Float.class)\n                    {\n                        args[i] = Convert.toFloat(args[i]);\n                    }\n                    else if (cs[i] == Date.class)\n                    {\n                        if (args[i] instanceof String)\n                        {\n                            args[i] = DateUtils.parseDate(args[i]);\n                        }\n                        else\n                        {\n                            args[i] = DateUtil.getJavaDate((Double) args[i]);\n                        }\n                    }\n                    else if (cs[i] == boolean.class || cs[i] == Boolean.class)\n                    {\n                        args[i] = Convert.toBool(args[i]);\n                    }\n                    else if (cs[i] == BigDecimal.class)\n                    {\n                        args[i] = Convert.toBigDecimal(args[i]);\n                    }\n                }\n            }\n            return (E) method.invoke(obj, args);\n        }\n        catch (Exception e)\n        {\n            String msg = \"method: \" + method + \", obj: \" + obj + \", args: \" + args + \"\";\n            throw convertReflectionExceptionToUnchecked(msg, e);\n        }\n    }\n\n    /**\n     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.\n     * 如向上转型到Object仍无法找到, 返回null.\n     */\n    public static Field getAccessibleField(final Object obj, final String fieldName)\n    {\n        // 为空不报错。直接返回 null\n        if (obj == null)\n        {\n            return null;\n        }\n        Validate.notBlank(fieldName, \"fieldName can't be blank\");\n        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())\n        {\n            try\n            {\n                Field field = superClass.getDeclaredField(fieldName);\n                makeAccessible(field);\n                return field;\n            }\n            catch (NoSuchFieldException e)\n            {\n                continue;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.\n     * 如向上转型到Object仍无法找到, 返回null.\n     * 匹配函数名+参数类型。\n     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)\n     */\n    public static Method getAccessibleMethod(final Object obj, final String methodName,\n            final Class<?>... parameterTypes)\n    {\n        // 为空不报错。直接返回 null\n        if (obj == null)\n        {\n            return null;\n        }\n        Validate.notBlank(methodName, \"methodName can't be blank\");\n        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())\n        {\n            try\n            {\n                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);\n                makeAccessible(method);\n                return method;\n            }\n            catch (NoSuchMethodException e)\n            {\n                continue;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.\n     * 如向上转型到Object仍无法找到, 返回null.\n     * 只匹配函数名。\n     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)\n     */\n    public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)\n    {\n        // 为空不报错。直接返回 null\n        if (obj == null)\n        {\n            return null;\n        }\n        Validate.notBlank(methodName, \"methodName can't be blank\");\n        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())\n        {\n            Method[] methods = searchType.getDeclaredMethods();\n            for (Method method : methods)\n            {\n                if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)\n                {\n                    makeAccessible(method);\n                    return method;\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 改变private/protected的方法为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱怨。\n     */\n    @SuppressWarnings(\"deprecation\")\n\tpublic static void makeAccessible(Method method)\n    {\n        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))\n                && !method.isAccessible())\n        {\n            method.setAccessible(true);\n        }\n    }\n\n    /**\n     * 改变private/protected的成员变量为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱怨。\n     */\n    @SuppressWarnings(\"deprecation\")\n\tpublic static void makeAccessible(Field field)\n    {\n        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())\n                || Modifier.isFinal(field.getModifiers())) && !field.isAccessible())\n        {\n            field.setAccessible(true);\n        }\n    }\n\n    /**\n     * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处\n     * 如无法找到, 返回Object.class.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> Class<T> getClassGenricType(final Class clazz)\n    {\n        return getClassGenricType(clazz, 0);\n    }\n\n    /**\n     * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.\n     * 如无法找到, 返回Object.class.\n     */\n    public static Class getClassGenricType(final Class clazz, final int index)\n    {\n        Type genType = clazz.getGenericSuperclass();\n\n        if (!(genType instanceof ParameterizedType))\n        {\n            logger.debug(clazz.getSimpleName() + \"'s superclass not ParameterizedType\");\n            return Object.class;\n        }\n\n        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();\n\n        if (index >= params.length || index < 0)\n        {\n            logger.debug(\"Index: \" + index + \", Size of \" + clazz.getSimpleName() + \"'s Parameterized Type: \"\n                    + params.length);\n            return Object.class;\n        }\n        if (!(params[index] instanceof Class))\n        {\n            logger.debug(clazz.getSimpleName() + \" not set the actual class on superclass generic parameter\");\n            return Object.class;\n        }\n\n        return (Class) params[index];\n    }\n\n    public static Class<?> getUserClass(Object instance)\n    {\n        if (instance == null)\n        {\n            throw new RuntimeException(\"Instance must not be null\");\n        }\n        Class clazz = instance.getClass();\n        if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))\n        {\n            Class<?> superClass = clazz.getSuperclass();\n            if (superClass != null && !Object.class.equals(superClass))\n            {\n                return superClass;\n            }\n        }\n        return clazz;\n\n    }\n\n    /**\n     * 将反射时的checked exception转换为unchecked exception.\n     */\n    public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)\n    {\n        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException\n                || e instanceof NoSuchMethodException)\n        {\n            return new IllegalArgumentException(msg, e);\n        }\n        else if (e instanceof InvocationTargetException)\n        {\n            return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());\n        }\n        return new RuntimeException(msg, e);\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/security/CipherUtils.java",
    "content": "package com.ruoyi.common.utils.security;\r\n\r\nimport java.security.Key;\r\nimport java.security.NoSuchAlgorithmException;\r\nimport javax.crypto.KeyGenerator;\r\n\r\n/**\r\n * 对称密钥密码算法工具类\r\n *\r\n * @author ruoyi\r\n */\r\npublic class CipherUtils\r\n{\r\n    /**\r\n     * 生成随机秘钥\r\n     *\r\n     * @param keyBitSize 字节大小\r\n     * @param algorithmName 算法名称\r\n     * @return 创建密匙\r\n     */\r\n    public static Key generateNewKey(int keyBitSize, String algorithmName)\r\n    {\r\n        KeyGenerator kg;\r\n        try\r\n        {\r\n            kg = KeyGenerator.getInstance(algorithmName);\r\n        }\r\n        catch (NoSuchAlgorithmException e)\r\n        {\r\n            String msg = \"Unable to acquire \" + algorithmName + \" algorithm.  This is required to function.\";\r\n            throw new IllegalStateException(msg, e);\r\n        }\r\n        kg.init(keyBitSize);\r\n        return kg.generateKey();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/security/Md5Utils.java",
    "content": "package com.ruoyi.common.utils.security;\r\n\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.security.MessageDigest;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * Md5加密方法\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Md5Utils\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);\r\n\r\n    private static byte[] md5(String s)\r\n    {\r\n        MessageDigest algorithm;\r\n        try\r\n        {\r\n            algorithm = MessageDigest.getInstance(\"MD5\");\r\n            algorithm.reset();\r\n            algorithm.update(s.getBytes(\"UTF-8\"));\r\n            byte[] messageDigest = algorithm.digest();\r\n            return messageDigest;\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"MD5 Error...\", e);\r\n        }\r\n        return null;\r\n    }\r\n\r\n    private static final String toHex(byte hash[])\r\n    {\r\n        if (hash == null)\r\n        {\r\n            return null;\r\n        }\r\n        StringBuffer buf = new StringBuffer(hash.length * 2);\r\n        int i;\r\n\r\n        for (i = 0; i < hash.length; i++)\r\n        {\r\n            if ((hash[i] & 0xff) < 0x10)\r\n            {\r\n                buf.append(\"0\");\r\n            }\r\n            buf.append(Long.toString(hash[i] & 0xff, 16));\r\n        }\r\n        return buf.toString();\r\n    }\r\n\r\n    public static String hash(String s)\r\n    {\r\n        try\r\n        {\r\n            return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"not supported charset...{}\", e);\r\n            return s;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/security/PermissionUtils.java",
    "content": "package com.ruoyi.common.utils.security;\r\n\r\nimport java.beans.BeanInfo;\r\nimport java.beans.Introspector;\r\nimport java.beans.PropertyDescriptor;\r\nimport org.apache.shiro.SecurityUtils;\r\nimport org.apache.shiro.subject.Subject;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.constant.PermissionConstants;\r\nimport com.ruoyi.common.utils.MessageUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * permission 工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class PermissionUtils\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(PermissionUtils.class);\r\n\r\n    /**\r\n     * 查看数据的权限\r\n     */\r\n    public static final String VIEW_PERMISSION = \"no.view.permission\";\r\n\r\n    /**\r\n     * 创建数据的权限\r\n     */\r\n    public static final String CREATE_PERMISSION = \"no.create.permission\";\r\n\r\n    /**\r\n     * 修改数据的权限\r\n     */\r\n    public static final String UPDATE_PERMISSION = \"no.update.permission\";\r\n\r\n    /**\r\n     * 删除数据的权限\r\n     */\r\n    public static final String DELETE_PERMISSION = \"no.delete.permission\";\r\n\r\n    /**\r\n     * 导出数据的权限\r\n     */\r\n    public static final String EXPORT_PERMISSION = \"no.export.permission\";\r\n\r\n    /**\r\n     * 其他数据的权限\r\n     */\r\n    public static final String PERMISSION = \"no.permission\";\r\n\r\n    /**\r\n     * 权限错误消息提醒\r\n     * \r\n     * @param permissionsStr 错误信息\r\n     * @return 提示信息\r\n     */\r\n    public static String getMsg(String permissionsStr)\r\n    {\r\n        String permission = StringUtils.substringBetween(permissionsStr, \"[\", \"]\");\r\n        String msg = MessageUtils.message(PERMISSION, permission);\r\n        if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.ADD_PERMISSION))\r\n        {\r\n            msg = MessageUtils.message(CREATE_PERMISSION, permission);\r\n        }\r\n        else if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.EDIT_PERMISSION))\r\n        {\r\n            msg = MessageUtils.message(UPDATE_PERMISSION, permission);\r\n        }\r\n        else if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.REMOVE_PERMISSION))\r\n        {\r\n            msg = MessageUtils.message(DELETE_PERMISSION, permission);\r\n        }\r\n        else if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.EXPORT_PERMISSION))\r\n        {\r\n            msg = MessageUtils.message(EXPORT_PERMISSION, permission);\r\n        }\r\n        else if (StringUtils.endsWithAny(permission,\r\n                new String[] { PermissionConstants.VIEW_PERMISSION, PermissionConstants.LIST_PERMISSION }))\r\n        {\r\n            msg = MessageUtils.message(VIEW_PERMISSION, permission);\r\n        }\r\n        return msg;\r\n    }\r\n\r\n    /**\r\n     * 返回用户属性值\r\n     *\r\n     * @param property 属性名称\r\n     * @return 用户属性值\r\n     */\r\n    public static Object getPrincipalProperty(String property)\r\n    {\r\n        Subject subject = SecurityUtils.getSubject();\r\n        if (subject != null)\r\n        {\r\n            Object principal = subject.getPrincipal();\r\n            try\r\n            {\r\n                BeanInfo bi = Introspector.getBeanInfo(principal.getClass());\r\n                for (PropertyDescriptor pd : bi.getPropertyDescriptors())\r\n                {\r\n                    if (pd.getName().equals(property) == true)\r\n                    {\r\n                        return pd.getReadMethod().invoke(principal, (Object[]) null);\r\n                    }\r\n                }\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                log.error(\"Error reading property [{}] from principal of type [{}]\", property,\r\n                        principal.getClass().getName());\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java",
    "content": "package com.ruoyi.common.utils.spring;\n\nimport org.springframework.aop.framework.AopContext;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\nimport com.ruoyi.common.utils.StringUtils;\n\n/**\n * spring工具类 方便在非spring管理环境中获取bean\n * \n * @author ruoyi\n */\n@Component\npublic final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware\n{\n    /** Spring应用上下文环境 */\n    private static ConfigurableListableBeanFactory beanFactory;\n\n    private static ApplicationContext applicationContext;\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException\n    {\n        SpringUtils.beanFactory = beanFactory;\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException\n    {\n        SpringUtils.applicationContext = applicationContext;\n    }\n\n    /**\n     * 获取对象\n     *\n     * @param name\n     * @return Object 一个以所给名字注册的bean的实例\n     * @throws org.springframework.beans.BeansException\n     *\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getBean(String name) throws BeansException\n    {\n        return (T) beanFactory.getBean(name);\n    }\n\n    /**\n     * 获取类型为requiredType的对象\n     *\n     * @param clz\n     * @return\n     * @throws org.springframework.beans.BeansException\n     *\n     */\n    public static <T> T getBean(Class<T> clz) throws BeansException\n    {\n        T result = (T) beanFactory.getBean(clz);\n        return result;\n    }\n\n    /**\n     * 如果BeanFactory包含一个与所给名称匹配的bean定义，则返回true\n     *\n     * @param name\n     * @return boolean\n     */\n    public static boolean containsBean(String name)\n    {\n        return beanFactory.containsBean(name);\n    }\n\n    /**\n     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到，将会抛出一个异常（NoSuchBeanDefinitionException）\n     *\n     * @param name\n     * @return boolean\n     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException\n     *\n     */\n    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException\n    {\n        return beanFactory.isSingleton(name);\n    }\n\n    /**\n     * @param name\n     * @return Class 注册对象的类型\n     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException\n     *\n     */\n    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException\n    {\n        return beanFactory.getType(name);\n    }\n\n    /**\n     * 如果给定的bean名字在bean定义中有别名，则返回这些别名\n     *\n     * @param name\n     * @return\n     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException\n     *\n     */\n    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException\n    {\n        return beanFactory.getAliases(name);\n    }\n\n    /**\n     * 获取aop代理对象\n     * \n     * @param invoker\n     * @return\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getAopProxy(T invoker)\n    {\n        return (T) AopContext.currentProxy();\n    }\n\n    /**\n     * 获取当前的环境配置，无配置返回null\n     *\n     * @return 当前的环境配置\n     */\n    public static String[] getActiveProfiles()\n    {\n        return applicationContext.getEnvironment().getActiveProfiles();\n    }\n\n    /**\n     * 获取当前的环境配置，当有多个环境配置时，只获取第一个\n     *\n     * @return 当前的环境配置\n     */\n    public static String getActiveProfile()\n    {\n        final String[] activeProfiles = getActiveProfiles();\n        return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;\n    }\n\n    /**\n     * 获取配置文件中的值\n     *\n     * @param key 配置文件的key\n     * @return 当前的配置文件的值\n     *\n     */\n    public static String getRequiredProperty(String key)\n    {\n        return applicationContext.getEnvironment().getRequiredProperty(key);\n    }\n\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java",
    "content": "package com.ruoyi.common.utils.sql;\n\nimport com.ruoyi.common.exception.UtilException;\nimport com.ruoyi.common.utils.StringUtils;\n\n/**\n * sql操作工具类\n * \n * @author ruoyi\n */\npublic class SqlUtil\n{\n    /**\n     * 定义常用的 sql关键字\n     */\n    public static String SQL_REGEX = \"\\u000B|and |extractvalue|updatexml|sleep|information_schema|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()\";\n\n    /**\n     * 仅支持字母、数字、下划线、空格、逗号、小数点（支持多个字段排序）\n     */\n    public static String SQL_PATTERN = \"[a-zA-Z0-9_\\\\ \\\\,\\\\.]+\";\n\n    /**\n     * 限制orderBy最大长度\n     */\n    private static final int ORDER_BY_MAX_LENGTH = 500;\n\n    /**\n     * 检查字符，防止注入绕过\n     */\n    public static String escapeOrderBySql(String value)\n    {\n        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))\n        {\n            throw new UtilException(\"参数不符合规范，不能进行查询\");\n        }\n        if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)\n        {\n            throw new UtilException(\"参数已超过最大限制，不能进行查询\");\n        }\n        return value;\n    }\n\n    /**\n     * 验证 order by 语法是否符合规范\n     */\n    public static boolean isValidOrderBySql(String value)\n    {\n        return value.matches(SQL_PATTERN);\n    }\n\n    /**\n     * SQL关键字检查\n     */\n    public static void filterKeyword(String value)\n    {\n        if (StringUtils.isEmpty(value))\n        {\n            return;\n        }\n        String[] sqlKeywords = StringUtils.split(SQL_REGEX, \"\\\\|\");\n        for (String sqlKeyword : sqlKeywords)\n        {\n            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)\n            {\n                throw new UtilException(\"参数存在SQL注入风险\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java",
    "content": "package com.ruoyi.common.utils.uuid;\r\n\r\n/**\r\n * ID生成器工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class IdUtils\r\n{\r\n    /**\r\n     * 获取随机UUID\r\n     * \r\n     * @return 随机UUID\r\n     */\r\n    public static String randomUUID()\r\n    {\r\n        return UUID.randomUUID().toString();\r\n    }\r\n\r\n    /**\r\n     * 简化的UUID，去掉了横线\r\n     * \r\n     * @return 简化的UUID，去掉了横线\r\n     */\r\n    public static String simpleUUID()\r\n    {\r\n        return UUID.randomUUID().toString(true);\r\n    }\r\n\r\n    /**\r\n     * 获取随机UUID，使用性能更好的ThreadLocalRandom生成UUID\r\n     * \r\n     * @return 随机UUID\r\n     */\r\n    public static String fastUUID()\r\n    {\r\n        return UUID.fastUUID().toString();\r\n    }\r\n\r\n    /**\r\n     * 简化的UUID，去掉了横线，使用性能更好的ThreadLocalRandom生成UUID\r\n     * \r\n     * @return 简化的UUID，去掉了横线\r\n     */\r\n    public static String fastSimpleUUID()\r\n    {\r\n        return UUID.fastUUID().toString(true);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java",
    "content": "package com.ruoyi.common.utils.uuid;\r\n\r\nimport java.util.concurrent.atomic.AtomicInteger;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * @author ruoyi 序列生成类\r\n */\r\npublic class Seq\r\n{\r\n    // 通用序列类型\r\n    public static final String commSeqType = \"COMMON\";\r\n\r\n    // 上传序列类型\r\n    public static final String uploadSeqType = \"UPLOAD\";\r\n\r\n    // 通用接口序列数\r\n    private static AtomicInteger commSeq = new AtomicInteger(1);\r\n\r\n    // 上传接口序列数\r\n    private static AtomicInteger uploadSeq = new AtomicInteger(1);\r\n\r\n    // 机器标识\r\n    private static final String machineCode = \"A\";\r\n\r\n    /**\r\n     * 获取通用序列号\r\n     * \r\n     * @return 序列值\r\n     */\r\n    public static String getId()\r\n    {\r\n        return getId(commSeqType);\r\n    }\r\n    \r\n    /**\r\n     * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串\r\n     * \r\n     * @return 序列值\r\n     */\r\n    public static String getId(String type)\r\n    {\r\n        AtomicInteger atomicInt = commSeq;\r\n        if (uploadSeqType.equals(type))\r\n        {\r\n            atomicInt = uploadSeq;\r\n        }\r\n        return getId(atomicInt, 3);\r\n    }\r\n\r\n    /**\r\n     * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串\r\n     * \r\n     * @param atomicInt 序列数\r\n     * @param length 数值长度\r\n     * @return 序列值\r\n     */\r\n    public static String getId(AtomicInteger atomicInt, int length)\r\n    {\r\n        String result = DateUtils.dateTimeNow();\r\n        result += machineCode;\r\n        result += getSeq(atomicInt, length);\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数\r\n     * \r\n     * @return 序列值\r\n     */\r\n    private synchronized static String getSeq(AtomicInteger atomicInt, int length)\r\n    {\r\n        // 先取值再+1\r\n        int value = atomicInt.getAndIncrement();\r\n\r\n        // 如果更新后值>=10 的 (length)幂次方则重置为1\r\n        int maxSeq = (int) Math.pow(10, length);\r\n        if (atomicInt.get() >= maxSeq)\r\n        {\r\n            atomicInt.set(1);\r\n        }\r\n        // 转字符串，用0左补齐\r\n        return StringUtils.padl(value, length);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java",
    "content": "package com.ruoyi.common.utils.uuid;\r\n\r\nimport java.security.MessageDigest;\r\nimport java.security.NoSuchAlgorithmException;\r\nimport java.security.SecureRandom;\r\nimport java.util.Random;\r\nimport java.util.concurrent.ThreadLocalRandom;\r\nimport com.ruoyi.common.exception.UtilException;\r\n\r\n/**\r\n * 提供通用唯一识别码（universally unique identifier）（UUID）实现\r\n *\r\n * @author ruoyi\r\n */\r\npublic final class UUID implements java.io.Serializable, Comparable<UUID>\r\n{\r\n    private static final long serialVersionUID = -1185015143654744140L;\r\n\r\n    /**\r\n     * SecureRandom 的单例\r\n     *\r\n     */\r\n    private static class Holder\r\n    {\r\n        static final SecureRandom numberGenerator = getSecureRandom();\r\n    }\r\n\r\n    /** 此UUID的最高64有效位 */\r\n    private final long mostSigBits;\r\n\r\n    /** 此UUID的最低64有效位 */\r\n    private final long leastSigBits;\r\n\r\n    /**\r\n     * 私有构造\r\n     * \r\n     * @param data 数据\r\n     */\r\n    private UUID(byte[] data)\r\n    {\r\n        long msb = 0;\r\n        long lsb = 0;\r\n        assert data.length == 16 : \"data must be 16 bytes in length\";\r\n        for (int i = 0; i < 8; i++)\r\n        {\r\n            msb = (msb << 8) | (data[i] & 0xff);\r\n        }\r\n        for (int i = 8; i < 16; i++)\r\n        {\r\n            lsb = (lsb << 8) | (data[i] & 0xff);\r\n        }\r\n        this.mostSigBits = msb;\r\n        this.leastSigBits = lsb;\r\n    }\r\n\r\n    /**\r\n     * 使用指定的数据构造新的 UUID。\r\n     *\r\n     * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位\r\n     * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位\r\n     */\r\n    public UUID(long mostSigBits, long leastSigBits)\r\n    {\r\n        this.mostSigBits = mostSigBits;\r\n        this.leastSigBits = leastSigBits;\r\n    }\r\n\r\n    /**\r\n     * 获取类型 4（伪随机生成的）UUID 的静态工厂。\r\n     * \r\n     * @return 随机生成的 {@code UUID}\r\n     */\r\n    public static UUID fastUUID()\r\n    {\r\n        return randomUUID(false);\r\n    }\r\n\r\n    /**\r\n     * 获取类型 4（伪随机生成的）UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。\r\n     * \r\n     * @return 随机生成的 {@code UUID}\r\n     */\r\n    public static UUID randomUUID()\r\n    {\r\n        return randomUUID(true);\r\n    }\r\n\r\n    /**\r\n     * 获取类型 4（伪随机生成的）UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。\r\n     * \r\n     * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码，否则可以得到更好的性能\r\n     * @return 随机生成的 {@code UUID}\r\n     */\r\n    public static UUID randomUUID(boolean isSecure)\r\n    {\r\n        final Random ng = isSecure ? Holder.numberGenerator : getRandom();\r\n\r\n        byte[] randomBytes = new byte[16];\r\n        ng.nextBytes(randomBytes);\r\n        randomBytes[6] &= 0x0f; /* clear version */\r\n        randomBytes[6] |= 0x40; /* set to version 4 */\r\n        randomBytes[8] &= 0x3f; /* clear variant */\r\n        randomBytes[8] |= 0x80; /* set to IETF variant */\r\n        return new UUID(randomBytes);\r\n    }\r\n\r\n    /**\r\n     * 根据指定的字节数组获取类型 3（基于名称的）UUID 的静态工厂。\r\n     *\r\n     * @param name 用于构造 UUID 的字节数组。\r\n     *\r\n     * @return 根据指定数组生成的 {@code UUID}\r\n     */\r\n    public static UUID nameUUIDFromBytes(byte[] name)\r\n    {\r\n        MessageDigest md;\r\n        try\r\n        {\r\n            md = MessageDigest.getInstance(\"MD5\");\r\n        }\r\n        catch (NoSuchAlgorithmException nsae)\r\n        {\r\n            throw new InternalError(\"MD5 not supported\");\r\n        }\r\n        byte[] md5Bytes = md.digest(name);\r\n        md5Bytes[6] &= 0x0f; /* clear version */\r\n        md5Bytes[6] |= 0x30; /* set to version 3 */\r\n        md5Bytes[8] &= 0x3f; /* clear variant */\r\n        md5Bytes[8] |= 0x80; /* set to IETF variant */\r\n        return new UUID(md5Bytes);\r\n    }\r\n\r\n    /**\r\n     * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。\r\n     *\r\n     * @param name 指定 {@code UUID} 字符串\r\n     * @return 具有指定值的 {@code UUID}\r\n     * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常\r\n     *\r\n     */\r\n    public static UUID fromString(String name)\r\n    {\r\n        String[] components = name.split(\"-\");\r\n        if (components.length != 5)\r\n        {\r\n            throw new IllegalArgumentException(\"Invalid UUID string: \" + name);\r\n        }\r\n        for (int i = 0; i < 5; i++)\r\n        {\r\n            components[i] = \"0x\" + components[i];\r\n        }\r\n\r\n        long mostSigBits = Long.decode(components[0]).longValue();\r\n        mostSigBits <<= 16;\r\n        mostSigBits |= Long.decode(components[1]).longValue();\r\n        mostSigBits <<= 16;\r\n        mostSigBits |= Long.decode(components[2]).longValue();\r\n\r\n        long leastSigBits = Long.decode(components[3]).longValue();\r\n        leastSigBits <<= 48;\r\n        leastSigBits |= Long.decode(components[4]).longValue();\r\n\r\n        return new UUID(mostSigBits, leastSigBits);\r\n    }\r\n\r\n    /**\r\n     * 返回此 UUID 的 128 位值中的最低有效 64 位。\r\n     *\r\n     * @return 此 UUID 的 128 位值中的最低有效 64 位。\r\n     */\r\n    public long getLeastSignificantBits()\r\n    {\r\n        return leastSigBits;\r\n    }\r\n\r\n    /**\r\n     * 返回此 UUID 的 128 位值中的最高有效 64 位。\r\n     *\r\n     * @return 此 UUID 的 128 位值中最高有效 64 位。\r\n     */\r\n    public long getMostSignificantBits()\r\n    {\r\n        return mostSigBits;\r\n    }\r\n\r\n    /**\r\n     * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。\r\n     * <p>\r\n     * 版本号具有以下含意:\r\n     * <ul>\r\n     * <li>1 基于时间的 UUID\r\n     * <li>2 DCE 安全 UUID\r\n     * <li>3 基于名称的 UUID\r\n     * <li>4 随机生成的 UUID\r\n     * </ul>\r\n     *\r\n     * @return 此 {@code UUID} 的版本号\r\n     */\r\n    public int version()\r\n    {\r\n        // Version is bits masked by 0x000000000000F000 in MS long\r\n        return (int) ((mostSigBits >> 12) & 0x0f);\r\n    }\r\n\r\n    /**\r\n     * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。\r\n     * <p>\r\n     * 变体号具有以下含意：\r\n     * <ul>\r\n     * <li>0 为 NCS 向后兼容保留\r\n     * <li>2 <a href=\"http://www.ietf.org/rfc/rfc4122.txt\">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz), 用于此类\r\n     * <li>6 保留，微软向后兼容\r\n     * <li>7 保留供以后定义使用\r\n     * </ul>\r\n     *\r\n     * @return 此 {@code UUID} 相关联的变体号\r\n     */\r\n    public int variant()\r\n    {\r\n        // This field is composed of a varying number of bits.\r\n        // 0 - - Reserved for NCS backward compatibility\r\n        // 1 0 - The IETF aka Leach-Salz variant (used by this class)\r\n        // 1 1 0 Reserved, Microsoft backward compatibility\r\n        // 1 1 1 Reserved for future definition.\r\n        return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));\r\n    }\r\n\r\n    /**\r\n     * 与此 UUID 相关联的时间戳值。\r\n     *\r\n     * <p>\r\n     * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>\r\n     * 所得到的时间戳以 100 毫微秒为单位，从 UTC（通用协调时间） 1582 年 10 月 15 日零时开始。\r\n     *\r\n     * <p>\r\n     * 时间戳值仅在在基于时间的 UUID（其 version 类型为 1）中才有意义。<br>\r\n     * 如果此 {@code UUID} 不是基于时间的 UUID，则此方法抛出 UnsupportedOperationException。\r\n     *\r\n     * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。\r\n     */\r\n    public long timestamp() throws UnsupportedOperationException\r\n    {\r\n        checkTimeBase();\r\n        return (mostSigBits & 0x0FFFL) << 48//\r\n                | ((mostSigBits >> 16) & 0x0FFFFL) << 32//\r\n                | mostSigBits >>> 32;\r\n    }\r\n\r\n    /**\r\n     * 与此 UUID 相关联的时钟序列值。\r\n     *\r\n     * <p>\r\n     * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。\r\n     * <p>\r\n     * {@code clockSequence} 值仅在基于时间的 UUID（其 version 类型为 1）中才有意义。 如果此 UUID 不是基于时间的 UUID，则此方法抛出\r\n     * UnsupportedOperationException。\r\n     *\r\n     * @return 此 {@code UUID} 的时钟序列\r\n     *\r\n     * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1\r\n     */\r\n    public int clockSequence() throws UnsupportedOperationException\r\n    {\r\n        checkTimeBase();\r\n        return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);\r\n    }\r\n\r\n    /**\r\n     * 与此 UUID 相关的节点值。\r\n     *\r\n     * <p>\r\n     * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址，该地址用于生成此 UUID 以保证空间唯一性。\r\n     * <p>\r\n     * 节点值仅在基于时间的 UUID（其 version 类型为 1）中才有意义。<br>\r\n     * 如果此 UUID 不是基于时间的 UUID，则此方法抛出 UnsupportedOperationException。\r\n     *\r\n     * @return 此 {@code UUID} 的节点值\r\n     *\r\n     * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1\r\n     */\r\n    public long node() throws UnsupportedOperationException\r\n    {\r\n        checkTimeBase();\r\n        return leastSigBits & 0x0000FFFFFFFFFFFFL;\r\n    }\r\n\r\n    /**\r\n     * 返回此{@code UUID} 的字符串表现形式。\r\n     *\r\n     * <p>\r\n     * UUID 的字符串表示形式由此 BNF 描述：\r\n     * \r\n     * <pre>\r\n     * {@code\r\n     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>\r\n     * time_low               = 4*<hexOctet>\r\n     * time_mid               = 2*<hexOctet>\r\n     * time_high_and_version  = 2*<hexOctet>\r\n     * variant_and_sequence   = 2*<hexOctet>\r\n     * node                   = 6*<hexOctet>\r\n     * hexOctet               = <hexDigit><hexDigit>\r\n     * hexDigit               = [0-9a-fA-F]\r\n     * }\r\n     * </pre>\r\n     * \r\n     * </blockquote>\r\n     *\r\n     * @return 此{@code UUID} 的字符串表现形式\r\n     * @see #toString(boolean)\r\n     */\r\n    @Override\r\n    public String toString()\r\n    {\r\n        return toString(false);\r\n    }\r\n\r\n    /**\r\n     * 返回此{@code UUID} 的字符串表现形式。\r\n     *\r\n     * <p>\r\n     * UUID 的字符串表示形式由此 BNF 描述：\r\n     * \r\n     * <pre>\r\n     * {@code\r\n     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>\r\n     * time_low               = 4*<hexOctet>\r\n     * time_mid               = 2*<hexOctet>\r\n     * time_high_and_version  = 2*<hexOctet>\r\n     * variant_and_sequence   = 2*<hexOctet>\r\n     * node                   = 6*<hexOctet>\r\n     * hexOctet               = <hexDigit><hexDigit>\r\n     * hexDigit               = [0-9a-fA-F]\r\n     * }\r\n     * </pre>\r\n     * \r\n     * </blockquote>\r\n     *\r\n     * @param isSimple 是否简单模式，简单模式为不带'-'的UUID字符串\r\n     * @return 此{@code UUID} 的字符串表现形式\r\n     */\r\n    public String toString(boolean isSimple)\r\n    {\r\n        final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);\r\n        // time_low\r\n        builder.append(digits(mostSigBits >> 32, 8));\r\n        if (!isSimple)\r\n        {\r\n            builder.append('-');\r\n        }\r\n        // time_mid\r\n        builder.append(digits(mostSigBits >> 16, 4));\r\n        if (!isSimple)\r\n        {\r\n            builder.append('-');\r\n        }\r\n        // time_high_and_version\r\n        builder.append(digits(mostSigBits, 4));\r\n        if (!isSimple)\r\n        {\r\n            builder.append('-');\r\n        }\r\n        // variant_and_sequence\r\n        builder.append(digits(leastSigBits >> 48, 4));\r\n        if (!isSimple)\r\n        {\r\n            builder.append('-');\r\n        }\r\n        // node\r\n        builder.append(digits(leastSigBits, 12));\r\n\r\n        return builder.toString();\r\n    }\r\n\r\n    /**\r\n     * 返回此 UUID 的哈希码。\r\n     *\r\n     * @return UUID 的哈希码值。\r\n     */\r\n    @Override\r\n    public int hashCode()\r\n    {\r\n        long hilo = mostSigBits ^ leastSigBits;\r\n        return ((int) (hilo >> 32)) ^ (int) hilo;\r\n    }\r\n\r\n    /**\r\n     * 将此对象与指定对象比较。\r\n     * <p>\r\n     * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值（每一位均相同）时，结果才为 {@code true}。\r\n     *\r\n     * @param obj 要与之比较的对象\r\n     *\r\n     * @return 如果对象相同，则返回 {@code true}；否则返回 {@code false}\r\n     */\r\n    @Override\r\n    public boolean equals(Object obj)\r\n    {\r\n        if ((null == obj) || (obj.getClass() != UUID.class))\r\n        {\r\n            return false;\r\n        }\r\n        UUID id = (UUID) obj;\r\n        return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);\r\n    }\r\n\r\n    // Comparison Operations\r\n\r\n    /**\r\n     * 将此 UUID 与指定的 UUID 比较。\r\n     *\r\n     * <p>\r\n     * 如果两个 UUID 不同，且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段，则第一个 UUID 大于第二个 UUID。\r\n     *\r\n     * @param val 与此 UUID 比较的 UUID\r\n     *\r\n     * @return 在此 UUID 小于、等于或大于 val 时，分别返回 -1、0 或 1。\r\n     *\r\n     */\r\n    @Override\r\n    public int compareTo(UUID val)\r\n    {\r\n        // The ordering is intentionally set up so that the UUIDs\r\n        // can simply be numerically compared as two numbers\r\n        return (this.mostSigBits < val.mostSigBits ? -1 : //\r\n                (this.mostSigBits > val.mostSigBits ? 1 : //\r\n                        (this.leastSigBits < val.leastSigBits ? -1 : //\r\n                                (this.leastSigBits > val.leastSigBits ? 1 : //\r\n                                        0))));\r\n    }\r\n\r\n    // -------------------------------------------------------------------------------------------------------------------\r\n    // Private method start\r\n    /**\r\n     * 返回指定数字对应的hex值\r\n     * \r\n     * @param val 值\r\n     * @param digits 位\r\n     * @return 值\r\n     */\r\n    private static String digits(long val, int digits)\r\n    {\r\n        long hi = 1L << (digits * 4);\r\n        return Long.toHexString(hi | (val & (hi - 1))).substring(1);\r\n    }\r\n\r\n    /**\r\n     * 检查是否为time-based版本UUID\r\n     */\r\n    private void checkTimeBase()\r\n    {\r\n        if (version() != 1)\r\n        {\r\n            throw new UnsupportedOperationException(\"Not a time-based UUID\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取{@link SecureRandom}，类提供加密的强随机数生成器 (RNG)\r\n     * \r\n     * @return {@link SecureRandom}\r\n     */\r\n    public static SecureRandom getSecureRandom()\r\n    {\r\n        try\r\n        {\r\n            return SecureRandom.getInstance(\"SHA1PRNG\");\r\n        }\r\n        catch (NoSuchAlgorithmException e)\r\n        {\r\n            throw new UtilException(e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取随机数生成器对象<br>\r\n     * ThreadLocalRandom是JDK 7之后提供并发产生随机数，能够解决多个线程发生的竞争争夺。\r\n     * \r\n     * @return {@link ThreadLocalRandom}\r\n     */\r\n    public static ThreadLocalRandom getRandom()\r\n    {\r\n        return ThreadLocalRandom.current();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java",
    "content": "package com.ruoyi.common.xss;\r\n\r\nimport jakarta.validation.Constraint;\r\nimport jakarta.validation.Payload;\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n/**\r\n * 自定义xss校验注解\r\n * \r\n * @author ruoyi\r\n */\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })\r\n@Constraint(validatedBy = { XssValidator.class })\r\npublic @interface Xss\r\n{\r\n    String message()\r\n\r\n    default \"不允许任何脚本运行\";\r\n\r\n    Class<?>[] groups() default {};\r\n\r\n    Class<? extends Payload>[] payload() default {};\r\n}\r\n"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/xss/XssFilter.java",
    "content": "package com.ruoyi.common.xss;\r\n\r\nimport java.io.IOException;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport jakarta.servlet.Filter;\r\nimport jakarta.servlet.FilterChain;\r\nimport jakarta.servlet.FilterConfig;\r\nimport jakarta.servlet.ServletException;\r\nimport jakarta.servlet.ServletRequest;\r\nimport jakarta.servlet.ServletResponse;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 防止XSS攻击的过滤器\r\n * \r\n * @author ruoyi\r\n */\r\npublic class XssFilter implements Filter\r\n{\r\n    /**\r\n     * 排除链接\r\n     */\r\n    public List<String> excludes = new ArrayList<>();\r\n\r\n    @Override\r\n    public void init(FilterConfig filterConfig) throws ServletException\r\n    {\r\n        String tempExcludes = filterConfig.getInitParameter(\"excludes\");\r\n        if (StringUtils.isNotEmpty(tempExcludes))\r\n        {\r\n            String[] urls = tempExcludes.split(\",\");\r\n            for (String url : urls)\r\n            {\r\n                excludes.add(url);\r\n            }\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\r\n            throws IOException, ServletException\r\n    {\r\n        HttpServletRequest req = (HttpServletRequest) request;\r\n        HttpServletResponse resp = (HttpServletResponse) response;\r\n        if (handleExcludeURL(req, resp))\r\n        {\r\n            chain.doFilter(request, response);\r\n            return;\r\n        }\r\n        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);\r\n        chain.doFilter(xssRequest, response);\r\n    }\r\n\r\n    private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)\r\n    {\r\n        String url = request.getServletPath();\r\n        String method = request.getMethod();\r\n        // GET DELETE 不过滤\r\n        if (method == null || method.matches(\"GET\") || method.matches(\"DELETE\"))\r\n        {\r\n            return true;\r\n        }\r\n        return StringUtils.matches(url, excludes);\r\n    }\r\n\r\n    @Override\r\n    public void destroy()\r\n    {\r\n\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java",
    "content": "package com.ruoyi.common.xss;\r\n\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletRequestWrapper;\r\nimport com.ruoyi.common.utils.html.EscapeUtil;\r\n\r\n/**\r\n * XSS过滤处理\r\n * \r\n * @author ruoyi\r\n */\r\npublic class XssHttpServletRequestWrapper extends HttpServletRequestWrapper\r\n{\r\n    /**\r\n     * @param request\r\n     */\r\n    public XssHttpServletRequestWrapper(HttpServletRequest request)\r\n    {\r\n        super(request);\r\n    }\r\n\r\n    @Override\r\n    public String[] getParameterValues(String name)\r\n    {\r\n        String[] values = super.getParameterValues(name);\r\n        if (values != null)\r\n        {\r\n            int length = values.length;\r\n            String[] escapseValues = new String[length];\r\n            for (int i = 0; i < length; i++)\r\n            {\r\n                // 防xss攻击和过滤前后空格\r\n                escapseValues[i] = EscapeUtil.clean(values[i]).trim();\r\n            }\r\n            return escapseValues;\r\n        }\r\n        return super.getParameterValues(name);\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java",
    "content": "package com.ruoyi.common.xss;\r\n\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport jakarta.validation.ConstraintValidator;\r\nimport jakarta.validation.ConstraintValidatorContext;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\n\r\n/**\r\n * 自定义xss校验注解实现\r\n * \r\n * @author ruoyi\r\n */\r\npublic class XssValidator implements ConstraintValidator<Xss, String>\r\n{\r\n    private static final String HTML_PATTERN = \"<(\\\\S*?)[^>]*>.*?|<.*? />\";\r\n\r\n    @Override\r\n    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)\r\n    {\r\n        if (StringUtils.isBlank(value))\r\n        {\r\n            return true;\r\n        }\r\n        return !containsHtml(value);\r\n    }\r\n\r\n    public static boolean containsHtml(String value)\r\n    {\r\n        StringBuilder sHtml = new StringBuilder();\r\n        Pattern pattern = Pattern.compile(HTML_PATTERN);\r\n        Matcher matcher = pattern.matcher(value);\r\n        while (matcher.find())\r\n        {\r\n            sHtml.append(matcher.group());\r\n        }\r\n        return pattern.matcher(sHtml).matches();\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-framework/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>ruoyi</artifactId>\n        <groupId>com.ruoyi</groupId>\n        <version>4.8.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>ruoyi-framework</artifactId>\n\n    <description>\n        framework框架核心\n    </description>\n\n    <dependencies>\n\n        <!-- SpringBoot Web容器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-webmvc</artifactId>\n        </dependency>\n\n        <!-- SpringBoot 拦截器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aspectj</artifactId>\n        </dependency>\n\n        <!-- 阿里数据库连接池 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-4-starter</artifactId>\n        </dependency>\n\n        <!-- 验证码 -->\n        <dependency>\n            <groupId>pro.fessional</groupId>\n            <artifactId>kaptcha</artifactId>\n            <exclusions>\n                <exclusion>\n                    <artifactId>servlet-api</artifactId>\n                    <groupId>javax.servlet</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!-- Shiro使用Spring框架 -->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n            <classifier>jakarta</classifier>\n        </dependency>\n\n        <!-- Shiro核心框架 -->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-core</artifactId>\n            <classifier>jakarta</classifier>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-web</artifactId>\n            <classifier>jakarta</classifier>\n        </dependency>\n\n        <!-- thymeleaf模板引擎和shiro框架的整合 -->\n        <dependency>\n            <groupId>com.github.theborakompanioni</groupId>\n            <artifactId>thymeleaf-extras-shiro</artifactId>\n        </dependency>\n\n        <!-- 获取系统信息 -->\n        <dependency>\n            <groupId>com.github.oshi</groupId>\n            <artifactId>oshi-core</artifactId>\n        </dependency>\n\n        <!-- 系统模块-->\n        <dependency>\n            <groupId>com.ruoyi</groupId>\n            <artifactId>ruoyi-system</artifactId>\n        </dependency>\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java",
    "content": "package com.ruoyi.framework.aspectj;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport org.aspectj.lang.JoinPoint;\r\nimport org.aspectj.lang.annotation.Aspect;\r\nimport org.aspectj.lang.annotation.Before;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.annotation.DataScope;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.context.PermissionContextHolder;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 数据过滤处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Aspect\r\n@Component\r\npublic class DataScopeAspect\r\n{\r\n    /**\r\n     * 数据权限过滤关键字\r\n     */\r\n    public static final String DATA_SCOPE = \"dataScope\";\r\n\r\n    @Before(\"@annotation(controllerDataScope)\")\r\n    public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable\r\n    {\r\n        clearDataScope(point);\r\n        handleDataScope(point, controllerDataScope);\r\n    }\r\n\r\n    protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)\r\n    {\r\n        // 获取当前的用户\r\n        SysUser currentUser = ShiroUtils.getSysUser();\r\n        if (currentUser != null)\r\n        {\r\n            // 如果是超级管理员，则不过滤数据\r\n            if (!currentUser.isAdmin())\r\n            {\r\n                String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());\r\n                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 数据范围过滤\r\n     * \r\n     * @param joinPoint 切点\r\n     * @param user 用户\r\n     * @param deptAlias 部门别名\r\n     * @param userAlias 用户别名\r\n     * @param permission 权限字符\r\n     */\r\n    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission)\r\n    {\r\n        StringBuilder sqlString = new StringBuilder();\r\n        List<String> conditions = new ArrayList<String>();\r\n        List<String> scopeCustomIds = new ArrayList<String>();\r\n        user.getRoles().forEach(role -> {\r\n            if (Constants.Dept.DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && (StringUtils.isEmpty(permission) || StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))))\r\n            {\r\n                scopeCustomIds.add(Convert.toStr(role.getRoleId()));\r\n            }\r\n        });\r\n\r\n        for (SysRole role : user.getRoles())\r\n        {\r\n            String dataScope = role.getDataScope();\r\n            if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE))\r\n            {\r\n                continue;\r\n            }\r\n            if (StringUtils.isNotEmpty(permission) && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))\r\n            {\r\n                continue;\r\n            }\r\n            if (Constants.Dept.DATA_SCOPE_ALL.equals(dataScope))\r\n            {\r\n                sqlString = new StringBuilder();\r\n                conditions.add(dataScope);\r\n                break;\r\n            }\r\n            else if (Constants.Dept.DATA_SCOPE_CUSTOM.equals(dataScope))\r\n            {\r\n                if (scopeCustomIds.size() > 1)\r\n                {\r\n                    // 多个自定数据权限使用in查询，避免多次拼接。\r\n                    sqlString.append(StringUtils.format(\" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) \", deptAlias, String.join(\",\", scopeCustomIds)));\r\n                }\r\n                else\r\n                {\r\n                    sqlString.append(StringUtils.format(\" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) \", deptAlias, role.getRoleId()));\r\n                }\r\n            }\r\n            else if (Constants.Dept.DATA_SCOPE_DEPT.equals(dataScope))\r\n            {\r\n                sqlString.append(StringUtils.format(\" OR {}.dept_id = {} \", deptAlias, user.getDeptId()));\r\n            }\r\n            else if (Constants.Dept.DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))\r\n            {\r\n                sqlString.append(StringUtils.format(\" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )\", deptAlias, user.getDeptId(), user.getDeptId()));\r\n            }\r\n            else if (Constants.Dept.DATA_SCOPE_SELF.equals(dataScope))\r\n            {\r\n                if (StringUtils.isNotBlank(userAlias))\r\n                {\r\n                    sqlString.append(StringUtils.format(\" OR {}.user_id = {} \", userAlias, user.getUserId()));\r\n                }\r\n                else\r\n                {\r\n                    // 数据权限为仅本人且没有userAlias别名不查询任何数据\r\n                    sqlString.append(StringUtils.format(\" OR {}.dept_id = 0 \", deptAlias));\r\n                }\r\n            }\r\n            conditions.add(dataScope);\r\n        }\r\n\r\n        // 角色都不包含传递过来的权限字符，这个时候sqlString也会为空，所以要限制一下,不查询任何数据\r\n        if (StringUtils.isEmpty(conditions))\r\n        {\r\n            sqlString.append(StringUtils.format(\" OR {}.dept_id = 0 \", deptAlias));\r\n        }\r\n\r\n        if (StringUtils.isNotBlank(sqlString.toString()))\r\n        {\r\n            Object params = joinPoint.getArgs()[0];\r\n            if (StringUtils.isNotNull(params) && params instanceof BaseEntity)\r\n            {\r\n                BaseEntity baseEntity = (BaseEntity) params;\r\n                baseEntity.getParams().put(DATA_SCOPE, \" AND (\" + sqlString.substring(4) + \")\");\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 拼接权限sql前先清空params.dataScope参数防止注入\r\n     */\r\n    private void clearDataScope(final JoinPoint joinPoint)\r\n    {\r\n        Object params = joinPoint.getArgs()[0];\r\n        if (StringUtils.isNotNull(params) && params instanceof BaseEntity)\r\n        {\r\n            BaseEntity baseEntity = (BaseEntity) params;\r\n            baseEntity.getParams().put(DATA_SCOPE, \"\");\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java",
    "content": "package com.ruoyi.framework.aspectj;\r\n\r\nimport java.util.Objects;\r\nimport org.aspectj.lang.ProceedingJoinPoint;\r\nimport org.aspectj.lang.annotation.Around;\r\nimport org.aspectj.lang.annotation.Aspect;\r\nimport org.aspectj.lang.annotation.Pointcut;\r\nimport org.aspectj.lang.reflect.MethodSignature;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.core.annotation.AnnotationUtils;\r\nimport org.springframework.core.annotation.Order;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.annotation.DataSource;\r\nimport com.ruoyi.common.config.datasource.DynamicDataSourceContextHolder;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 多数据源处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Aspect\r\n@Order(1)\r\n@Component\r\npublic class DataSourceAspect\r\n{\r\n    protected Logger logger = LoggerFactory.getLogger(getClass());\r\n\r\n    @Pointcut(\"@annotation(com.ruoyi.common.annotation.DataSource)\"\r\n            + \"|| @within(com.ruoyi.common.annotation.DataSource)\")\r\n    public void dsPointCut()\r\n    {\r\n\r\n    }\r\n\r\n    @Around(\"dsPointCut()\")\r\n    public Object around(ProceedingJoinPoint point) throws Throwable\r\n    {\r\n        DataSource dataSource = getDataSource(point);\r\n\r\n        if (StringUtils.isNotNull(dataSource))\r\n        {\r\n            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());\r\n        }\r\n\r\n        try\r\n        {\r\n            return point.proceed();\r\n        }\r\n        finally\r\n        {\r\n            // 销毁数据源 在执行方法之后\r\n            DynamicDataSourceContextHolder.clearDataSourceType();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取需要切换的数据源\r\n     */\r\n    public DataSource getDataSource(ProceedingJoinPoint point)\r\n    {\r\n        MethodSignature signature = (MethodSignature) point.getSignature();\r\n        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);\r\n        if (Objects.nonNull(dataSource))\r\n        {\r\n            return dataSource;\r\n        }\r\n\r\n        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java",
    "content": "package com.ruoyi.framework.aspectj;\r\n\r\nimport java.util.Collection;\r\nimport java.util.Map;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport jakarta.servlet.http.HttpServletResponse;\r\nimport org.apache.commons.lang3.ArrayUtils;\r\nimport org.aspectj.lang.JoinPoint;\r\nimport org.aspectj.lang.annotation.AfterReturning;\r\nimport org.aspectj.lang.annotation.AfterThrowing;\r\nimport org.aspectj.lang.annotation.Aspect;\r\nimport org.aspectj.lang.annotation.Before;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.core.NamedThreadLocal;\r\nimport org.springframework.stereotype.Component;\r\nimport org.springframework.validation.BindingResult;\r\nimport org.springframework.web.multipart.MultipartFile;\r\nimport com.alibaba.fastjson.JSONObject;\r\nimport com.alibaba.fastjson.support.spring.PropertyPreFilters;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.enums.BusinessStatus;\r\nimport com.ruoyi.common.utils.ExceptionUtil;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.framework.manager.AsyncManager;\r\nimport com.ruoyi.framework.manager.factory.AsyncFactory;\r\nimport com.ruoyi.system.domain.SysOperLog;\r\n\r\n/**\r\n * 操作日志记录处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Aspect\r\n@Component\r\npublic class LogAspect\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);\r\n\r\n    /** 排除敏感属性字段 */\r\n    public static final String[] EXCLUDE_PROPERTIES = { \"password\", \"oldPassword\", \"newPassword\", \"confirmPassword\" };\r\n\r\n    /** 计算操作消耗时间 */\r\n    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>(\"Cost Time\");\r\n\r\n    /** 参数最大长度限制 */\r\n    private static final int PARAM_MAX_LENGTH = 2000;\r\n\r\n    /**\r\n     * 处理请求前执行\r\n     */\r\n    @Before(value = \"@annotation(controllerLog)\")\r\n    public void doBefore(JoinPoint joinPoint, Log controllerLog)\r\n    {\r\n        TIME_THREADLOCAL.set(System.currentTimeMillis());\r\n    }\r\n\r\n    /**\r\n     * 处理完请求后执行\r\n     *\r\n     * @param joinPoint 切点\r\n     */\r\n    @AfterReturning(pointcut = \"@annotation(controllerLog)\", returning = \"jsonResult\")\r\n    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)\r\n    {\r\n        handleLog(joinPoint, controllerLog, null, jsonResult);\r\n    }\r\n\r\n    /**\r\n     * 拦截异常操作\r\n     * \r\n     * @param joinPoint 切点\r\n     * @param e 异常\r\n     */\r\n    @AfterThrowing(value = \"@annotation(controllerLog)\", throwing = \"e\")\r\n    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)\r\n    {\r\n        handleLog(joinPoint, controllerLog, e, null);\r\n    }\r\n\r\n    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)\r\n    {\r\n        try\r\n        {\r\n            // 获取当前的用户\r\n            SysUser currentUser = ShiroUtils.getSysUser();\r\n\r\n            // *========数据库日志=========*//\r\n            SysOperLog operLog = new SysOperLog();\r\n            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());\r\n            // 请求的地址\r\n            String ip = ShiroUtils.getIp();\r\n            operLog.setOperIp(ip);\r\n            operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));\r\n            if (currentUser != null)\r\n            {\r\n                operLog.setOperName(currentUser.getLoginName());\r\n                if (StringUtils.isNotNull(currentUser.getDept())\r\n                        && StringUtils.isNotEmpty(currentUser.getDept().getDeptName()))\r\n                {\r\n                    operLog.setDeptName(currentUser.getDept().getDeptName());\r\n                }\r\n            }\r\n\r\n            if (e != null)\r\n            {\r\n                operLog.setStatus(BusinessStatus.FAIL.ordinal());\r\n                operLog.setErrorMsg(StringUtils.substring(Convert.toStr(e.getMessage(), ExceptionUtil.getExceptionMessage(e)), 0, 2000));\r\n            }\r\n            // 设置方法名称\r\n            String className = joinPoint.getTarget().getClass().getName();\r\n            String methodName = joinPoint.getSignature().getName();\r\n            operLog.setMethod(className + \".\" + methodName + \"()\");\r\n            // 设置请求方式\r\n            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());\r\n            // 处理设置注解上的参数\r\n            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);\r\n            // 设置消耗时间\r\n            operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());\r\n            // 保存数据库\r\n            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));\r\n        }\r\n        catch (Exception exp)\r\n        {\r\n            // 记录本地异常日志\r\n            log.error(\"异常信息:{}\", exp.getMessage());\r\n            exp.printStackTrace();\r\n        }\r\n        finally\r\n        {\r\n            TIME_THREADLOCAL.remove();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取注解中对方法的描述信息 用于Controller层注解\r\n     * \r\n     * @param log 日志\r\n     * @param operLog 操作日志\r\n     * @throws Exception\r\n     */\r\n    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception\r\n    {\r\n        // 设置action动作\r\n        operLog.setBusinessType(log.businessType().ordinal());\r\n        // 设置标题\r\n        operLog.setTitle(log.title());\r\n        // 设置操作人类别\r\n        operLog.setOperatorType(log.operatorType().ordinal());\r\n        // 是否需要保存request，参数和值\r\n        if (log.isSaveRequestData())\r\n        {\r\n            // 获取参数的信息，传入到数据库中。\r\n            setRequestValue(joinPoint, operLog, log.excludeParamNames());\r\n        }\r\n        // 是否需要保存response，参数和值\r\n        if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))\r\n        {\r\n            operLog.setJsonResult(StringUtils.substring(JSONObject.toJSONString(jsonResult), 0, 2000));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取请求的参数，放到log中\r\n     * \r\n     * @param operLog 操作日志\r\n     * @throws Exception 异常\r\n     */\r\n    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception\r\n    {\r\n        Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();\r\n        if (StringUtils.isNotEmpty(map))\r\n        {\r\n            String params = JSONObject.toJSONString(map, excludePropertyPreFilter(excludeParamNames));\r\n            operLog.setOperParam(StringUtils.substring(params, 0, PARAM_MAX_LENGTH));\r\n        }\r\n        else\r\n        {\r\n            Object args = joinPoint.getArgs();\r\n            if (StringUtils.isNotNull(args))\r\n            {\r\n                String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);\r\n                operLog.setOperParam(params);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 忽略敏感属性\r\n     */\r\n    public PropertyPreFilters.MySimplePropertyPreFilter excludePropertyPreFilter(String[] excludeParamNames)\r\n    {\r\n        return new PropertyPreFilters().addFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));\r\n    }\r\n\r\n    /**\r\n     * 参数拼装\r\n     */\r\n    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)\r\n    {\r\n        StringBuilder params = new StringBuilder();\r\n        if (paramsArray != null && paramsArray.length > 0)\r\n        {\r\n            for (Object o : paramsArray)\r\n            {\r\n                if (StringUtils.isNotNull(o) && !isFilterObject(o))\r\n                {\r\n                    try\r\n                    {\r\n                        Object jsonObj = JSONObject.toJSONString(o, excludePropertyPreFilter(excludeParamNames));\r\n                        params.append(jsonObj).append(\" \");\r\n                        if (params.length() >= PARAM_MAX_LENGTH)\r\n                        {\r\n                            return StringUtils.substring(params.toString(), 0, PARAM_MAX_LENGTH);\r\n                        }\r\n                    }\r\n                    catch (Exception e)\r\n                    {\r\n                        log.error(\"请求参数拼装异常 msg:{}, 参数:{}\", e.getMessage(), paramsArray, e);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        return params.toString();\r\n    }\r\n\r\n    /**\r\n     * 判断是否需要过滤的对象。\r\n     * \r\n     * @param o 对象信息。\r\n     * @return 如果是需要过滤的对象，则返回true；否则返回false。\r\n     */\r\n    @SuppressWarnings(\"rawtypes\")\r\n    public boolean isFilterObject(final Object o)\r\n    {\r\n        Class<?> clazz = o.getClass();\r\n        if (clazz.isArray())\r\n        {\r\n            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);\r\n        }\r\n        else if (Collection.class.isAssignableFrom(clazz))\r\n        {\r\n            Collection collection = (Collection) o;\r\n            for (Object value : collection)\r\n            {\r\n                return value instanceof MultipartFile;\r\n            }\r\n        }\r\n        else if (Map.class.isAssignableFrom(clazz))\r\n        {\r\n            Map map = (Map) o;\r\n            for (Object value : map.entrySet())\r\n            {\r\n                Map.Entry entry = (Map.Entry) value;\r\n                return entry.getValue() instanceof MultipartFile;\r\n            }\r\n        }\r\n        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse\r\n                || o instanceof BindingResult;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/PermissionsAspect.java",
    "content": "package com.ruoyi.framework.aspectj;\n\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Before;\nimport org.springframework.stereotype.Component;\nimport com.ruoyi.common.core.context.PermissionContextHolder;\nimport com.ruoyi.common.utils.StringUtils;\n\n/**\n * 自定义权限拦截器，将权限字符串放到当前请求中以便用于多个角色匹配符合要求的权限\n * \n * @author ruoyi\n */\n@Aspect\n@Component\npublic class PermissionsAspect\n{\n    @Before(\"@annotation(controllerRequiresPermissions)\")\n    public void doBefore(JoinPoint point, RequiresPermissions controllerRequiresPermissions) throws Throwable\n    {\n        handleRequiresPermissions(point, controllerRequiresPermissions);\n    }\n\n    protected void handleRequiresPermissions(final JoinPoint joinPoint, RequiresPermissions requiresPermissions)\n    {\n        PermissionContextHolder.setContext(StringUtils.join(requiresPermissions.value(), \",\"));\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java",
    "content": "package com.ruoyi.framework.config;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\n\n/**\n * 程序注解配置\n *\n * @author ruoyi\n */\n@Configuration\n// 表示通过aop框架暴露该代理对象,AopContext能够访问\n@EnableAspectJAutoProxy(exposeProxy = true)\n// 指定要扫描的Mapper类的包的路径\n@MapperScan(\"com.ruoyi.**.mapper\")\npublic class ApplicationConfig\n{\n\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java",
    "content": "package com.ruoyi.framework.config;\r\n\r\nimport java.util.Properties;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport com.google.code.kaptcha.impl.DefaultKaptcha;\r\nimport com.google.code.kaptcha.util.Config;\r\nimport static com.google.code.kaptcha.Constants.*;\r\n\r\n/**\r\n * 验证码配置\r\n * \r\n * @author ruoyi\r\n */\r\n@Configuration\r\npublic class CaptchaConfig\r\n{\r\n    @Bean(name = \"captchaProducer\")\r\n    public DefaultKaptcha getKaptchaBean()\r\n    {\r\n        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();\r\n        Properties properties = new Properties();\r\n        // 是否有边框 默认为true 我们可以自己设置yes，no\r\n        properties.setProperty(KAPTCHA_BORDER, \"yes\");\r\n        // 验证码文本字符颜色 默认为Color.BLACK\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, \"black\");\r\n        // 验证码图片宽度 默认为200\r\n        properties.setProperty(KAPTCHA_IMAGE_WIDTH, \"160\");\r\n        // 验证码图片高度 默认为50\r\n        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, \"60\");\r\n        // 验证码文本字符大小 默认为40\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, \"38\");\r\n        // KAPTCHA_SESSION_KEY\r\n        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, \"kaptchaCode\");\r\n        // 验证码文本字符长度 默认为5\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, \"4\");\r\n        // 验证码文本字体样式 默认为new Font(\"Arial\", 1, fontSize), new Font(\"Courier\", 1, fontSize)\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, \"Arial,Courier\");\r\n        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy\r\n        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, \"com.google.code.kaptcha.impl.ShadowGimpy\");\r\n        Config config = new Config(properties);\r\n        defaultKaptcha.setConfig(config);\r\n        return defaultKaptcha;\r\n    }\r\n\r\n    @Bean(name = \"captchaProducerMath\")\r\n    public DefaultKaptcha getKaptchaBeanMath()\r\n    {\r\n        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();\r\n        Properties properties = new Properties();\r\n        // 是否有边框 默认为true 我们可以自己设置yes，no\r\n        properties.setProperty(KAPTCHA_BORDER, \"yes\");\r\n        // 边框颜色 默认为Color.BLACK\r\n        properties.setProperty(KAPTCHA_BORDER_COLOR, \"105,179,90\");\r\n        // 验证码文本字符颜色 默认为Color.BLACK\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, \"blue\");\r\n        // 验证码图片宽度 默认为200\r\n        properties.setProperty(KAPTCHA_IMAGE_WIDTH, \"160\");\r\n        // 验证码图片高度 默认为50\r\n        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, \"60\");\r\n        // 验证码文本字符大小 默认为40\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, \"35\");\r\n        // KAPTCHA_SESSION_KEY\r\n        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, \"kaptchaCodeMath\");\r\n        // 验证码文本生成器\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, \"com.ruoyi.framework.config.KaptchaTextCreator\");\r\n        // 验证码文本字符间距 默认为2\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, \"3\");\r\n        // 验证码文本字符长度 默认为5\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, \"6\");\r\n        // 验证码文本字体样式 默认为new Font(\"Arial\", 1, fontSize), new Font(\"Courier\", 1, fontSize)\r\n        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, \"Arial,Courier\");\r\n        // 验证码噪点颜色 默认为Color.BLACK\r\n        properties.setProperty(KAPTCHA_NOISE_COLOR, \"white\");\r\n        // 干扰实现类\r\n        properties.setProperty(KAPTCHA_NOISE_IMPL, \"com.google.code.kaptcha.impl.NoNoise\");\r\n        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy\r\n        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, \"com.google.code.kaptcha.impl.ShadowGimpy\");\r\n        Config config = new Config(properties);\r\n        defaultKaptcha.setConfig(config);\r\n        return defaultKaptcha;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java",
    "content": "package com.ruoyi.framework.config;\r\n\r\nimport java.io.IOException;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\nimport javax.sql.DataSource;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.context.annotation.Primary;\r\nimport com.alibaba.druid.pool.DruidDataSource;\r\nimport com.alibaba.druid.spring.boot4.autoconfigure.DruidDataSourceBuilder;\r\nimport com.alibaba.druid.spring.boot4.autoconfigure.properties.DruidStatProperties;\r\nimport com.alibaba.druid.util.Utils;\r\nimport com.ruoyi.common.enums.DataSourceType;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.framework.config.properties.DruidProperties;\r\nimport com.ruoyi.framework.datasource.DynamicDataSource;\r\nimport jakarta.servlet.Filter;\r\nimport jakarta.servlet.FilterChain;\r\nimport jakarta.servlet.ServletException;\r\nimport jakarta.servlet.ServletRequest;\r\nimport jakarta.servlet.ServletResponse;\r\n\r\n/**\r\n * druid 配置多数据源\r\n * \r\n * @author ruoyi\r\n */\r\n@Configuration\r\npublic class DruidConfig\r\n{\r\n    @Bean\r\n    @ConfigurationProperties(\"spring.datasource.druid.master\")\r\n    public DataSource masterDataSource(DruidProperties druidProperties)\r\n    {\r\n        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();\r\n        return druidProperties.dataSource(dataSource);\r\n    }\r\n\r\n    @Bean\r\n    @ConfigurationProperties(\"spring.datasource.druid.slave\")\r\n    @ConditionalOnProperty(prefix = \"spring.datasource.druid.slave\", name = \"enabled\", havingValue = \"true\")\r\n    public DataSource slaveDataSource(DruidProperties druidProperties)\r\n    {\r\n        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();\r\n        return druidProperties.dataSource(dataSource);\r\n    }\r\n\r\n    @Bean(name = \"dynamicDataSource\")\r\n    @Primary\r\n    public DynamicDataSource dataSource(DataSource masterDataSource)\r\n    {\r\n        Map<Object, Object> targetDataSources = new HashMap<>();\r\n        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);\r\n        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), \"slaveDataSource\");\r\n        return new DynamicDataSource(masterDataSource, targetDataSources);\r\n    }\r\n\r\n    /**\r\n     * 设置数据源\r\n     * \r\n     * @param targetDataSources 备选数据源集合\r\n     * @param sourceName 数据源名称\r\n     * @param beanName bean名称\r\n     */\r\n    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)\r\n    {\r\n        try\r\n        {\r\n            DataSource dataSource = SpringUtils.getBean(beanName);\r\n            targetDataSources.put(sourceName, dataSource);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 去除监控页面底部的广告\r\n     */\r\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\r\n    @Bean\r\n    @ConditionalOnProperty(name = \"spring.datasource.druid.statViewServlet.enabled\", havingValue = \"true\")\r\n    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)\r\n    {\r\n        // 获取web监控页面的参数\r\n        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();\r\n        // 提取common.js的配置路径\r\n        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : \"/druid/*\";\r\n        String commonJsPattern = pattern.replaceAll(\"\\\\*\", \"js/common.js\");\r\n        final String filePath = \"support/http/resources/js/common.js\";\r\n        // 创建filter进行过滤\r\n        Filter filter = new Filter()\r\n        {\r\n            @Override\r\n            public void init(jakarta.servlet.FilterConfig filterConfig) throws ServletException\r\n            {\r\n            }\r\n\r\n            @Override\r\n            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\r\n                    throws IOException, ServletException\r\n            {\r\n                chain.doFilter(request, response);\r\n                // 重置缓冲区，响应头不会被重置\r\n                response.resetBuffer();\r\n                // 获取common.js\r\n                String text = Utils.readFromResource(filePath);\r\n                // 正则替换banner, 除去底部的广告信息\r\n                text = text.replaceAll(\"<a.*?banner\\\"></a><br/>\", \"\");\r\n                text = text.replaceAll(\"powered.*?shrek.wang</a>\", \"\");\r\n                response.getWriter().write(text);\r\n            }\r\n\r\n            @Override\r\n            public void destroy()\r\n            {\r\n            }\r\n        };\r\n        FilterRegistrationBean registrationBean = new FilterRegistrationBean();\r\n        registrationBean.setFilter(filter);\r\n        registrationBean.addUrlPatterns(commonJsPattern);\r\n        return registrationBean;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java",
    "content": "package com.ruoyi.framework.config;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\nimport jakarta.servlet.DispatcherType;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\r\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.xss.XssFilter;\r\n\r\n/**\r\n * Filter配置\r\n *\r\n * @author ruoyi\r\n */\r\n@Configuration\r\n@ConditionalOnProperty(value = \"xss.enabled\", havingValue = \"true\")\r\npublic class FilterConfig\r\n{\r\n    @Value(\"${xss.excludes}\")\r\n    private String excludes;\r\n\r\n    @Value(\"${xss.urlPatterns}\")\r\n    private String urlPatterns;\r\n\r\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\r\n    @Bean\r\n    public FilterRegistrationBean xssFilterRegistration()\r\n    {\r\n        FilterRegistrationBean registration = new FilterRegistrationBean();\r\n        registration.setDispatcherTypes(DispatcherType.REQUEST);\r\n        registration.setFilter(new XssFilter());\r\n        registration.addUrlPatterns(StringUtils.split(urlPatterns, \",\"));\r\n        registration.setName(\"xssFilter\");\r\n        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);\r\n        Map<String, String> initParameters = new HashMap<String, String>();\r\n        initParameters.put(\"excludes\", excludes);\r\n        registration.setInitParameters(initParameters);\r\n        return registration;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java",
    "content": "package com.ruoyi.framework.config;\r\n\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.web.servlet.LocaleResolver;\r\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\r\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\r\nimport org.springframework.web.servlet.i18n.LocaleChangeInterceptor;\r\nimport org.springframework.web.servlet.i18n.SessionLocaleResolver;\r\nimport com.ruoyi.common.constant.Constants;\r\n\r\n/**\r\n * 资源文件配置加载\r\n * \r\n * @author ruoyi\r\n */\r\n@Configuration\r\npublic class I18nConfig implements WebMvcConfigurer\r\n{\r\n    @Bean\r\n    public LocaleResolver localeResolver()\r\n    {\r\n        SessionLocaleResolver slr = new SessionLocaleResolver();\r\n        // 默认语言\r\n        slr.setDefaultLocale(Constants.DEFAULT_LOCALE);\r\n        return slr;\r\n    }\r\n\r\n    @Bean\r\n    public LocaleChangeInterceptor localeChangeInterceptor()\r\n    {\r\n        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();\r\n        // 参数名\r\n        lci.setParamName(\"lang\");\r\n        return lci;\r\n    }\r\n\r\n    @Override\r\n    public void addInterceptors(InterceptorRegistry registry)\r\n    {\r\n        registry.addInterceptor(localeChangeInterceptor());\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java",
    "content": "package com.ruoyi.framework.config;\r\n\r\nimport java.security.SecureRandom;\r\nimport java.util.Random;\r\nimport com.google.code.kaptcha.text.impl.DefaultTextCreator;\r\n\r\n/**\r\n * 验证码文本生成器\r\n * \r\n * @author ruoyi\r\n */\r\npublic class KaptchaTextCreator extends DefaultTextCreator\r\n{\r\n    private static final String[] CNUMBERS = \"0,1,2,3,4,5,6,7,8,9,10\".split(\",\");\r\n\r\n    @Override\r\n    public String getText()\r\n    {\r\n        Integer result = 0;\r\n        Random random = new SecureRandom();\r\n        int x = random.nextInt(10);\r\n        int y = random.nextInt(10);\r\n        StringBuilder suChinese = new StringBuilder();\r\n        int randomoperands = random.nextInt(3);\r\n        if (randomoperands == 0)\r\n        {\r\n            result = x * y;\r\n            suChinese.append(CNUMBERS[x]);\r\n            suChinese.append(\"*\");\r\n            suChinese.append(CNUMBERS[y]);\r\n        }\r\n        else if (randomoperands == 1)\r\n        {\r\n            if (!(x == 0) && y % x == 0)\r\n            {\r\n                result = y / x;\r\n                suChinese.append(CNUMBERS[y]);\r\n                suChinese.append(\"/\");\r\n                suChinese.append(CNUMBERS[x]);\r\n            }\r\n            else\r\n            {\r\n                result = x + y;\r\n                suChinese.append(CNUMBERS[x]);\r\n                suChinese.append(\"+\");\r\n                suChinese.append(CNUMBERS[y]);\r\n            }\r\n        }\r\n        else if (randomoperands == 2)\r\n        {\r\n            if (x >= y)\r\n            {\r\n                result = x - y;\r\n                suChinese.append(CNUMBERS[x]);\r\n                suChinese.append(\"-\");\r\n                suChinese.append(CNUMBERS[y]);\r\n            }\r\n            else\r\n            {\r\n                result = y - x;\r\n                suChinese.append(CNUMBERS[y]);\r\n                suChinese.append(\"-\");\r\n                suChinese.append(CNUMBERS[x]);\r\n            }\r\n        }\r\n        else\r\n        {\r\n            result = x + y;\r\n            suChinese.append(CNUMBERS[x]);\r\n            suChinese.append(\"+\");\r\n            suChinese.append(CNUMBERS[y]);\r\n        }\r\n        suChinese.append(\"=?@\" + result);\r\n        return suChinese.toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java",
    "content": "package com.ruoyi.framework.config;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport javax.sql.DataSource;\nimport org.apache.ibatis.io.VFS;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.boot.autoconfigure.SpringBootVFS;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.core.type.classreading.CachingMetadataReaderFactory;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.util.ClassUtils;\nimport com.ruoyi.common.utils.StringUtils;\n\n/**\n * Mybatis支持*匹配扫描包\n * \n * @author ruoyi\n */\n@Configuration\npublic class MyBatisConfig\n{\n    @Autowired\n    private Environment env;\n\n    static final String DEFAULT_RESOURCE_PATTERN = \"**/*.class\";\n\n    public static String setTypeAliasesPackage(String typeAliasesPackage)\n    {\n        ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();\n        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);\n        List<String> allResult = new ArrayList<String>();\n        try\n        {\n            for (String aliasesPackage : typeAliasesPackage.split(\",\"))\n            {\n                List<String> result = new ArrayList<String>();\n                aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX\n                        + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + \"/\" + DEFAULT_RESOURCE_PATTERN;\n                Resource[] resources = resolver.getResources(aliasesPackage);\n                if (resources != null && resources.length > 0)\n                {\n                    MetadataReader metadataReader = null;\n                    for (Resource resource : resources)\n                    {\n                        if (resource.isReadable())\n                        {\n                            metadataReader = metadataReaderFactory.getMetadataReader(resource);\n                            try\n                            {\n                                result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());\n                            }\n                            catch (ClassNotFoundException e)\n                            {\n                                e.printStackTrace();\n                            }\n                        }\n                    }\n                }\n                if (result.size() > 0)\n                {\n                    HashSet<String> hashResult = new HashSet<String>(result);\n                    allResult.addAll(hashResult);\n                }\n            }\n            if (allResult.size() > 0)\n            {\n                typeAliasesPackage = String.join(\",\", (String[]) allResult.toArray(new String[0]));\n            }\n            else\n            {\n                throw new RuntimeException(\"mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:\" + typeAliasesPackage + \"未找到任何包\");\n            }\n        }\n        catch (IOException e)\n        {\n            e.printStackTrace();\n        }\n        return typeAliasesPackage;\n    }\n\n    public Resource[] resolveMapperLocations(String[] mapperLocations)\n    {\n        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();\n        List<Resource> resources = new ArrayList<Resource>();\n        if (mapperLocations != null)\n        {\n            for (String mapperLocation : mapperLocations)\n            {\n                try\n                {\n                    Resource[] mappers = resourceResolver.getResources(mapperLocation);\n                    resources.addAll(Arrays.asList(mappers));\n                }\n                catch (IOException e)\n                {\n                    // ignore\n                }\n            }\n        }\n        return resources.toArray(new Resource[resources.size()]);\n    }\n\n    @Bean\n    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception\n    {\n        String typeAliasesPackage = env.getProperty(\"mybatis.typeAliasesPackage\");\n        String mapperLocations = env.getProperty(\"mybatis.mapperLocations\");\n        String configLocation = env.getProperty(\"mybatis.configLocation\");\n        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);\n        VFS.addImplClass(SpringBootVFS.class);\n\n        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(dataSource);\n        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);\n        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, \",\")));\n        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));\n        return sessionFactory.getObject();\n    }\n}"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java",
    "content": "package com.ruoyi.framework.config;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\r\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\r\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\r\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\r\nimport com.ruoyi.common.config.RuoYiConfig;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;\r\n\r\n/**\r\n * 通用配置\r\n * \r\n * @author ruoyi\r\n */\r\n@Configuration\r\npublic class ResourcesConfig implements WebMvcConfigurer\r\n{\r\n    /**\r\n     * 首页地址\r\n     */\r\n    @Value(\"${shiro.user.indexUrl}\")\r\n    private String indexUrl;\r\n\r\n    @Autowired\r\n    private RepeatSubmitInterceptor repeatSubmitInterceptor;\r\n\r\n    /**\r\n     * 默认首页的设置，当输入域名是可以自动跳转到默认指定的网页\r\n     */\r\n    @Override\r\n    public void addViewControllers(ViewControllerRegistry registry)\r\n    {\r\n        registry.addViewController(\"/\").setViewName(\"forward:\" + indexUrl);\r\n    }\r\n\r\n    @Override\r\n    public void addResourceHandlers(ResourceHandlerRegistry registry)\r\n    {\r\n        /** 本地文件上传路径 */\r\n        registry.addResourceHandler(Constants.RESOURCE_PREFIX + \"/**\").addResourceLocations(\"file:\" + RuoYiConfig.getProfile() + \"/\");\r\n\r\n        /** swagger配置 */\r\n        registry.addResourceHandler(\"/swagger-ui/**\").addResourceLocations(\"classpath:/META-INF/resources/webjars/springfox-swagger-ui/\");\r\n    }\r\n\r\n    /**\r\n     * 自定义拦截规则\r\n     */\r\n    @Override\r\n    public void addInterceptors(InterceptorRegistry registry)\r\n    {\r\n        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns(\"/**\");\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java",
    "content": "package com.ruoyi.framework.config;\r\n\r\nimport java.io.ByteArrayInputStream;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.Map;\r\nimport org.apache.commons.io.IOUtils;\r\nimport org.apache.shiro.cache.ehcache.EhCacheManager;\r\nimport org.apache.shiro.config.ConfigurationException;\r\nimport org.apache.shiro.lang.codec.Base64;\r\nimport org.apache.shiro.lang.io.ResourceUtils;\r\nimport org.apache.shiro.mgt.SecurityManager;\r\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\r\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\r\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\r\nimport org.apache.shiro.web.servlet.SimpleCookie;\r\nimport org.springframework.beans.factory.annotation.Qualifier;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.security.CipherUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.framework.shiro.realm.UserRealm;\r\nimport com.ruoyi.framework.shiro.rememberMe.CustomCookieRememberMeManager;\r\nimport com.ruoyi.framework.shiro.session.OnlineSessionDAO;\r\nimport com.ruoyi.framework.shiro.session.OnlineSessionFactory;\r\nimport com.ruoyi.framework.shiro.web.CustomShiroFilterFactoryBean;\r\nimport com.ruoyi.framework.shiro.web.filter.LogoutFilter;\r\nimport com.ruoyi.framework.shiro.web.filter.captcha.CaptchaValidateFilter;\r\nimport com.ruoyi.framework.shiro.web.filter.csrf.CsrfValidateFilter;\r\nimport com.ruoyi.framework.shiro.web.filter.kickout.KickoutSessionFilter;\r\nimport com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter;\r\nimport com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;\r\nimport com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager;\r\nimport com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler;\r\nimport at.pollux.thymeleaf.shiro.dialect.ShiroDialect;\r\nimport jakarta.servlet.Filter;\r\n\r\n/**\r\n * 权限配置加载\r\n * \r\n * @author ruoyi\r\n */\r\n@Configuration\r\npublic class ShiroConfig\r\n{\r\n    /**\r\n     * Session超时时间，单位为毫秒（默认30分钟）\r\n     */\r\n    @Value(\"${shiro.session.expireTime}\")\r\n    private int expireTime;\r\n\r\n    /**\r\n     * 相隔多久检查一次session的有效性，单位毫秒，默认就是10分钟\r\n     */\r\n    @Value(\"${shiro.session.validationInterval}\")\r\n    private int validationInterval;\r\n\r\n    /**\r\n     * 同一个用户最大会话数\r\n     */\r\n    @Value(\"${shiro.session.maxSession}\")\r\n    private int maxSession;\r\n\r\n    /**\r\n     * 踢出之前登录的/之后登录的用户，默认踢出之前登录的用户\r\n     */\r\n    @Value(\"${shiro.session.kickoutAfter}\")\r\n    private boolean kickoutAfter;\r\n\r\n    /**\r\n     * 验证码开关\r\n     */\r\n    @Value(\"${shiro.user.captchaEnabled}\")\r\n    private boolean captchaEnabled;\r\n\r\n    /**\r\n     * 验证码类型\r\n     */\r\n    @Value(\"${shiro.user.captchaType}\")\r\n    private String captchaType;\r\n\r\n    /**\r\n     * 设置Cookie的域名\r\n     */\r\n    @Value(\"${shiro.cookie.domain}\")\r\n    private String domain;\r\n\r\n    /**\r\n     * 设置cookie的有效访问路径\r\n     */\r\n    @Value(\"${shiro.cookie.path}\")\r\n    private String path;\r\n\r\n    /**\r\n     * 设置HttpOnly属性\r\n     */\r\n    @Value(\"${shiro.cookie.httpOnly}\")\r\n    private boolean httpOnly;\r\n\r\n    /**\r\n     * 设置Cookie的过期时间，秒为单位\r\n     */\r\n    @Value(\"${shiro.cookie.maxAge}\")\r\n    private int maxAge;\r\n\r\n    /**\r\n     * 设置cipherKey密钥\r\n     */\r\n    @Value(\"${shiro.cookie.cipherKey}\")\r\n    private String cipherKey;\r\n\r\n    /**\r\n     * 登录地址\r\n     */\r\n    @Value(\"${shiro.user.loginUrl}\")\r\n    private String loginUrl;\r\n\r\n    /**\r\n     * 权限认证失败地址\r\n     */\r\n    @Value(\"${shiro.user.unauthorizedUrl}\")\r\n    private String unauthorizedUrl;\r\n\r\n    /**\r\n     * 是否开启记住我功能\r\n     */\r\n    @Value(\"${shiro.rememberMe.enabled: false}\")\r\n    private boolean rememberMe;\r\n\r\n    /**\r\n     * 是否开启csrf\r\n     */\r\n    @Value(\"${csrf.enabled: false}\")\r\n    private boolean csrfEnabled;\r\n\r\n    /**\r\n     * csrf白名单链接\r\n     */\r\n    @Value(\"${csrf.whites: ''}\")\r\n    private String csrfWhites;\r\n\r\n    /**\r\n     * 缓存管理器 使用Ehcache实现\r\n     */\r\n    @Bean\r\n    public EhCacheManager getEhCacheManager()\r\n    {\r\n        net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager(\"ruoyi\");\r\n        EhCacheManager em = new EhCacheManager();\r\n        if (StringUtils.isNull(cacheManager))\r\n        {\r\n            em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));\r\n            return em;\r\n        }\r\n        else\r\n        {\r\n            em.setCacheManager(cacheManager);\r\n            return em;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 返回配置文件流 避免ehcache配置文件一直被占用，无法完全销毁项目重新部署\r\n     */\r\n    protected InputStream getCacheManagerConfigFileInputStream()\r\n    {\r\n        String configFile = \"classpath:ehcache/ehcache-shiro.xml\";\r\n        InputStream inputStream = null;\r\n        try\r\n        {\r\n            inputStream = ResourceUtils.getInputStreamForPath(configFile);\r\n            byte[] b = IOUtils.toByteArray(inputStream);\r\n            InputStream in = new ByteArrayInputStream(b);\r\n            return in;\r\n        }\r\n        catch (IOException e)\r\n        {\r\n            throw new ConfigurationException(\r\n                    \"Unable to obtain input stream for cacheManagerConfigFile [\" + configFile + \"]\", e);\r\n        }\r\n        finally\r\n        {\r\n            IOUtils.closeQuietly(inputStream);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 自定义Realm\r\n     */\r\n    @Bean\r\n    public UserRealm userRealm(EhCacheManager cacheManager)\r\n    {\r\n        UserRealm userRealm = new UserRealm();\r\n        userRealm.setAuthorizationCacheName(Constants.SYS_AUTH_CACHE);\r\n        userRealm.setCacheManager(cacheManager);\r\n        return userRealm;\r\n    }\r\n\r\n    /**\r\n     * 自定义sessionDAO会话\r\n     */\r\n    @Bean\r\n    public OnlineSessionDAO sessionDAO()\r\n    {\r\n        OnlineSessionDAO sessionDAO = new OnlineSessionDAO();\r\n        return sessionDAO;\r\n    }\r\n\r\n    /**\r\n     * 自定义sessionFactory会话\r\n     */\r\n    @Bean\r\n    public OnlineSessionFactory sessionFactory()\r\n    {\r\n        OnlineSessionFactory sessionFactory = new OnlineSessionFactory();\r\n        return sessionFactory;\r\n    }\r\n\r\n    /**\r\n     * 会话管理器\r\n     */\r\n    @Bean\r\n    public OnlineWebSessionManager sessionManager()\r\n    {\r\n        OnlineWebSessionManager manager = new OnlineWebSessionManager();\r\n        // 加入缓存管理器\r\n        manager.setCacheManager(getEhCacheManager());\r\n        // 删除过期的session\r\n        manager.setDeleteInvalidSessions(true);\r\n        // 设置全局session超时时间\r\n        manager.setGlobalSessionTimeout(expireTime * 60 * 1000);\r\n        // 去掉 JSESSIONID\r\n        manager.setSessionIdUrlRewritingEnabled(false);\r\n        // 定义要使用的无效的Session定时调度器\r\n        manager.setSessionValidationScheduler(SpringUtils.getBean(SpringSessionValidationScheduler.class));\r\n        // 是否定时检查session\r\n        manager.setSessionValidationSchedulerEnabled(true);\r\n        // 自定义SessionDao\r\n        manager.setSessionDAO(sessionDAO());\r\n        // 自定义sessionFactory\r\n        manager.setSessionFactory(sessionFactory());\r\n        return manager;\r\n    }\r\n\r\n    /**\r\n     * 安全管理器\r\n     */\r\n    @Bean\r\n    public SecurityManager securityManager(UserRealm userRealm)\r\n    {\r\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\r\n        // 设置realm.\r\n        securityManager.setRealm(userRealm);\r\n        // 记住我\r\n        securityManager.setRememberMeManager(rememberMe ? rememberMeManager() : null);\r\n        // 注入缓存管理器;\r\n        securityManager.setCacheManager(getEhCacheManager());\r\n        // session管理器\r\n        securityManager.setSessionManager(sessionManager());\r\n        return securityManager;\r\n    }\r\n\r\n    /**\r\n     * 退出过滤器\r\n     */\r\n    public LogoutFilter logoutFilter()\r\n    {\r\n        LogoutFilter logoutFilter = new LogoutFilter();\r\n        logoutFilter.setLoginUrl(loginUrl);\r\n        return logoutFilter;\r\n    }\r\n\r\n    /**\r\n     * csrf过滤器\r\n     */\r\n    public CsrfValidateFilter csrfValidateFilter()\r\n    {\r\n        CsrfValidateFilter csrfValidateFilter = new CsrfValidateFilter();\r\n        csrfValidateFilter.setEnabled(csrfEnabled);\r\n        csrfValidateFilter.setCsrfWhites(StringUtils.str2List(csrfWhites, \",\"));\r\n        return csrfValidateFilter;\r\n    }\r\n\r\n    /**\r\n     * Shiro过滤器配置\r\n     */\r\n    @Bean\r\n    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)\r\n    {\r\n        CustomShiroFilterFactoryBean shiroFilterFactoryBean = new CustomShiroFilterFactoryBean();\r\n        // Shiro的核心安全接口,这个属性是必须的\r\n        shiroFilterFactoryBean.setSecurityManager(securityManager);\r\n        // 身份认证失败，则跳转到登录页面的配置\r\n        shiroFilterFactoryBean.setLoginUrl(loginUrl);\r\n        // 权限认证失败，则跳转到指定页面\r\n        shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);\r\n        // Shiro连接约束配置，即过滤链的定义\r\n        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();\r\n        // 对静态资源设置匿名访问\r\n        filterChainDefinitionMap.put(\"/favicon.ico**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/ruoyi.png**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/html/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/css/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/docs/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/fonts/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/img/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/ajax/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/js/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/ruoyi/**\", \"anon\");\r\n        filterChainDefinitionMap.put(\"/captcha/captchaImage**\", \"anon\");\r\n        // 退出 logout地址，shiro去清除session\r\n        filterChainDefinitionMap.put(\"/logout\", \"logout\");\r\n        // 不需要拦截的访问\r\n        filterChainDefinitionMap.put(\"/login\", \"anon,captchaValidate\");\r\n        // 注册相关\r\n        filterChainDefinitionMap.put(\"/register\", \"anon,captchaValidate\");\r\n        // 系统权限列表\r\n        // filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());\r\n\r\n        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();\r\n        filters.put(\"onlineSession\", onlineSessionFilter());\r\n        filters.put(\"syncOnlineSession\", syncOnlineSessionFilter());\r\n        filters.put(\"captchaValidate\", captchaValidateFilter());\r\n        filters.put(\"csrfValidateFilter\", csrfValidateFilter());\r\n        filters.put(\"kickout\", kickoutSessionFilter());\r\n        // 注销成功，则跳转到指定页面\r\n        filters.put(\"logout\", logoutFilter());\r\n        shiroFilterFactoryBean.setFilters(filters);\r\n\r\n        // 所有请求需要认证\r\n        filterChainDefinitionMap.put(\"/**\", \"user,kickout,onlineSession,syncOnlineSession,csrfValidateFilter\");\r\n        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);\r\n\r\n        return shiroFilterFactoryBean;\r\n    }\r\n\r\n    /**\r\n     * 自定义在线用户处理过滤器\r\n     */\r\n    public OnlineSessionFilter onlineSessionFilter()\r\n    {\r\n        OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter();\r\n        onlineSessionFilter.setLoginUrl(loginUrl);\r\n        onlineSessionFilter.setOnlineSessionDAO(sessionDAO());\r\n        return onlineSessionFilter;\r\n    }\r\n\r\n    /**\r\n     * 自定义在线用户同步过滤器\r\n     */\r\n    public SyncOnlineSessionFilter syncOnlineSessionFilter()\r\n    {\r\n        SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter();\r\n        syncOnlineSessionFilter.setOnlineSessionDAO(sessionDAO());\r\n        return syncOnlineSessionFilter;\r\n    }\r\n\r\n    /**\r\n     * 自定义验证码过滤器\r\n     */\r\n    public CaptchaValidateFilter captchaValidateFilter()\r\n    {\r\n        CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter();\r\n        captchaValidateFilter.setCaptchaEnabled(captchaEnabled);\r\n        captchaValidateFilter.setCaptchaType(captchaType);\r\n        return captchaValidateFilter;\r\n    }\r\n\r\n    /**\r\n     * cookie 属性设置\r\n     */\r\n    public SimpleCookie rememberMeCookie()\r\n    {\r\n        SimpleCookie cookie = new SimpleCookie(\"rememberMe\");\r\n        cookie.setDomain(domain);\r\n        cookie.setPath(path);\r\n        cookie.setHttpOnly(httpOnly);\r\n        cookie.setMaxAge(maxAge * 24 * 60 * 60);\r\n        return cookie;\r\n    }\r\n\r\n    /**\r\n     * 记住我\r\n     */\r\n    public CustomCookieRememberMeManager rememberMeManager()\r\n    {\r\n        CustomCookieRememberMeManager cookieRememberMeManager = new CustomCookieRememberMeManager();\r\n        cookieRememberMeManager.setCookie(rememberMeCookie());\r\n        if (StringUtils.isNotEmpty(cipherKey))\r\n        {\r\n            cookieRememberMeManager.setCipherKey(Base64.decode(cipherKey));\r\n        }\r\n        else\r\n        {\r\n            cookieRememberMeManager.setCipherKey(CipherUtils.generateNewKey(128, \"AES\").getEncoded());\r\n        }\r\n        return cookieRememberMeManager;\r\n    }\r\n\r\n    /**\r\n     * 同一个用户多设备登录限制\r\n     */\r\n    public KickoutSessionFilter kickoutSessionFilter()\r\n    {\r\n        KickoutSessionFilter kickoutSessionFilter = new KickoutSessionFilter();\r\n        kickoutSessionFilter.setCacheManager(getEhCacheManager());\r\n        kickoutSessionFilter.setSessionManager(sessionManager());\r\n        // 同一个用户最大的会话数，默认-1无限制；比如2的意思是同一个用户允许最多同时两个人登录\r\n        kickoutSessionFilter.setMaxSession(maxSession);\r\n        // 是否踢出后来登录的，默认是false；即后者登录的用户踢出前者登录的用户；踢出顺序\r\n        kickoutSessionFilter.setKickoutAfter(kickoutAfter);\r\n        // 被踢出后重定向到的地址；\r\n        kickoutSessionFilter.setKickoutUrl(\"/login?kickout=1\");\r\n        return kickoutSessionFilter;\r\n    }\r\n\r\n    /**\r\n     * thymeleaf模板引擎和shiro框架的整合\r\n     */\r\n    @Bean\r\n    public ShiroDialect shiroDialect()\r\n    {\r\n        return new ShiroDialect();\r\n    }\r\n\r\n    /**\r\n     * 开启Shiro注解通知器\r\n     */\r\n    @Bean\r\n    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(\r\n            @Qualifier(\"securityManager\") SecurityManager securityManager)\r\n    {\r\n        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();\r\n        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);\r\n        return authorizationAttributeSourceAdvisor;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java",
    "content": "package com.ruoyi.framework.config.properties;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport com.alibaba.druid.pool.DruidDataSource;\n\n/**\n * druid 配置属性\n * \n * @author ruoyi\n */\n@Configuration\npublic class DruidProperties\n{\n    @Value(\"${spring.datasource.druid.initialSize}\")\n    private int initialSize;\n\n    @Value(\"${spring.datasource.druid.minIdle}\")\n    private int minIdle;\n\n    @Value(\"${spring.datasource.druid.maxActive}\")\n    private int maxActive;\n\n    @Value(\"${spring.datasource.druid.maxWait}\")\n    private int maxWait;\n\n    @Value(\"${spring.datasource.druid.connectTimeout}\")\n    private int connectTimeout;\n\n    @Value(\"${spring.datasource.druid.socketTimeout}\")\n    private int socketTimeout;\n\n    @Value(\"${spring.datasource.druid.timeBetweenEvictionRunsMillis}\")\n    private int timeBetweenEvictionRunsMillis;\n\n    @Value(\"${spring.datasource.druid.minEvictableIdleTimeMillis}\")\n    private int minEvictableIdleTimeMillis;\n\n    @Value(\"${spring.datasource.druid.maxEvictableIdleTimeMillis}\")\n    private int maxEvictableIdleTimeMillis;\n\n    @Value(\"${spring.datasource.druid.validationQuery}\")\n    private String validationQuery;\n\n    @Value(\"${spring.datasource.druid.testWhileIdle}\")\n    private boolean testWhileIdle;\n\n    @Value(\"${spring.datasource.druid.testOnBorrow}\")\n    private boolean testOnBorrow;\n\n    @Value(\"${spring.datasource.druid.testOnReturn}\")\n    private boolean testOnReturn;\n\n    public DruidDataSource dataSource(DruidDataSource datasource)\n    {\n        /** 配置初始化大小、最小、最大 */\n        datasource.setInitialSize(initialSize);\n        datasource.setMaxActive(maxActive);\n        datasource.setMinIdle(minIdle);\n\n        /** 配置获取连接等待超时的时间 */\n        datasource.setMaxWait(maxWait);\n        \n        /** 配置驱动连接超时时间，检测数据库建立连接的超时时间，单位是毫秒 */\n        datasource.setConnectTimeout(connectTimeout);\n        \n        /** 配置网络超时时间，等待数据库操作完成的网络超时时间，单位是毫秒 */\n        datasource.setSocketTimeout(socketTimeout);\n\n        /** 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒 */\n        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n\n        /** 配置一个连接在池中最小、最大生存的时间，单位是毫秒 */\n        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);\n\n        /**\n         * 用来检测连接是否有效的sql，要求是一个查询语句，常用select 'x'。如果validationQuery为null，testOnBorrow、testOnReturn、testWhileIdle都不会起作用。\n         */\n        datasource.setValidationQuery(validationQuery);\n        /** 建议配置为true，不影响性能，并且保证安全性。申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效。 */\n        datasource.setTestWhileIdle(testWhileIdle);\n        /** 申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。 */\n        datasource.setTestOnBorrow(testOnBorrow);\n        /** 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。 */\n        datasource.setTestOnReturn(testOnReturn);\n        return datasource;\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java",
    "content": "package com.ruoyi.framework.datasource;\r\n\r\nimport java.util.Map;\r\nimport javax.sql.DataSource;\r\nimport org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;\r\nimport com.ruoyi.common.config.datasource.DynamicDataSourceContextHolder;\r\n\r\n/**\r\n * 动态数据源\r\n * \r\n * @author ruoyi\r\n */\r\npublic class DynamicDataSource extends AbstractRoutingDataSource\r\n{\r\n    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)\r\n    {\r\n        super.setDefaultTargetDataSource(defaultTargetDataSource);\r\n        super.setTargetDataSources(targetDataSources);\r\n        super.afterPropertiesSet();\r\n    }\r\n\r\n    @Override\r\n    protected Object determineCurrentLookupKey()\r\n    {\r\n        return DynamicDataSourceContextHolder.getDataSourceType();\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java",
    "content": "package com.ruoyi.framework.interceptor;\n\nimport java.lang.reflect.Method;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport com.ruoyi.common.json.JSON;\nimport com.ruoyi.common.annotation.RepeatSubmit;\nimport com.ruoyi.common.core.domain.AjaxResult;\nimport com.ruoyi.common.utils.ServletUtils;\n\n/**\n * 防止重复提交拦截器\n *\n * @author ruoyi\n */\n@Component\npublic abstract class RepeatSubmitInterceptor implements HandlerInterceptor\n{\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception\n    {\n        if (handler instanceof HandlerMethod)\n        {\n            HandlerMethod handlerMethod = (HandlerMethod) handler;\n            Method method = handlerMethod.getMethod();\n            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);\n            if (annotation != null)\n            {\n                if (this.isRepeatSubmit(request, annotation))\n                {\n                    AjaxResult ajaxResult = AjaxResult.error(annotation.message());\n                    ServletUtils.renderString(response, JSON.marshal(ajaxResult));\n                    return false;\n                }\n            }\n            return true;\n        }\n        else\n        {\n            return true;\n        }\n    }\n\n    /**\n     * 验证是否重复提交由子类实现具体的防重复提交的规则\n     *\n     * @param request 请求对象\n     * @param annotation 防复注解\n     * @return 结果\n     */\n    public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception;\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java",
    "content": "package com.ruoyi.framework.interceptor.impl;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpSession;\nimport org.springframework.stereotype.Component;\nimport com.ruoyi.common.annotation.RepeatSubmit;\nimport com.ruoyi.common.json.JSON;\nimport com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;\n\n/**\n * 判断请求url和数据是否和上一次相同， \n * 如果和上次相同，则是重复提交表单。 有效时间为10秒内。\n * \n * @author ruoyi\n */\n@Component\npublic class SameUrlDataInterceptor extends RepeatSubmitInterceptor\n{\n    public final String REPEAT_PARAMS = \"repeatParams\";\n\n    public final String REPEAT_TIME = \"repeatTime\";\n\n    public final String SESSION_REPEAT_KEY = \"repeatData\";\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception\n    {\n        // 本次参数及系统时间\n        String nowParams = JSON.marshal(request.getParameterMap());\n        Map<String, Object> nowDataMap = new HashMap<String, Object>();\n        nowDataMap.put(REPEAT_PARAMS, nowParams);\n        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());\n\n        // 请求地址（作为存放session的key值）\n        String url = request.getRequestURI();\n\n        HttpSession session = request.getSession();\n        Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY);\n        if (sessionObj != null)\n        {\n            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;\n            if (sessionMap.containsKey(url))\n            {\n                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);\n                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))\n                {\n                    return true;\n                }\n            }\n        }\n        Map<String, Object> sessionMap = new HashMap<String, Object>();\n        sessionMap.put(url, nowDataMap);\n        session.setAttribute(SESSION_REPEAT_KEY, sessionMap);\n        return false;\n    }\n\n    /**\n     * 判断参数是否相同\n     */\n    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)\n    {\n        String nowParams = (String) nowMap.get(REPEAT_PARAMS);\n        String preParams = (String) preMap.get(REPEAT_PARAMS);\n        return nowParams.equals(preParams);\n    }\n\n    /**\n     * 判断两次间隔时间\n     */\n    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval)\n    {\n        long time1 = (Long) nowMap.get(REPEAT_TIME);\n        long time2 = (Long) preMap.get(REPEAT_TIME);\n        if ((time1 - time2) < interval)\n        {\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java",
    "content": "package com.ruoyi.framework.manager;\r\n\r\nimport java.util.TimerTask;\r\nimport java.util.concurrent.ScheduledExecutorService;\r\nimport java.util.concurrent.TimeUnit;\r\nimport com.ruoyi.common.utils.Threads;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\n\r\n/**\r\n * 异步任务管理器\r\n * \r\n * @author liuhulu\r\n */\r\npublic class AsyncManager\r\n{\r\n    /**\r\n     * 操作延迟10毫秒\r\n     */\r\n    private final int OPERATE_DELAY_TIME = 10;\r\n\r\n    /**\r\n     * 异步操作任务调度线程池\r\n     */\r\n    private ScheduledExecutorService executor = SpringUtils.getBean(\"scheduledExecutorService\");\r\n\r\n    /**\r\n     * 单例模式\r\n     */\r\n    private AsyncManager(){}\r\n\r\n    private static AsyncManager me = new AsyncManager();\r\n\r\n    public static AsyncManager me()\r\n    {\r\n        return me;\r\n    }\r\n\r\n    /**\r\n     * 执行任务\r\n     * \r\n     * @param task 任务\r\n     */\r\n    public void execute(TimerTask task)\r\n    {\r\n        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);\r\n    }\r\n\r\n    /**\r\n     * 停止任务线程池\r\n     */\r\n    public void shutdown()\r\n    {\r\n        Threads.shutdownAndAwaitTermination(executor);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java",
    "content": "package com.ruoyi.framework.manager;\n\nimport com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler;\nimport net.sf.ehcache.CacheManager;\nimport org.apache.shiro.cache.ehcache.EhCacheManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport jakarta.annotation.PreDestroy;\n\n/**\n * 确保应用退出时能关闭后台线程\n *\n * @author cj\n */\n@Component\npublic class ShutdownManager\n{\n    private static final Logger logger = LoggerFactory.getLogger(\"sys-user\");\n\n    @Autowired(required = false)\n    private SpringSessionValidationScheduler springSessionValidationScheduler;\n\n    @Autowired(required = false)\n    private EhCacheManager ehCacheManager;\n\n    @PreDestroy\n    public void destroy()\n    {\n        shutdownSpringSessionValidationScheduler();\n        shutdownAsyncManager();\n        shutdownEhCacheManager();\n    }\n\n    /**\n     * 停止Seesion会话检查\n     */\n    private void shutdownSpringSessionValidationScheduler()\n    {\n        if (springSessionValidationScheduler != null && springSessionValidationScheduler.isEnabled())\n        {\n            try\n            {\n                logger.info(\"====关闭会话验证任务====\");\n                springSessionValidationScheduler.disableSessionValidation();\n            }\n            catch (Exception e)\n            {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n\n    /**\n     * 停止异步执行任务\n     */\n    private void shutdownAsyncManager()\n    {\n        try\n        {\n            logger.info(\"====关闭后台任务任务线程池====\");\n            AsyncManager.me().shutdown();\n        }\n        catch (Exception e)\n        {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    private void shutdownEhCacheManager()\n    {\n        try\n        {\n            logger.info(\"====关闭缓存====\");\n            if (ehCacheManager != null)\n            {\n                CacheManager cacheManager = ehCacheManager.getCacheManager();\n                cacheManager.shutdown();\n            }\n        }\n        catch (Exception e)\n        {\n            logger.error(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java",
    "content": "package com.ruoyi.framework.manager.factory;\r\n\r\nimport java.io.ByteArrayOutputStream;\r\nimport java.io.ObjectOutputStream;\r\nimport java.util.TimerTask;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.common.utils.AddressUtils;\r\nimport com.ruoyi.common.utils.LogUtils;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.http.UserAgentUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.system.domain.SysLogininfor;\r\nimport com.ruoyi.system.domain.SysOperLog;\r\nimport com.ruoyi.system.domain.SysUserOnline;\r\nimport com.ruoyi.system.service.ISysOperLogService;\r\nimport com.ruoyi.system.service.ISysUserOnlineService;\r\nimport com.ruoyi.system.service.impl.SysLogininforServiceImpl;\r\n\r\n/**\r\n * 异步工厂（产生任务用）\r\n * \r\n * @author liuhulu\r\n *\r\n */\r\npublic class AsyncFactory\r\n{\r\n    private static final Logger sys_user_logger = LoggerFactory.getLogger(\"sys-user\");\r\n\r\n    /**\r\n     * 同步session到数据库\r\n     * \r\n     * @param session 在线用户会话\r\n     * @return 任务task\r\n     */\r\n    public static TimerTask syncSessionToDb(final OnlineSession session)\r\n    {\r\n        return new TimerTask()\r\n        {\r\n            @Override\r\n            public void run()\r\n            {\r\n                SysUserOnline online = new SysUserOnline();\r\n                online.setSessionId(String.valueOf(session.getId()));\r\n                online.setDeptName(session.getDeptName());\r\n                online.setLoginName(session.getLoginName());\r\n                online.setStartTimestamp(session.getStartTimestamp());\r\n                online.setLastAccessTime(session.getLastAccessTime());\r\n                online.setExpireTime(session.getTimeout());\r\n                online.setIpaddr(session.getHost());\r\n                online.setLoginLocation(AddressUtils.getRealAddressByIP(session.getHost()));\r\n                online.setBrowser(session.getBrowser());\r\n                online.setOs(session.getOs());\r\n                online.setStatus(session.getStatus());\r\n                // 序列化 OnlineSession，重启后可从 DB 恢复会话\r\n                try\r\n                {\r\n                    ByteArrayOutputStream bos = new ByteArrayOutputStream();\r\n                    ObjectOutputStream oos = new ObjectOutputStream(bos);\r\n                    oos.writeObject(session);\r\n                    oos.close();\r\n                    online.setSessionData(bos.toByteArray());\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    // 序列化失败不影响正常流程，仅记录日志\r\n                    LoggerFactory.getLogger(AsyncFactory.class).warn(\"serialize OnlineSession failed\", e);\r\n                }\r\n                SpringUtils.getBean(ISysUserOnlineService.class).saveOnline(online);\r\n            }\r\n        };\r\n    }\r\n\r\n    /**\r\n     * 操作日志记录\r\n     * \r\n     * @param operLog 操作日志信息\r\n     * @return 任务task\r\n     */\r\n    public static TimerTask recordOper(final SysOperLog operLog)\r\n    {\r\n        return new TimerTask()\r\n        {\r\n            @Override\r\n            public void run()\r\n            {\r\n                // 远程查询操作地点\r\n                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));\r\n                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);\r\n            }\r\n        };\r\n    }\r\n\r\n    /**\r\n     * 记录登录信息\r\n     * \r\n     * @param username 用户名\r\n     * @param status 状态\r\n     * @param message 消息\r\n     * @param args 列表\r\n     * @return 任务task\r\n     */\r\n    public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args)\r\n    {\r\n        final String userAgent = ServletUtils.getRequest().getHeader(\"User-Agent\");\r\n        final String ip = ShiroUtils.getIp();\r\n        return new TimerTask()\r\n        {\r\n            @Override\r\n            public void run()\r\n            {\r\n                String address = AddressUtils.getRealAddressByIP(ip);\r\n                StringBuilder s = new StringBuilder();\r\n                s.append(LogUtils.getBlock(ip));\r\n                s.append(address);\r\n                s.append(LogUtils.getBlock(username));\r\n                s.append(LogUtils.getBlock(status));\r\n                s.append(LogUtils.getBlock(message));\r\n                // 打印信息到日志\r\n                sys_user_logger.info(s.toString(), args);\r\n                // 获取客户端操作系统\r\n                String os = UserAgentUtils.getOperatingSystem(userAgent);\r\n                // 获取客户端浏览器\r\n                String browser = UserAgentUtils.getBrowser(userAgent);\r\n                // 封装对象\r\n                SysLogininfor logininfor = new SysLogininfor();\r\n                logininfor.setLoginName(username);\r\n                logininfor.setIpaddr(ip);\r\n                logininfor.setLoginLocation(address);\r\n                logininfor.setBrowser(browser);\r\n                logininfor.setOs(os);\r\n                logininfor.setMsg(message);\r\n                // 日志状态\r\n                if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))\r\n                {\r\n                    logininfor.setStatus(Constants.SUCCESS);\r\n                }\r\n                else if (Constants.LOGIN_FAIL.equals(status))\r\n                {\r\n                    logininfor.setStatus(Constants.FAIL);\r\n                }\r\n                // 插入数据\r\n                SpringUtils.getBean(SysLogininforServiceImpl.class).insertLogininfor(logininfor);\r\n            }\r\n        };\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/realm/UserRealm.java",
    "content": "package com.ruoyi.framework.shiro.realm;\r\n\r\nimport java.util.HashSet;\r\nimport java.util.Set;\r\nimport org.apache.shiro.authc.AuthenticationException;\r\nimport org.apache.shiro.authc.AuthenticationInfo;\r\nimport org.apache.shiro.authc.AuthenticationToken;\r\nimport org.apache.shiro.authc.ExcessiveAttemptsException;\r\nimport org.apache.shiro.authc.IncorrectCredentialsException;\r\nimport org.apache.shiro.authc.LockedAccountException;\r\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\r\nimport org.apache.shiro.authc.UnknownAccountException;\r\nimport org.apache.shiro.authc.UsernamePasswordToken;\r\nimport org.apache.shiro.authz.AuthorizationInfo;\r\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\r\nimport org.apache.shiro.cache.Cache;\r\nimport org.apache.shiro.realm.AuthorizingRealm;\r\nimport org.apache.shiro.subject.PrincipalCollection;\r\nimport org.apache.shiro.subject.SimplePrincipalCollection;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.exception.user.CaptchaException;\r\nimport com.ruoyi.common.exception.user.RoleBlockedException;\r\nimport com.ruoyi.common.exception.user.UserBlockedException;\r\nimport com.ruoyi.common.exception.user.UserNotExistsException;\r\nimport com.ruoyi.common.exception.user.UserPasswordNotMatchException;\r\nimport com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.framework.shiro.service.SysLoginService;\r\nimport com.ruoyi.system.service.ISysMenuService;\r\nimport com.ruoyi.system.service.ISysRoleService;\r\n\r\n/**\r\n * 自定义Realm 处理登录 权限\r\n * \r\n * @author ruoyi\r\n */\r\npublic class UserRealm extends AuthorizingRealm\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(UserRealm.class);\r\n\r\n    @Autowired\r\n    private ISysMenuService menuService;\r\n\r\n    @Autowired\r\n    private ISysRoleService roleService;\r\n\r\n    @Autowired\r\n    private SysLoginService loginService;\r\n\r\n    /**\r\n     * 授权\r\n     */\r\n    @Override\r\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)\r\n    {\r\n        SysUser user = ShiroUtils.getSysUser();\r\n        // 角色列表\r\n        Set<String> roles = new HashSet<String>();\r\n        // 功能列表\r\n        Set<String> menus = new HashSet<String>();\r\n        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();\r\n        // 管理员拥有所有权限\r\n        if (user.isAdmin())\r\n        {\r\n            info.addRole(\"admin\");\r\n            info.addStringPermission(\"*:*:*\");\r\n        }\r\n        else\r\n        {\r\n            roles = roleService.selectRoleKeys(user.getUserId());\r\n            menus = menuService.selectPermsByUserId(user.getUserId());\r\n            // 角色加入AuthorizationInfo认证对象\r\n            info.setRoles(roles);\r\n            // 权限加入AuthorizationInfo认证对象\r\n            info.setStringPermissions(menus);\r\n        }\r\n        return info;\r\n    }\r\n\r\n    /**\r\n     * 登录认证\r\n     */\r\n    @Override\r\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException\r\n    {\r\n        UsernamePasswordToken upToken = (UsernamePasswordToken) token;\r\n        String username = upToken.getUsername();\r\n        String password = \"\";\r\n        if (upToken.getPassword() != null)\r\n        {\r\n            password = new String(upToken.getPassword());\r\n        }\r\n\r\n        SysUser user = null;\r\n        try\r\n        {\r\n            user = loginService.login(username, password);\r\n        }\r\n        catch (CaptchaException e)\r\n        {\r\n            throw new AuthenticationException(e.getMessage(), e);\r\n        }\r\n        catch (UserNotExistsException e)\r\n        {\r\n            throw new UnknownAccountException(e.getMessage(), e);\r\n        }\r\n        catch (UserPasswordNotMatchException e)\r\n        {\r\n            throw new IncorrectCredentialsException(e.getMessage(), e);\r\n        }\r\n        catch (UserPasswordRetryLimitExceedException e)\r\n        {\r\n            throw new ExcessiveAttemptsException(e.getMessage(), e);\r\n        }\r\n        catch (UserBlockedException e)\r\n        {\r\n            throw new LockedAccountException(e.getMessage(), e);\r\n        }\r\n        catch (RoleBlockedException e)\r\n        {\r\n            throw new LockedAccountException(e.getMessage(), e);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.info(\"对用户[\" + username + \"]进行登录验证..验证未通过{}\", e.getMessage());\r\n            throw new AuthenticationException(e.getMessage(), e);\r\n        }\r\n        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());\r\n        return info;\r\n    }\r\n\r\n    /**\r\n     * 清理指定用户授权信息缓存\r\n     */\r\n    public void clearCachedAuthorizationInfo(Object principal)\r\n    {\r\n        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());\r\n        this.clearCachedAuthorizationInfo(principals);\r\n    }\r\n\r\n    /**\r\n     * 清理所有用户授权信息缓存\r\n     */\r\n    public void clearAllCachedAuthorizationInfo()\r\n    {\r\n        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();\r\n        if (cache != null)\r\n        {\r\n            for (Object key : cache.keys())\r\n            {\r\n                cache.remove(key);\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/rememberMe/CustomCookieRememberMeManager.java",
    "content": "package com.ruoyi.framework.shiro.rememberMe;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport org.apache.shiro.subject.PrincipalCollection;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.subject.SubjectContext;\nimport org.apache.shiro.web.mgt.CookieRememberMeManager;\nimport com.ruoyi.common.core.domain.entity.SysRole;\nimport com.ruoyi.common.core.domain.entity.SysUser;\nimport com.ruoyi.common.utils.spring.SpringUtils;\nimport com.ruoyi.framework.shiro.service.SysLoginService;\n\n/**\n * 自定义CookieRememberMeManager\n *\n * @author ruoyi\n */\npublic class CustomCookieRememberMeManager extends CookieRememberMeManager\n{\n    /**\n     * 记住我时去掉角色的permissions权限字符串，防止http请求头过大。\n     */\n    @Override\n    protected void rememberIdentity(Subject subject, PrincipalCollection principalCollection)\n    {\n        Map<SysRole, Set<String>> rolePermissions = new HashMap<>();\n        // 清除角色的permissions权限字符串\n        for (Object principal : principalCollection)\n        {\n            if (principal instanceof SysUser)\n            {\n                List<SysRole> roles = ((SysUser) principal).getRoles();\n                for (SysRole role : roles)\n                {\n                    rolePermissions.put(role, role.getPermissions());\n                    role.setPermissions(null);\n                }\n            }\n        }\n        byte[] bytes = convertPrincipalsToBytes(principalCollection);\n        // 恢复角色的permissions权限字符串\n        for (Object principal : principalCollection)\n        {\n            if (principal instanceof SysUser)\n            {\n                List<SysRole> roles = ((SysUser) principal).getRoles();\n                for (SysRole role : roles)\n                {\n                    role.setPermissions(rolePermissions.get(role));\n                }\n            }\n        }\n        rememberSerializedIdentity(subject, bytes);\n    }\n\n    /**\n     * 取记住我身份时恢复角色permissions权限字符串。\n     */\n    @Override\n    public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext)\n    {\n        PrincipalCollection principals = super.getRememberedPrincipals(subjectContext);\n        if (principals == null || principals.isEmpty())\n        {\n            return principals;\n        }\n        for (Object principal : principals)\n        {\n            if (principal instanceof SysUser)\n            {\n                SpringUtils.getBean(SysLoginService.class).setRolePermission((SysUser) principal);\n            }\n        }\n        return principals;\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysLoginService.java",
    "content": "package com.ruoyi.framework.shiro.service;\r\n\r\nimport java.util.List;\r\nimport java.util.Set;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.enums.UserStatus;\r\nimport com.ruoyi.common.exception.user.BlackListException;\r\nimport com.ruoyi.common.exception.user.CaptchaException;\r\nimport com.ruoyi.common.exception.user.UserBlockedException;\r\nimport com.ruoyi.common.exception.user.UserDeleteException;\r\nimport com.ruoyi.common.exception.user.UserNotExistsException;\r\nimport com.ruoyi.common.exception.user.UserPasswordNotMatchException;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.IpUtils;\r\nimport com.ruoyi.common.utils.MessageUtils;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.framework.manager.AsyncManager;\r\nimport com.ruoyi.framework.manager.factory.AsyncFactory;\r\nimport com.ruoyi.system.service.ISysConfigService;\r\nimport com.ruoyi.system.service.ISysMenuService;\r\nimport com.ruoyi.system.service.ISysUserService;\r\n\r\n/**\r\n * 登录校验方法\r\n * \r\n * @author ruoyi\r\n */\r\n@Component\r\npublic class SysLoginService\r\n{\r\n    @Autowired\r\n    private SysPasswordService passwordService;\r\n\r\n    @Autowired\r\n    private ISysUserService userService;\r\n\r\n    @Autowired\r\n    private ISysMenuService menuService;\r\n\r\n    @Autowired\r\n    private ISysConfigService configService;\r\n\r\n    /**\r\n     * 登录\r\n     */\r\n    public SysUser login(String username, String password)\r\n    {\r\n        // 验证码校验\r\n        if (ShiroConstants.CAPTCHA_ERROR.equals(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA)))\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"user.jcaptcha.error\")));\r\n            throw new CaptchaException();\r\n        }\r\n        // 用户名或密码为空 错误\r\n        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"not.null\")));\r\n            throw new UserNotExistsException();\r\n        }\r\n        // 密码如果不在指定范围内 错误\r\n        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH\r\n                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"user.password.not.match\")));\r\n            throw new UserPasswordNotMatchException();\r\n        }\r\n\r\n        // 用户名不在指定范围内 错误\r\n        if (username.length() < UserConstants.USERNAME_MIN_LENGTH\r\n                || username.length() > UserConstants.USERNAME_MAX_LENGTH)\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"user.password.not.match\")));\r\n            throw new UserPasswordNotMatchException();\r\n        }\r\n\r\n        // IP黑名单校验\r\n        String blackStr = configService.selectConfigByKey(\"sys.login.blackIPList\");\r\n        if (IpUtils.isMatchedIp(blackStr, ShiroUtils.getIp()))\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"login.blocked\")));\r\n            throw new BlackListException();\r\n        }\r\n\r\n        // 查询用户信息\r\n        SysUser user = userService.selectUserByLoginName(username);\r\n\r\n        /**\r\n        if (user == null && maybeMobilePhoneNumber(username))\r\n        {\r\n            user = userService.selectUserByPhoneNumber(username);\r\n        }\r\n\r\n        if (user == null && maybeEmail(username))\r\n        {\r\n            user = userService.selectUserByEmail(username);\r\n        }\r\n        */\r\n\r\n        if (user == null)\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"user.not.exists\")));\r\n            throw new UserNotExistsException();\r\n        }\r\n        \r\n        if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"user.password.delete\")));\r\n            throw new UserDeleteException();\r\n        }\r\n        \r\n        if (UserStatus.DISABLE.getCode().equals(user.getStatus()))\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(\"user.blocked\")));\r\n            throw new UserBlockedException();\r\n        }\r\n\r\n        passwordService.validate(user, password);\r\n\r\n        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message(\"user.login.success\")));\r\n        setRolePermission(user);\r\n        recordLoginInfo(user.getUserId());\r\n        return user;\r\n    }\r\n\r\n    /**\r\n    private boolean maybeEmail(String username)\r\n    {\r\n        if (!username.matches(UserConstants.EMAIL_PATTERN))\r\n        {\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n\r\n    private boolean maybeMobilePhoneNumber(String username)\r\n    {\r\n        if (!username.matches(UserConstants.MOBILE_PHONE_NUMBER_PATTERN))\r\n        {\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n    */\r\n\r\n    /**\r\n     * 设置角色权限\r\n     *\r\n     * @param user 用户信息\r\n     */\r\n    public void setRolePermission(SysUser user)\r\n    {\r\n        List<SysRole> roles = user.getRoles();\r\n        if (!roles.isEmpty())\r\n        {\r\n            // 设置permissions属性，以便数据权限匹配权限\r\n            for (SysRole role : roles)\r\n            {\r\n                if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && !role.isAdmin())\r\n                {\r\n                    Set<String> rolePerms = menuService.selectPermsByRoleId(role.getRoleId());\r\n                    role.setPermissions(rolePerms);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 记录登录信息\r\n     *\r\n     * @param userId 用户ID\r\n     */\r\n    public void recordLoginInfo(Long userId)\r\n    {\r\n        userService.updateLoginInfo(userId, ShiroUtils.getIp(), DateUtils.getNowDate());\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysPasswordService.java",
    "content": "package com.ruoyi.framework.shiro.service;\r\n\r\nimport java.util.concurrent.atomic.AtomicInteger;\r\nimport org.apache.shiro.cache.Cache;\r\nimport org.apache.shiro.cache.CacheManager;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.exception.user.UserPasswordNotMatchException;\r\nimport com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;\r\nimport com.ruoyi.common.utils.MessageUtils;\r\nimport com.ruoyi.common.utils.security.Md5Utils;\r\nimport com.ruoyi.framework.manager.AsyncManager;\r\nimport com.ruoyi.framework.manager.factory.AsyncFactory;\r\nimport jakarta.annotation.PostConstruct;\r\n\r\n/**\r\n * 登录密码方法\r\n * \r\n * @author ruoyi\r\n */\r\n@Component\r\npublic class SysPasswordService\r\n{\r\n    @Autowired\r\n    private CacheManager cacheManager;\r\n\r\n    private Cache<String, AtomicInteger> loginRecordCache;\r\n\r\n    @Value(value = \"${user.password.maxRetryCount}\")\r\n    private String maxRetryCount;\r\n\r\n    @PostConstruct\r\n    public void init()\r\n    {\r\n        loginRecordCache = cacheManager.getCache(ShiroConstants.LOGIN_RECORD_CACHE);\r\n    }\r\n\r\n    public void validate(SysUser user, String password)\r\n    {\r\n        String loginName = user.getLoginName();\r\n\r\n        AtomicInteger retryCount = loginRecordCache.get(loginName);\r\n\r\n        if (retryCount == null)\r\n        {\r\n            retryCount = new AtomicInteger(0);\r\n            loginRecordCache.put(loginName, retryCount);\r\n        }\r\n        if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue())\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message(\"user.password.retry.limit.exceed\", maxRetryCount)));\r\n            throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue());\r\n        }\r\n\r\n        if (!matches(user, password))\r\n        {\r\n            AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message(\"user.password.retry.limit.count\", retryCount)));\r\n            loginRecordCache.put(loginName, retryCount);\r\n            throw new UserPasswordNotMatchException();\r\n        }\r\n        else\r\n        {\r\n            clearLoginRecordCache(loginName);\r\n        }\r\n    }\r\n\r\n    public boolean matches(SysUser user, String newPassword)\r\n    {\r\n        return user.getPassword().equals(encryptPassword(user.getLoginName(), newPassword, user.getSalt()));\r\n    }\r\n\r\n    public void clearLoginRecordCache(String loginName)\r\n    {\r\n        loginRecordCache.remove(loginName);\r\n    }\r\n\r\n    public String encryptPassword(String loginName, String password, String salt)\r\n    {\r\n        return Md5Utils.hash(loginName + password + salt);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysRegisterService.java",
    "content": "package com.ruoyi.framework.shiro.service;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.MessageUtils;\r\nimport com.ruoyi.common.utils.ServletUtils;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.framework.manager.AsyncManager;\r\nimport com.ruoyi.framework.manager.factory.AsyncFactory;\r\nimport com.ruoyi.system.service.ISysUserService;\r\n\r\n/**\r\n * 注册校验方法\r\n * \r\n * @author ruoyi\r\n */\r\n@Component\r\npublic class SysRegisterService\r\n{\r\n    @Autowired\r\n    private ISysUserService userService;\r\n\r\n    @Autowired\r\n    private SysPasswordService passwordService;\r\n\r\n    /**\r\n     * 注册\r\n     */\r\n    public String register(SysUser user)\r\n    {\r\n        String msg = \"\", loginName = user.getLoginName(), password = user.getPassword();\r\n\r\n        if (ShiroConstants.CAPTCHA_ERROR.equals(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA)))\r\n        {\r\n            msg = \"验证码错误\";\r\n        }\r\n        else if (StringUtils.isEmpty(loginName))\r\n        {\r\n            msg = \"用户名不能为空\";\r\n        }\r\n        else if (StringUtils.isEmpty(password))\r\n        {\r\n            msg = \"用户密码不能为空\";\r\n        }\r\n        else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH\r\n                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)\r\n        {\r\n            msg = \"密码长度必须在5到20个字符之间\";\r\n        }\r\n        else if (loginName.length() < UserConstants.USERNAME_MIN_LENGTH\r\n                || loginName.length() > UserConstants.USERNAME_MAX_LENGTH)\r\n        {\r\n            msg = \"账户长度必须在2到20个字符之间\";\r\n        }\r\n        else if (!userService.checkLoginNameUnique(user))\r\n        {\r\n            msg = \"保存用户'\" + loginName + \"'失败，注册账号已存在\";\r\n        }\r\n        else\r\n        {\r\n            user.setPwdUpdateDate(DateUtils.getNowDate());\r\n            user.setUserName(loginName);\r\n            user.setSalt(ShiroUtils.randomSalt());\r\n            user.setPassword(passwordService.encryptPassword(loginName, password, user.getSalt()));\r\n            boolean regFlag = userService.registerUser(user);\r\n            if (!regFlag)\r\n            {\r\n                msg = \"注册失败,请联系系统管理人员\";\r\n            }\r\n            else\r\n            {\r\n                AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.REGISTER, MessageUtils.message(\"user.register.success\")));\r\n            }\r\n        }\r\n        return msg;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysShiroService.java",
    "content": "package com.ruoyi.framework.shiro.service;\n\nimport java.io.Serializable;\nimport org.apache.shiro.session.Session;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport com.ruoyi.common.core.session.OnlineSession;\nimport com.ruoyi.common.utils.StringUtils;\nimport com.ruoyi.system.domain.SysUserOnline;\nimport com.ruoyi.framework.shiro.session.OnlineSessionFactory;\nimport com.ruoyi.system.service.ISysUserOnlineService;\n\n/**\n * 会话db操作处理\n * \n * @author ruoyi\n */\n@Component\npublic class SysShiroService\n{\n    @Autowired\n    private ISysUserOnlineService onlineService;\n\n    @Autowired\n    private OnlineSessionFactory onlineSessionFactory;\n\n    /**\n     * 删除会话\n     *\n     * @param onlineSession 会话信息\n     */\n    public void deleteSession(OnlineSession onlineSession)\n    {\n        onlineService.deleteOnlineById(String.valueOf(onlineSession.getId()));\n    }\n\n    /**\n     * 获取会话信息\n     *\n     * @param sessionId\n     * @return\n     */\n    public Session getSession(Serializable sessionId)\n    {\n        SysUserOnline userOnline = onlineService.selectOnlineById(String.valueOf(sessionId));\n        return StringUtils.isNull(userOnline) ? null : createSession(userOnline);\n    }\n\n    public Session createSession(SysUserOnline userOnline)\n    {\n        return onlineSessionFactory.createSession(userOnline);\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java",
    "content": "package com.ruoyi.framework.shiro.session;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.Date;\r\nimport org.apache.shiro.session.Session;\r\nimport org.apache.shiro.session.UnknownSessionException;\r\nimport org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.common.enums.OnlineStatus;\r\nimport com.ruoyi.framework.manager.AsyncManager;\r\nimport com.ruoyi.framework.manager.factory.AsyncFactory;\r\nimport com.ruoyi.framework.shiro.service.SysShiroService;\r\n\r\n/**\r\n * 针对自定义的ShiroSession的db操作\r\n * \r\n * @author ruoyi\r\n */\r\npublic class OnlineSessionDAO extends EnterpriseCacheSessionDAO\r\n{\r\n    /**\r\n     * 同步session到数据库的周期 单位为毫秒（默认1分钟）\r\n     */\r\n    @Value(\"${shiro.session.dbSyncPeriod}\")\r\n    private int dbSyncPeriod;\r\n\r\n    /**\r\n     * 上次同步数据库的时间戳\r\n     */\r\n    private static final String LAST_SYNC_DB_TIMESTAMP = OnlineSessionDAO.class.getName() + \"LAST_SYNC_DB_TIMESTAMP\";\r\n\r\n    @Autowired\r\n    private SysShiroService sysShiroService;\r\n\r\n    public OnlineSessionDAO()\r\n    {\r\n        super();\r\n    }\r\n\r\n    public OnlineSessionDAO(long expireTime)\r\n    {\r\n        super();\r\n    }\r\n\r\n    /**\r\n     * 根据会话ID获取会话\r\n     *\r\n     * @param sessionId 会话ID\r\n     * @return ShiroSession\r\n     */\r\n    @Override\r\n    protected Session doReadSession(Serializable sessionId)\r\n    {\r\n        return sysShiroService.getSession(sessionId);\r\n    }\r\n\r\n    @Override\r\n    public void update(Session session) throws UnknownSessionException\r\n    {\r\n        super.update(session);\r\n    }\r\n\r\n    /**\r\n     * 更新会话；如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用\r\n     */\r\n    public void syncToDb(OnlineSession onlineSession)\r\n    {\r\n        Date lastSyncTimestamp = (Date) onlineSession.getAttribute(LAST_SYNC_DB_TIMESTAMP);\r\n        if (lastSyncTimestamp != null)\r\n        {\r\n            boolean needSync = true;\r\n            long deltaTime = onlineSession.getLastAccessTime().getTime() - lastSyncTimestamp.getTime();\r\n            if (deltaTime < dbSyncPeriod * 60 * 1000)\r\n            {\r\n                // 时间差不足 无需同步\r\n                needSync = false;\r\n            }\r\n            // isGuest = true 访客\r\n            boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L;\r\n\r\n            // session 数据变更了 同步\r\n            if (!isGuest && onlineSession.isAttributeChanged())\r\n            {\r\n                needSync = true;\r\n            }\r\n\r\n            if (!needSync)\r\n            {\r\n                return;\r\n            }\r\n        }\r\n        // 更新上次同步数据库时间\r\n        onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime());\r\n        // 更新完后 重置标识\r\n        if (onlineSession.isAttributeChanged())\r\n        {\r\n            onlineSession.resetAttributeChanged();\r\n        }\r\n        AsyncManager.me().execute(AsyncFactory.syncSessionToDb(onlineSession));\r\n    }\r\n\r\n    /**\r\n     * 当会话过期/停止（如用户退出时）属性等会调用\r\n     */\r\n    @Override\r\n    protected void doDelete(Session session)\r\n    {\r\n        OnlineSession onlineSession = (OnlineSession) session;\r\n        if (null == onlineSession)\r\n        {\r\n            return;\r\n        }\r\n        onlineSession.setStatus(OnlineStatus.off_line);\r\n        sysShiroService.deleteSession(onlineSession);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java",
    "content": "package com.ruoyi.framework.shiro.session;\r\n\r\nimport java.io.ByteArrayInputStream;\r\nimport java.io.ObjectInputStream;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport org.apache.shiro.session.Session;\r\nimport org.apache.shiro.session.mgt.SessionContext;\r\nimport org.apache.shiro.session.mgt.SessionFactory;\r\nimport org.apache.shiro.web.session.mgt.WebSessionContext;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.common.utils.IpUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.http.UserAgentUtils;\r\nimport com.ruoyi.system.domain.SysUserOnline;\r\n\r\n/**\r\n * 自定义sessionFactory会话\r\n * \r\n * @author ruoyi\r\n */\r\n@Component\r\npublic class OnlineSessionFactory implements SessionFactory\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(OnlineSessionFactory.class);\r\n\r\n    public Session createSession(SysUserOnline userOnline)\r\n    {\r\n        // 优先从序列化数据恢复完整 Session（包含 principals 认证信息）\r\n        if (userOnline.getSessionData() != null && userOnline.getSessionData().length > 0)\r\n        {\r\n            try\r\n            {\r\n                ByteArrayInputStream bis = new ByteArrayInputStream(userOnline.getSessionData());\r\n                ObjectInputStream ois = new ObjectInputStream(bis);\r\n                OnlineSession onlineSession = (OnlineSession) ois.readObject();\r\n                ois.close();\r\n                // 确保 sessionId 和 DB 一致\r\n                if (onlineSession.getId() == null)\r\n                {\r\n                    onlineSession.setId(userOnline.getSessionId());\r\n                }\r\n                return onlineSession;\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                log.warn(\"deserialize OnlineSession failed, sessionId={}\", userOnline.getSessionId(), e);\r\n            }\r\n        }\r\n        // 降级：仅用基础字段重建（无认证信息，会触发重新登录）\r\n        OnlineSession onlineSession = userOnline.getSession();\r\n        if (StringUtils.isNotNull(onlineSession) && onlineSession.getId() == null)\r\n        {\r\n            onlineSession.setId(userOnline.getSessionId());\r\n        }\r\n        return onlineSession;\r\n    }\r\n    \r\n    @Override\r\n    public Session createSession(SessionContext initData)\r\n    {\r\n        OnlineSession session = new OnlineSession();\r\n        if (initData != null && initData instanceof WebSessionContext)\r\n        {\r\n            WebSessionContext sessionContext = (WebSessionContext) initData;\r\n            HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest();\r\n            if (request != null)\r\n            {\r\n                String userAgent = request.getHeader(\"User-Agent\");\r\n                // 获取客户端操作系统\r\n                String os = UserAgentUtils.getOperatingSystem(userAgent);\r\n                // 获取客户端浏览器\r\n                String browser = UserAgentUtils.getBrowser(userAgent);\r\n                session.setHost(IpUtils.getIpAddr(request));\r\n                session.setBrowser(browser);\r\n                session.setOs(os);\r\n            }\r\n        }\r\n        return session;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/util/AuthorizationUtils.java",
    "content": "package com.ruoyi.framework.shiro.util;\r\n\r\nimport org.apache.shiro.SecurityUtils;\r\nimport org.apache.shiro.mgt.RealmSecurityManager;\r\nimport com.ruoyi.framework.shiro.realm.UserRealm;\r\n\r\n/**\r\n * 用户授权信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class AuthorizationUtils\r\n{\r\n    /**\r\n     * 清理所有用户授权信息缓存\r\n     */\r\n    public static void clearAllCachedAuthorizationInfo()\r\n    {\r\n        getUserRealm().clearAllCachedAuthorizationInfo();\r\n    }\r\n\r\n    /**\r\n     * 获取自定义Realm\r\n     */\r\n    public static UserRealm getUserRealm()\r\n    {\r\n        RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();\r\n        return (UserRealm) rsm.getRealms().iterator().next();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/CustomShiroFilterFactoryBean.java",
    "content": "package com.ruoyi.framework.shiro.web;\r\n\r\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\r\nimport org.apache.shiro.web.filter.InvalidRequestFilter;\r\nimport org.apache.shiro.web.filter.mgt.DefaultFilter;\r\nimport org.apache.shiro.web.filter.mgt.FilterChainManager;\r\nimport org.apache.shiro.web.filter.mgt.FilterChainResolver;\r\nimport org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;\r\nimport org.apache.shiro.web.mgt.WebSecurityManager;\r\nimport org.apache.shiro.web.servlet.AbstractShiroFilter;\r\nimport org.apache.shiro.mgt.SecurityManager;\r\nimport org.springframework.beans.factory.BeanInitializationException;\r\nimport jakarta.servlet.Filter;\r\nimport java.util.Map;\r\n\r\n/**\r\n * 自定义ShiroFilterFactoryBean解决资源中文路径问题\r\n * \r\n * @author ruoyi\r\n */\r\npublic class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean\r\n{\r\n    @Override\r\n    public Class<MySpringShiroFilter> getObjectType()\r\n    {\r\n        return MySpringShiroFilter.class;\r\n    }\r\n\r\n    @Override\r\n    protected AbstractShiroFilter createInstance() throws Exception\r\n    {\r\n\r\n        SecurityManager securityManager = getSecurityManager();\r\n        if (securityManager == null)\r\n        {\r\n            String msg = \"SecurityManager property must be set.\";\r\n            throw new BeanInitializationException(msg);\r\n        }\r\n\r\n        if (!(securityManager instanceof WebSecurityManager))\r\n        {\r\n            String msg = \"The security manager does not implement the WebSecurityManager interface.\";\r\n            throw new BeanInitializationException(msg);\r\n        }\r\n\r\n        FilterChainManager manager = createFilterChainManager();\r\n        // Expose the constructed FilterChainManager by first wrapping it in a\r\n        // FilterChainResolver implementation. The AbstractShiroFilter implementations\r\n        // do not know about FilterChainManagers - only resolvers:\r\n        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();\r\n        chainResolver.setFilterChainManager(manager);\r\n\r\n        Map<String, Filter> filterMap = manager.getFilters();\r\n        Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name());\r\n        if (invalidRequestFilter instanceof InvalidRequestFilter)\r\n        {\r\n            // 此处是关键,设置false跳过URL携带中文400，servletPath中文校验bug\r\n            ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false);\r\n        }\r\n        // Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built\r\n        // FilterChainResolver. It doesn't matter that the instance is an anonymous inner class\r\n        // here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts\r\n        // injection of the SecurityManager and FilterChainResolver:\r\n        return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver);\r\n    }\r\n\r\n    private static final class MySpringShiroFilter extends AbstractShiroFilter\r\n    {\r\n        protected MySpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver)\r\n        {\r\n            if (webSecurityManager == null)\r\n            {\r\n                throw new IllegalArgumentException(\"WebSecurityManager property cannot be null.\");\r\n            }\r\n            else\r\n            {\r\n                this.setSecurityManager(webSecurityManager);\r\n                if (resolver != null)\r\n                {\r\n                    this.setFilterChainResolver(resolver);\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java",
    "content": "package com.ruoyi.framework.shiro.web.filter;\r\n\r\nimport jakarta.servlet.ServletRequest;\r\nimport jakarta.servlet.ServletResponse;\r\nimport org.apache.shiro.session.SessionException;\r\nimport org.apache.shiro.subject.Subject;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.utils.MessageUtils;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.framework.manager.AsyncManager;\r\nimport com.ruoyi.framework.manager.factory.AsyncFactory;\r\nimport com.ruoyi.system.service.ISysUserOnlineService;\r\n\r\n/**\r\n * 退出过滤器\r\n * \r\n * @author ruoyi\r\n */\r\npublic class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(LogoutFilter.class);\r\n\r\n    /**\r\n     * 退出后重定向的地址\r\n     */\r\n    private String loginUrl;\r\n\r\n    public String getLoginUrl()\r\n    {\r\n        return loginUrl;\r\n    }\r\n\r\n    public void setLoginUrl(String loginUrl)\r\n    {\r\n        this.loginUrl = loginUrl;\r\n    }\r\n\r\n    @Override\r\n    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception\r\n    {\r\n        try\r\n        {\r\n            Subject subject = getSubject(request, response);\r\n            String redirectUrl = getRedirectUrl(request, response, subject);\r\n            try\r\n            {\r\n                SysUser user = ShiroUtils.getSysUser();\r\n                if (StringUtils.isNotNull(user))\r\n                {\r\n                    String loginName = user.getLoginName();\r\n                    // 记录用户退出日志\r\n                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message(\"user.logout.success\")));\r\n                    // 清理缓存\r\n                    SpringUtils.getBean(ISysUserOnlineService.class).removeUserCache(loginName, ShiroUtils.getSessionId());\r\n                }\r\n                // 退出登录\r\n                subject.logout();\r\n            }\r\n            catch (SessionException ise)\r\n            {\r\n                log.error(\"logout fail.\", ise);\r\n            }\r\n            issueRedirect(request, response, redirectUrl);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"Encountered session exception during logout.  This can generally safely be ignored.\", e);\r\n        }\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 退出跳转URL\r\n     */\r\n    @Override\r\n    protected String getRedirectUrl(ServletRequest request, ServletResponse response, Subject subject)\r\n    {\r\n        String url = getLoginUrl();\r\n        if (StringUtils.isNotEmpty(url))\r\n        {\r\n            return url;\r\n        }\r\n        return super.getRedirectUrl(request, response, subject);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java",
    "content": "package com.ruoyi.framework.shiro.web.filter.captcha;\r\n\r\nimport jakarta.servlet.ServletRequest;\r\nimport jakarta.servlet.ServletResponse;\r\nimport jakarta.servlet.http.HttpServletRequest;\r\nimport org.apache.shiro.web.filter.AccessControlFilter;\r\nimport com.google.code.kaptcha.Constants;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 验证码过滤器\r\n * \r\n * @author ruoyi\r\n */\r\npublic class CaptchaValidateFilter extends AccessControlFilter\r\n{\r\n    /**\r\n     * 是否开启验证码\r\n     */\r\n    private boolean captchaEnabled = true;\r\n\r\n    /**\r\n     * 验证码类型\r\n     */\r\n    private String captchaType = \"math\";\r\n\r\n    public void setCaptchaEnabled(boolean captchaEnabled)\r\n    {\r\n        this.captchaEnabled = captchaEnabled;\r\n    }\r\n\r\n    public void setCaptchaType(String captchaType)\r\n    {\r\n        this.captchaType = captchaType;\r\n    }\r\n\r\n    @Override\r\n    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception\r\n    {\r\n        request.setAttribute(ShiroConstants.CURRENT_ENABLED, captchaEnabled);\r\n        request.setAttribute(ShiroConstants.CURRENT_TYPE, captchaType);\r\n        return super.onPreHandle(request, response, mappedValue);\r\n    }\r\n\r\n    @Override\r\n    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)\r\n            throws Exception\r\n    {\r\n        HttpServletRequest httpServletRequest = (HttpServletRequest) request;\r\n        // 验证码禁用 或不是表单提交 允许访问\r\n        if (captchaEnabled == false || !\"post\".equals(httpServletRequest.getMethod().toLowerCase()))\r\n        {\r\n            return true;\r\n        }\r\n        return validateResponse(httpServletRequest, httpServletRequest.getParameter(ShiroConstants.CURRENT_VALIDATECODE));\r\n    }\r\n\r\n    public boolean validateResponse(HttpServletRequest request, String validateCode)\r\n    {\r\n        Object obj = ShiroUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);\r\n        String code = String.valueOf(obj != null ? obj : \"\");\r\n        // 验证码清除，防止多次使用。\r\n        request.getSession().removeAttribute(Constants.KAPTCHA_SESSION_KEY);\r\n        if (StringUtils.isEmpty(validateCode) || !validateCode.equalsIgnoreCase(code))\r\n        {\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n\r\n    @Override\r\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception\r\n    {\r\n        request.setAttribute(ShiroConstants.CURRENT_CAPTCHA, ShiroConstants.CAPTCHA_ERROR);\r\n        return true;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/csrf/CsrfValidateFilter.java",
    "content": "package com.ruoyi.framework.shiro.web.filter.csrf;\n\nimport java.util.List;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.shiro.web.filter.AccessControlFilter;\nimport com.ruoyi.common.constant.ShiroConstants;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.common.utils.ServletUtils;\nimport com.ruoyi.common.utils.ShiroUtils;\nimport com.ruoyi.common.utils.StringUtils;\n\n/**\n * csrf过滤器\n * \n * @author ruoyi\n */\npublic class CsrfValidateFilter extends AccessControlFilter\n{\n    /**\n     * 白名单链接\n     */\n    private List<String> csrfWhites;\n\n    @Override\n    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)\n            throws Exception\n    {\n        HttpServletRequest httpServletRequest = (HttpServletRequest) request;\n        if (!isAllowMethod(httpServletRequest))\n        {\n            return true;\n        }\n        if (StringUtils.matches(httpServletRequest.getServletPath(), csrfWhites))\n        {\n            return true;\n        }\n        return validateResponse(httpServletRequest, httpServletRequest.getHeader(ShiroConstants.X_CSRF_TOKEN));\n    }\n\n    public boolean validateResponse(HttpServletRequest request, String requestToken)\n    {\n        Object obj = ShiroUtils.getSession().getAttribute(ShiroConstants.CSRF_TOKEN);\n        String sessionToken = Convert.toStr(obj, \"\");\n        if (StringUtils.isEmpty(requestToken) || !requestToken.equalsIgnoreCase(sessionToken))\n        {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception\n    {\n        ServletUtils.renderString((HttpServletResponse) response, \"{\\\"code\\\":\\\"1\\\",\\\"msg\\\":\\\"当前请求的安全验证未通过，请刷新页面后重试。\\\"}\");\n        return false;\n    }\n\n    private boolean isAllowMethod(HttpServletRequest request)\n    {\n        String method = request.getMethod();\n        return \"POST\".equalsIgnoreCase(method);\n    }\n\n    public List<String> getCsrfWhites()\n    {\n        return csrfWhites;\n    }\n\n    public void setCsrfWhites(List<String> csrfWhites)\n    {\n        this.csrfWhites = csrfWhites;\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/kickout/KickoutSessionFilter.java",
    "content": "package com.ruoyi.framework.shiro.web.filter.kickout;\n\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheManager;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.session.mgt.DefaultSessionKey;\nimport org.apache.shiro.session.mgt.SessionManager;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.web.filter.AccessControlFilter;\nimport org.apache.shiro.web.util.WebUtils;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.ruoyi.common.constant.ShiroConstants;\nimport com.ruoyi.common.core.domain.AjaxResult;\nimport com.ruoyi.common.core.domain.entity.SysUser;\nimport com.ruoyi.common.utils.ServletUtils;\nimport com.ruoyi.common.utils.ShiroUtils;\n\n/**\n * 登录账号控制过滤器\n * \n * @author ruoyi\n */\npublic class KickoutSessionFilter extends AccessControlFilter\n{\n    private final static ObjectMapper objectMapper = new ObjectMapper();\n\n    /**\n     * 同一个用户最大会话数\n     **/\n    private int maxSession = -1;\n\n    /**\n     * 踢出之前登录的/之后登录的用户 默认false踢出之前登录的用户\n     **/\n    private Boolean kickoutAfter = false;\n\n    /**\n     * 踢出后到的地址\n     **/\n    private String kickoutUrl;\n\n    private SessionManager sessionManager;\n    private Cache<String, Deque<Serializable>> cache;\n\n    @Override\n    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o)\n            throws Exception\n    {\n        return false;\n    }\n\n    @Override\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception\n    {\n        Subject subject = getSubject(request, response);\n        if (!subject.isAuthenticated() && !subject.isRemembered() || maxSession == -1)\n        {\n            // 如果没有登录或用户最大会话数为-1，直接进行之后的流程\n            return true;\n        }\n        try\n        {\n            Session session = subject.getSession();\n            // 当前登录用户\n            SysUser user = ShiroUtils.getSysUser();\n            String loginName = user.getLoginName();\n            Serializable sessionId = session.getId();\n\n            // 读取缓存用户 没有就存入\n            Deque<Serializable> deque = cache.get(loginName);\n            if (deque == null)\n            {\n                // 初始化队列\n                deque = new ArrayDeque<Serializable>();\n            }\n\n            // 如果队列里没有此sessionId，且用户没有被踢出；放入队列\n            if (!deque.contains(sessionId) && session.getAttribute(\"kickout\") == null)\n            {\n                // 将sessionId存入队列\n                deque.push(sessionId);\n                // 将用户的sessionId队列缓存\n                cache.put(loginName, deque);\n            }\n\n            // 如果队列里的sessionId数超出最大会话数，开始踢人\n            while (deque.size() > maxSession)\n            {\n                // 是否踢出后来登录的，默认是false；即后者登录的用户踢出前者登录的用户；\n                Serializable kickoutSessionId = kickoutAfter ? deque.removeFirst() : deque.removeLast();\n                // 踢出后再更新下缓存队列\n                cache.put(loginName, deque);\n\n                try\n                {\n                    // 获取被踢出的sessionId的session对象\n                    Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));\n                    if (null != kickoutSession)\n                    {\n                        // 设置会话的kickout属性表示踢出了\n                        kickoutSession.setAttribute(\"kickout\", true);\n                    }\n                }\n                catch (Exception e)\n                {\n                    // 面对异常，我们选择忽略\n                }\n            }\n\n            // 如果被踢出了，(前者或后者)直接退出，重定向到踢出后的地址\n            if (session.getAttribute(\"kickout\") != null && (Boolean) session.getAttribute(\"kickout\") == true)\n            {\n                // 退出登录\n                subject.logout();\n                saveRequest(request);\n                return isAjaxResponse(request, response);\n            }\n            return true;\n        }\n        catch (Exception e)\n        {\n            return isAjaxResponse(request, response);\n        }\n    }\n\n    private boolean isAjaxResponse(ServletRequest request, ServletResponse response) throws IOException\n    {\n        HttpServletRequest req = (HttpServletRequest) request;\n        HttpServletResponse res = (HttpServletResponse) response;\n        if (ServletUtils.isAjaxRequest(req))\n        {\n            AjaxResult ajaxResult = AjaxResult.error(\"您已在别处登录，请您修改密码或重新登录\");\n            ServletUtils.renderString(res, objectMapper.writeValueAsString(ajaxResult));\n        }\n        else\n        {\n            WebUtils.issueRedirect(request, response, kickoutUrl);\n        }\n        return false;\n    }\n\n    public void setMaxSession(int maxSession)\n    {\n        this.maxSession = maxSession;\n    }\n\n    public void setKickoutAfter(boolean kickoutAfter)\n    {\n        this.kickoutAfter = kickoutAfter;\n    }\n\n    public void setKickoutUrl(String kickoutUrl)\n    {\n        this.kickoutUrl = kickoutUrl;\n    }\n\n    public void setSessionManager(SessionManager sessionManager)\n    {\n        this.sessionManager = sessionManager;\n    }\n\n    // 设置Cache的key的前缀\n    public void setCacheManager(CacheManager cacheManager)\n    {\n        // 必须和ehcache缓存配置中的缓存name一致\n        this.cache = cacheManager.getCache(ShiroConstants.SYS_USERCACHE);\n    }\n}"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/online/OnlineSessionFilter.java",
    "content": "package com.ruoyi.framework.shiro.web.filter.online;\r\n\r\nimport java.io.IOException;\r\nimport jakarta.servlet.ServletRequest;\r\nimport jakarta.servlet.ServletResponse;\r\nimport org.apache.shiro.session.Session;\r\nimport org.apache.shiro.subject.Subject;\r\nimport org.apache.shiro.web.filter.AccessControlFilter;\r\nimport org.apache.shiro.web.util.WebUtils;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.common.enums.OnlineStatus;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.framework.shiro.session.OnlineSessionDAO;\r\n\r\n/**\r\n * 自定义访问控制\r\n * \r\n * @author ruoyi\r\n */\r\npublic class OnlineSessionFilter extends AccessControlFilter\r\n{\r\n    /**\r\n     * 强制退出后重定向的地址\r\n     */\r\n    @Value(\"${shiro.user.loginUrl}\")\r\n    private String loginUrl;\r\n\r\n    private OnlineSessionDAO onlineSessionDAO;\r\n\r\n    /**\r\n     * 表示是否允许访问；mappedValue就是[urls]配置中拦截器参数部分，如果允许访问返回true，否则false；\r\n     */\r\n    @Override\r\n    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)\r\n            throws Exception\r\n    {\r\n        Subject subject = getSubject(request, response);\r\n        if (subject == null || subject.getSession() == null)\r\n        {\r\n            return true;\r\n        }\r\n        Session session = onlineSessionDAO.readSession(subject.getSession().getId());\r\n        if (session != null && session instanceof OnlineSession)\r\n        {\r\n            OnlineSession onlineSession = (OnlineSession) session;\r\n            request.setAttribute(ShiroConstants.ONLINE_SESSION, onlineSession);\r\n            // 把user对象设置进去\r\n            boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L;\r\n            if (isGuest == true)\r\n            {\r\n                SysUser user = ShiroUtils.getSysUser();\r\n                if (user != null)\r\n                {\r\n                    onlineSession.setUserId(user.getUserId());\r\n                    onlineSession.setLoginName(user.getLoginName());\r\n                    onlineSession.setAvatar(user.getAvatar());\r\n                    onlineSession.setDeptName(user.getDept().getDeptName());\r\n                    onlineSession.markAttributeChanged();\r\n                    onlineSessionDAO.update(onlineSession);\r\n                }\r\n            }\r\n\r\n            if (onlineSession.getStatus() == OnlineStatus.off_line)\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * 表示当访问拒绝时是否已经处理了；如果返回true表示需要继续处理；如果返回false表示该拦截器实例已经处理了，将直接返回即可。\r\n     */\r\n    @Override\r\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception\r\n    {\r\n        Subject subject = getSubject(request, response);\r\n        if (subject != null)\r\n        {\r\n            subject.logout();\r\n        }\r\n        saveRequestAndRedirectToLogin(request, response);\r\n        return false;\r\n    }\r\n\r\n    // 跳转到登录页\r\n    @Override\r\n    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException\r\n    {\r\n        WebUtils.issueRedirect(request, response, loginUrl);\r\n    }\r\n\r\n    public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO)\r\n    {\r\n        this.onlineSessionDAO = onlineSessionDAO;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java",
    "content": "package com.ruoyi.framework.shiro.web.filter.sync;\r\n\r\nimport jakarta.servlet.ServletRequest;\r\nimport jakarta.servlet.ServletResponse;\r\nimport org.apache.shiro.web.filter.PathMatchingFilter;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.framework.shiro.session.OnlineSessionDAO;\r\n\r\n/**\r\n * 同步Session数据到Db\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SyncOnlineSessionFilter extends PathMatchingFilter\r\n{\r\n    private OnlineSessionDAO onlineSessionDAO;\r\n\r\n    /**\r\n     * 同步会话数据到DB 一次请求最多同步一次 防止过多处理 需要放到Shiro过滤器之前\r\n     */\r\n    @Override\r\n    protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception\r\n    {\r\n        OnlineSession session = (OnlineSession) request.getAttribute(ShiroConstants.ONLINE_SESSION);\r\n        // 如果session stop了 也不同步\r\n        // session停止时间，如果stopTimestamp不为null，则代表已停止\r\n        if (session != null && session.getUserId() != null && session.getStopTimestamp() == null)\r\n        {\r\n            onlineSessionDAO.syncToDb(session);\r\n        }\r\n        return true;\r\n    }\r\n\r\n    public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO)\r\n    {\r\n        this.onlineSessionDAO = onlineSessionDAO;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/OnlineWebSessionManager.java",
    "content": "package com.ruoyi.framework.shiro.web.session;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport org.apache.commons.lang3.time.DateUtils;\r\nimport org.apache.shiro.session.ExpiredSessionException;\r\nimport org.apache.shiro.session.InvalidSessionException;\r\nimport org.apache.shiro.session.Session;\r\nimport org.apache.shiro.session.mgt.DefaultSessionKey;\r\nimport org.apache.shiro.session.mgt.SessionKey;\r\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.bean.BeanUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.system.domain.SysUserOnline;\r\nimport com.ruoyi.system.service.ISysUserOnlineService;\r\n\r\n/**\r\n * 主要是在此如果会话的属性修改了 就标识下其修改了 然后方便 OnlineSessionDao同步\r\n * \r\n * @author ruoyi\r\n */\r\npublic class OnlineWebSessionManager extends DefaultWebSessionManager\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(OnlineWebSessionManager.class);\r\n\r\n    @Override\r\n    public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException\r\n    {\r\n        super.setAttribute(sessionKey, attributeKey, value);\r\n        if (value != null && needMarkAttributeChanged(attributeKey))\r\n        {\r\n            OnlineSession session = getOnlineSession(sessionKey);\r\n            session.markAttributeChanged();\r\n        }\r\n    }\r\n\r\n    private boolean needMarkAttributeChanged(Object attributeKey)\r\n    {\r\n        if (attributeKey == null)\r\n        {\r\n            return false;\r\n        }\r\n        String attributeKeyStr = attributeKey.toString();\r\n        // 优化 flash属性没必要持久化\r\n        if (attributeKeyStr.startsWith(\"org.springframework\"))\r\n        {\r\n            return false;\r\n        }\r\n        if (attributeKeyStr.startsWith(\"javax.servlet\") || attributeKeyStr.startsWith(\"jakarta.servlet\"))\r\n        {\r\n            return false;\r\n        }\r\n        if (attributeKeyStr.equals(ShiroConstants.CURRENT_USERNAME))\r\n        {\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n\r\n    @Override\r\n    public Object removeAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException\r\n    {\r\n        Object removed = super.removeAttribute(sessionKey, attributeKey);\r\n        if (removed != null)\r\n        {\r\n            OnlineSession s = getOnlineSession(sessionKey);\r\n            s.markAttributeChanged();\r\n        }\r\n\r\n        return removed;\r\n    }\r\n\r\n    public OnlineSession getOnlineSession(SessionKey sessionKey)\r\n    {\r\n        OnlineSession session = null;\r\n        Object obj = doGetSession(sessionKey);\r\n        if (StringUtils.isNotNull(obj))\r\n        {\r\n            session = new OnlineSession();\r\n            BeanUtils.copyBeanProp(session, obj);\r\n        }\r\n        return session;\r\n    }\r\n\r\n    /**\r\n     * 验证session是否有效 用于删除过期session\r\n     */\r\n    @Override\r\n    public void validateSessions()\r\n    {\r\n        if (log.isInfoEnabled())\r\n        {\r\n            log.info(\"invalidation sessions...\");\r\n        }\r\n\r\n        int invalidCount = 0;\r\n\r\n        int timeout = (int) this.getGlobalSessionTimeout();\r\n        if (timeout < 0)\r\n        {\r\n            // 永不过期不进行处理\r\n            return;\r\n        }\r\n        Date expiredDate = DateUtils.addMilliseconds(new Date(), 0 - timeout);\r\n        ISysUserOnlineService userOnlineService = SpringUtils.getBean(ISysUserOnlineService.class);\r\n        List<SysUserOnline> userOnlineList = userOnlineService.selectOnlineByExpired(expiredDate);\r\n        // 批量过期删除\r\n        List<String> needOfflineIdList = new ArrayList<String>();\r\n        for (SysUserOnline userOnline : userOnlineList)\r\n        {\r\n            try\r\n            {\r\n                SessionKey key = new DefaultSessionKey(userOnline.getSessionId());\r\n                Session session = retrieveSession(key);\r\n                if (session != null)\r\n                {\r\n                    throw new InvalidSessionException();\r\n                }\r\n            }\r\n            catch (InvalidSessionException e)\r\n            {\r\n                if (log.isDebugEnabled())\r\n                {\r\n                    boolean expired = (e instanceof ExpiredSessionException);\r\n                    String msg = \"Invalidated session with id [\" + userOnline.getSessionId() + \"]\"\r\n                            + (expired ? \" (expired)\" : \" (stopped)\");\r\n                    log.debug(msg);\r\n                }\r\n                invalidCount++;\r\n                needOfflineIdList.add(userOnline.getSessionId());\r\n                userOnlineService.removeUserCache(userOnline.getLoginName(), userOnline.getSessionId());\r\n            }\r\n\r\n        }\r\n        if (needOfflineIdList.size() > 0)\r\n        {\r\n            try\r\n            {\r\n                userOnlineService.batchDeleteOnline(needOfflineIdList);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                log.error(\"batch delete db session error.\", e);\r\n            }\r\n        }\r\n\r\n        if (log.isInfoEnabled())\r\n        {\r\n            String msg = \"Finished invalidation session.\";\r\n            if (invalidCount > 0)\r\n            {\r\n                msg += \" [\" + invalidCount + \"] sessions were stopped.\";\r\n            }\r\n            else\r\n            {\r\n                msg += \" No sessions were stopped.\";\r\n            }\r\n            log.info(msg);\r\n        }\r\n\r\n    }\r\n\r\n    @Override\r\n    protected Collection<Session> getActiveSessions()\r\n    {\r\n        throw new UnsupportedOperationException(\"getActiveSessions method not supported\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/SpringSessionValidationScheduler.java",
    "content": "package com.ruoyi.framework.shiro.web.session;\r\n\r\nimport java.util.concurrent.ScheduledExecutorService;\r\nimport java.util.concurrent.TimeUnit;\r\nimport org.apache.shiro.session.mgt.DefaultSessionManager;\r\nimport org.apache.shiro.session.mgt.SessionValidationScheduler;\r\nimport org.apache.shiro.session.mgt.ValidatingSessionManager;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.beans.factory.annotation.Qualifier;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.context.annotation.Lazy;\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.utils.Threads;\r\n\r\n/**\r\n * 自定义任务调度器完成\r\n * \r\n * @author ruoyi\r\n */\r\n@Component\r\npublic class SpringSessionValidationScheduler implements SessionValidationScheduler\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(SpringSessionValidationScheduler.class);\r\n\r\n    public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL;\r\n\r\n    /**\r\n     * 定时器，用于处理超时的挂起请求，也用于连接断开时的重连。\r\n     */\r\n    @Autowired\r\n    @Qualifier(\"scheduledExecutorService\")\r\n    private ScheduledExecutorService executorService;\r\n\r\n    private volatile boolean enabled = false;\r\n\r\n    /**\r\n     * 会话验证管理器\r\n     */\r\n    @Autowired\r\n    @Qualifier(\"sessionManager\")\r\n    @Lazy\r\n    private ValidatingSessionManager sessionManager;\r\n\r\n    // 相隔多久检查一次session的有效性，单位毫秒，默认就是10分钟\r\n    @Value(\"${shiro.session.validationInterval}\")\r\n    private long sessionValidationInterval;\r\n\r\n    @Override\r\n    public boolean isEnabled()\r\n    {\r\n        return this.enabled;\r\n    }\r\n\r\n    /**\r\n     * Specifies how frequently (in milliseconds) this Scheduler will call the\r\n     * {@link org.apache.shiro.session.mgt.ValidatingSessionManager#validateSessions()\r\n     * ValidatingSessionManager#validateSessions()} method.\r\n     *\r\n     * <p>\r\n     * Unless this method is called, the default value is {@link #DEFAULT_SESSION_VALIDATION_INTERVAL}.\r\n     *\r\n     * @param sessionValidationInterval\r\n     */\r\n    public void setSessionValidationInterval(long sessionValidationInterval)\r\n    {\r\n        this.sessionValidationInterval = sessionValidationInterval;\r\n    }\r\n\r\n    /**\r\n     * Starts session validation by creating a spring PeriodicTrigger.\r\n     */\r\n    @Override\r\n    public void enableSessionValidation()\r\n    {\r\n\r\n        enabled = true;\r\n\r\n        if (log.isDebugEnabled())\r\n        {\r\n            log.debug(\"Scheduling session validation job using Spring Scheduler with \"\r\n                    + \"session validation interval of [\" + sessionValidationInterval + \"]ms...\");\r\n        }\r\n\r\n        try\r\n        {\r\n            executorService.scheduleAtFixedRate(new Runnable()\r\n            {\r\n                @Override\r\n                public void run()\r\n                {\r\n                    if (enabled)\r\n                    {\r\n                        sessionManager.validateSessions();\r\n                    }\r\n                }\r\n            }, 1000, sessionValidationInterval * 60 * 1000, TimeUnit.MILLISECONDS);\r\n\r\n            this.enabled = true;\r\n\r\n            if (log.isDebugEnabled())\r\n            {\r\n                log.debug(\"Session validation job successfully scheduled with Spring Scheduler.\");\r\n            }\r\n\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            if (log.isErrorEnabled())\r\n            {\r\n                log.error(\"Error starting the Spring Scheduler session validation job.  Session validation may not occur.\", e);\r\n            }\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void disableSessionValidation()\r\n    {\r\n        if (log.isDebugEnabled())\r\n        {\r\n            log.debug(\"Stopping Spring Scheduler session validation job...\");\r\n        }\r\n\r\n        if (this.enabled)\r\n        {\r\n            Threads.shutdownAndAwaitTermination(executorService);\r\n        }\r\n        this.enabled = false;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java",
    "content": "package com.ruoyi.framework.web.domain;\r\n\r\nimport java.net.UnknownHostException;\r\nimport java.util.LinkedList;\r\nimport java.util.List;\r\nimport java.util.Properties;\r\nimport com.ruoyi.common.utils.Arith;\r\nimport com.ruoyi.common.utils.IpUtils;\r\nimport com.ruoyi.framework.web.domain.server.Cpu;\r\nimport com.ruoyi.framework.web.domain.server.Jvm;\r\nimport com.ruoyi.framework.web.domain.server.Mem;\r\nimport com.ruoyi.framework.web.domain.server.Sys;\r\nimport com.ruoyi.framework.web.domain.server.SysFile;\r\nimport oshi.SystemInfo;\r\nimport oshi.hardware.CentralProcessor;\r\nimport oshi.hardware.CentralProcessor.TickType;\r\nimport oshi.hardware.GlobalMemory;\r\nimport oshi.hardware.HardwareAbstractionLayer;\r\nimport oshi.software.os.FileSystem;\r\nimport oshi.software.os.OSFileStore;\r\nimport oshi.software.os.OperatingSystem;\r\nimport oshi.util.Util;\r\n\r\n/**\r\n * 服务器相关信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Server\r\n{\r\n    \r\n    private static final int OSHI_WAIT_SECOND = 1000;\r\n    \r\n    /**\r\n     * CPU相关信息\r\n     */\r\n    private Cpu cpu = new Cpu();\r\n\r\n    /**\r\n     * 內存相关信息\r\n     */\r\n    private Mem mem = new Mem();\r\n\r\n    /**\r\n     * JVM相关信息\r\n     */\r\n    private Jvm jvm = new Jvm();\r\n\r\n    /**\r\n     * 服务器相关信息\r\n     */\r\n    private Sys sys = new Sys();\r\n\r\n    /**\r\n     * 磁盘相关信息\r\n     */\r\n    private List<SysFile> sysFiles = new LinkedList<SysFile>();\r\n\r\n    public Cpu getCpu()\r\n    {\r\n        return cpu;\r\n    }\r\n\r\n    public void setCpu(Cpu cpu)\r\n    {\r\n        this.cpu = cpu;\r\n    }\r\n\r\n    public Mem getMem()\r\n    {\r\n        return mem;\r\n    }\r\n\r\n    public void setMem(Mem mem)\r\n    {\r\n        this.mem = mem;\r\n    }\r\n\r\n    public Jvm getJvm()\r\n    {\r\n        return jvm;\r\n    }\r\n\r\n    public void setJvm(Jvm jvm)\r\n    {\r\n        this.jvm = jvm;\r\n    }\r\n\r\n    public Sys getSys()\r\n    {\r\n        return sys;\r\n    }\r\n\r\n    public void setSys(Sys sys)\r\n    {\r\n        this.sys = sys;\r\n    }\r\n\r\n    public List<SysFile> getSysFiles()\r\n    {\r\n        return sysFiles;\r\n    }\r\n\r\n    public void setSysFiles(List<SysFile> sysFiles)\r\n    {\r\n        this.sysFiles = sysFiles;\r\n    }\r\n\r\n    public void copyTo() throws Exception\r\n    {\r\n        SystemInfo si = new SystemInfo();\r\n        HardwareAbstractionLayer hal = si.getHardware();\r\n\r\n        setCpuInfo(hal.getProcessor());\r\n\r\n        setMemInfo(hal.getMemory());\r\n\r\n        setSysInfo();\r\n\r\n        setJvmInfo();\r\n\r\n        setSysFiles(si.getOperatingSystem());\r\n    }\r\n\r\n    /**\r\n     * 设置CPU信息\r\n     */\r\n    private void setCpuInfo(CentralProcessor processor)\r\n    {\r\n        // CPU信息\r\n        long[] prevTicks = processor.getSystemCpuLoadTicks();\r\n        Util.sleep(OSHI_WAIT_SECOND);\r\n        long[] ticks = processor.getSystemCpuLoadTicks();\r\n        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];\r\n        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];\r\n        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];\r\n        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];\r\n        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];\r\n        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];\r\n        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];\r\n        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];\r\n        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;\r\n        cpu.setCpuNum(processor.getLogicalProcessorCount());\r\n        cpu.setTotal(totalCpu);\r\n        cpu.setSys(cSys);\r\n        cpu.setUsed(user);\r\n        cpu.setWait(iowait);\r\n        cpu.setFree(idle);\r\n    }\r\n\r\n    /**\r\n     * 设置内存信息\r\n     */\r\n    private void setMemInfo(GlobalMemory memory)\r\n    {\r\n        mem.setTotal(memory.getTotal());\r\n        mem.setUsed(memory.getTotal() - memory.getAvailable());\r\n        mem.setFree(memory.getAvailable());\r\n    }\r\n\r\n    /**\r\n     * 设置服务器信息\r\n     */\r\n    private void setSysInfo()\r\n    {\r\n        Properties props = System.getProperties();\r\n        sys.setComputerName(IpUtils.getHostName());\r\n        sys.setComputerIp(IpUtils.getHostIp());\r\n        sys.setOsName(props.getProperty(\"os.name\"));\r\n        sys.setOsArch(props.getProperty(\"os.arch\"));\r\n        sys.setUserDir(props.getProperty(\"user.dir\"));\r\n    }\r\n\r\n    /**\r\n     * 设置Java虚拟机\r\n     */\r\n    private void setJvmInfo() throws UnknownHostException\r\n    {\r\n        Properties props = System.getProperties();\r\n        jvm.setTotal(Runtime.getRuntime().totalMemory());\r\n        jvm.setMax(Runtime.getRuntime().maxMemory());\r\n        jvm.setFree(Runtime.getRuntime().freeMemory());\r\n        jvm.setVersion(props.getProperty(\"java.version\"));\r\n        jvm.setHome(props.getProperty(\"java.home\"));\r\n    }\r\n\r\n    /**\r\n     * 设置磁盘信息\r\n     */\r\n    private void setSysFiles(OperatingSystem os)\r\n    {\r\n        FileSystem fileSystem = os.getFileSystem();\r\n        List<OSFileStore> fsArray = fileSystem.getFileStores();\r\n        for (OSFileStore fs : fsArray)\r\n        {\r\n            long free = fs.getUsableSpace();\r\n            long total = fs.getTotalSpace();\r\n            long used = total - free;\r\n            SysFile sysFile = new SysFile();\r\n            sysFile.setDirName(fs.getMount());\r\n            sysFile.setSysTypeName(fs.getType());\r\n            sysFile.setTypeName(fs.getName());\r\n            sysFile.setTotal(convertFileSize(total));\r\n            sysFile.setFree(convertFileSize(free));\r\n            sysFile.setUsed(convertFileSize(used));\r\n            sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));\r\n            sysFiles.add(sysFile);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 字节转换\r\n     * \r\n     * @param size 字节大小\r\n     * @return 转换后值\r\n     */\r\n    public String convertFileSize(long size)\r\n    {\r\n        long kb = 1024;\r\n        long mb = kb * 1024;\r\n        long gb = mb * 1024;\r\n        if (size >= gb)\r\n        {\r\n            return String.format(\"%.1f GB\", (float) size / gb);\r\n        }\r\n        else if (size >= mb)\r\n        {\r\n            float f = (float) size / mb;\r\n            return String.format(f > 100 ? \"%.0f MB\" : \"%.1f MB\", f);\r\n        }\r\n        else if (size >= kb)\r\n        {\r\n            float f = (float) size / kb;\r\n            return String.format(f > 100 ? \"%.0f KB\" : \"%.1f KB\", f);\r\n        }\r\n        else\r\n        {\r\n            return String.format(\"%d B\", size);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java",
    "content": "package com.ruoyi.framework.web.domain.server;\r\n\r\nimport com.ruoyi.common.utils.Arith;\r\n\r\n/**\r\n * CPU相关信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Cpu\r\n{\r\n    /**\r\n     * 核心数\r\n     */\r\n    private int cpuNum;\r\n\r\n    /**\r\n     * CPU总的使用率\r\n     */\r\n    private double total;\r\n\r\n    /**\r\n     * CPU系统使用率\r\n     */\r\n    private double sys;\r\n\r\n    /**\r\n     * CPU用户使用率\r\n     */\r\n    private double used;\r\n\r\n    /**\r\n     * CPU当前等待率\r\n     */\r\n    private double wait;\r\n\r\n    /**\r\n     * CPU当前空闲率\r\n     */\r\n    private double free;\r\n\r\n    public int getCpuNum()\r\n    {\r\n        return cpuNum;\r\n    }\r\n\r\n    public void setCpuNum(int cpuNum)\r\n    {\r\n        this.cpuNum = cpuNum;\r\n    }\r\n\r\n    public double getTotal()\r\n    {\r\n        return Arith.round(Arith.mul(total, 100), 2);\r\n    }\r\n\r\n    public void setTotal(double total)\r\n    {\r\n        this.total = total;\r\n    }\r\n\r\n    public double getSys()\r\n    {\r\n        return Arith.round(Arith.mul(sys / total, 100), 2);\r\n    }\r\n\r\n    public void setSys(double sys)\r\n    {\r\n        this.sys = sys;\r\n    }\r\n\r\n    public double getUsed()\r\n    {\r\n        return Arith.round(Arith.mul(used / total, 100), 2);\r\n    }\r\n\r\n    public void setUsed(double used)\r\n    {\r\n        this.used = used;\r\n    }\r\n\r\n    public double getWait()\r\n    {\r\n        return Arith.round(Arith.mul(wait / total, 100), 2);\r\n    }\r\n\r\n    public void setWait(double wait)\r\n    {\r\n        this.wait = wait;\r\n    }\r\n\r\n    public double getFree()\r\n    {\r\n        return Arith.round(Arith.mul(free / total, 100), 2);\r\n    }\r\n\r\n    public void setFree(double free)\r\n    {\r\n        this.free = free;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java",
    "content": "package com.ruoyi.framework.web.domain.server;\r\n\r\nimport java.lang.management.ManagementFactory;\r\nimport com.ruoyi.common.utils.Arith;\r\nimport com.ruoyi.common.utils.DateUtils;\r\n\r\n/**\r\n * JVM相关信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Jvm\r\n{\r\n    /**\r\n     * 当前JVM占用的内存总数(M)\r\n     */\r\n    private double total;\r\n\r\n    /**\r\n     * JVM最大可用内存总数(M)\r\n     */\r\n    private double max;\r\n\r\n    /**\r\n     * JVM空闲内存(M)\r\n     */\r\n    private double free;\r\n\r\n    /**\r\n     * JDK版本\r\n     */\r\n    private String version;\r\n\r\n    /**\r\n     * JDK路径\r\n     */\r\n    private String home;\r\n\r\n    public double getTotal()\r\n    {\r\n        return Arith.div(total, (1024 * 1024), 2);\r\n    }\r\n\r\n    public void setTotal(double total)\r\n    {\r\n        this.total = total;\r\n    }\r\n\r\n    public double getMax()\r\n    {\r\n        return Arith.div(max, (1024 * 1024), 2);\r\n    }\r\n\r\n    public void setMax(double max)\r\n    {\r\n        this.max = max;\r\n    }\r\n\r\n    public double getFree()\r\n    {\r\n        return Arith.div(free, (1024 * 1024), 2);\r\n    }\r\n\r\n    public void setFree(double free)\r\n    {\r\n        this.free = free;\r\n    }\r\n\r\n    public double getUsed()\r\n    {\r\n        return Arith.div(total - free, (1024 * 1024), 2);\r\n    }\r\n\r\n    public double getUsage()\r\n    {\r\n        return Arith.mul(Arith.div(total - free, total, 4), 100);\r\n    }\r\n\r\n    /**\r\n     * 获取JDK名称\r\n     */\r\n    public String getName()\r\n    {\r\n        return ManagementFactory.getRuntimeMXBean().getVmName();\r\n    }\r\n\r\n    public String getVersion()\r\n    {\r\n        return version;\r\n    }\r\n\r\n    public void setVersion(String version)\r\n    {\r\n        this.version = version;\r\n    }\r\n\r\n    public String getHome()\r\n    {\r\n        return home;\r\n    }\r\n\r\n    public void setHome(String home)\r\n    {\r\n        this.home = home;\r\n    }\r\n\r\n    /**\r\n     * JDK启动时间\r\n     */\r\n    public String getStartTime()\r\n    {\r\n        return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate());\r\n    }\r\n\r\n    /**\r\n     * JDK运行时间\r\n     */\r\n    public String getRunTime()\r\n    {\r\n        return DateUtils.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate());\r\n    }\r\n\r\n    /**\r\n     * 运行参数\r\n     */\r\n    public String getInputArgs()\r\n    {\r\n        return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java",
    "content": "package com.ruoyi.framework.web.domain.server;\r\n\r\nimport com.ruoyi.common.utils.Arith;\r\n\r\n/**\r\n * 內存相关信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Mem\r\n{\r\n    /**\r\n     * 内存总量\r\n     */\r\n    private double total;\r\n\r\n    /**\r\n     * 已用内存\r\n     */\r\n    private double used;\r\n\r\n    /**\r\n     * 剩余内存\r\n     */\r\n    private double free;\r\n\r\n    public double getTotal()\r\n    {\r\n        return Arith.div(total, (1024 * 1024 * 1024), 2);\r\n    }\r\n\r\n    public void setTotal(long total)\r\n    {\r\n        this.total = total;\r\n    }\r\n\r\n    public double getUsed()\r\n    {\r\n        return Arith.div(used, (1024 * 1024 * 1024), 2);\r\n    }\r\n\r\n    public void setUsed(long used)\r\n    {\r\n        this.used = used;\r\n    }\r\n\r\n    public double getFree()\r\n    {\r\n        return Arith.div(free, (1024 * 1024 * 1024), 2);\r\n    }\r\n\r\n    public void setFree(long free)\r\n    {\r\n        this.free = free;\r\n    }\r\n\r\n    public double getUsage()\r\n    {\r\n        return Arith.mul(Arith.div(used, total, 4), 100);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java",
    "content": "package com.ruoyi.framework.web.domain.server;\r\n\r\n/**\r\n * 系统相关信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class Sys\r\n{\r\n    /**\r\n     * 服务器名称\r\n     */\r\n    private String computerName;\r\n\r\n    /**\r\n     * 服务器Ip\r\n     */\r\n    private String computerIp;\r\n\r\n    /**\r\n     * 项目路径\r\n     */\r\n    private String userDir;\r\n\r\n    /**\r\n     * 操作系统\r\n     */\r\n    private String osName;\r\n\r\n    /**\r\n     * 系统架构\r\n     */\r\n    private String osArch;\r\n\r\n    public String getComputerName()\r\n    {\r\n        return computerName;\r\n    }\r\n\r\n    public void setComputerName(String computerName)\r\n    {\r\n        this.computerName = computerName;\r\n    }\r\n\r\n    public String getComputerIp()\r\n    {\r\n        return computerIp;\r\n    }\r\n\r\n    public void setComputerIp(String computerIp)\r\n    {\r\n        this.computerIp = computerIp;\r\n    }\r\n\r\n    public String getUserDir()\r\n    {\r\n        return userDir;\r\n    }\r\n\r\n    public void setUserDir(String userDir)\r\n    {\r\n        this.userDir = userDir;\r\n    }\r\n\r\n    public String getOsName()\r\n    {\r\n        return osName;\r\n    }\r\n\r\n    public void setOsName(String osName)\r\n    {\r\n        this.osName = osName;\r\n    }\r\n\r\n    public String getOsArch()\r\n    {\r\n        return osArch;\r\n    }\r\n\r\n    public void setOsArch(String osArch)\r\n    {\r\n        this.osArch = osArch;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java",
    "content": "package com.ruoyi.framework.web.domain.server;\r\n\r\n/**\r\n * 系统文件相关信息\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysFile\r\n{\r\n    /**\r\n     * 盘符路径\r\n     */\r\n    private String dirName;\r\n\r\n    /**\r\n     * 盘符类型\r\n     */\r\n    private String sysTypeName;\r\n\r\n    /**\r\n     * 文件类型\r\n     */\r\n    private String typeName;\r\n\r\n    /**\r\n     * 总大小\r\n     */\r\n    private String total;\r\n\r\n    /**\r\n     * 剩余大小\r\n     */\r\n    private String free;\r\n\r\n    /**\r\n     * 已经使用量\r\n     */\r\n    private String used;\r\n\r\n    /**\r\n     * 资源的使用率\r\n     */\r\n    private double usage;\r\n\r\n    public String getDirName()\r\n    {\r\n        return dirName;\r\n    }\r\n\r\n    public void setDirName(String dirName)\r\n    {\r\n        this.dirName = dirName;\r\n    }\r\n\r\n    public String getSysTypeName()\r\n    {\r\n        return sysTypeName;\r\n    }\r\n\r\n    public void setSysTypeName(String sysTypeName)\r\n    {\r\n        this.sysTypeName = sysTypeName;\r\n    }\r\n\r\n    public String getTypeName()\r\n    {\r\n        return typeName;\r\n    }\r\n\r\n    public void setTypeName(String typeName)\r\n    {\r\n        this.typeName = typeName;\r\n    }\r\n\r\n    public String getTotal()\r\n    {\r\n        return total;\r\n    }\r\n\r\n    public void setTotal(String total)\r\n    {\r\n        this.total = total;\r\n    }\r\n\r\n    public String getFree()\r\n    {\r\n        return free;\r\n    }\r\n\r\n    public void setFree(String free)\r\n    {\r\n        this.free = free;\r\n    }\r\n\r\n    public String getUsed()\r\n    {\r\n        return used;\r\n    }\r\n\r\n    public void setUsed(String used)\r\n    {\r\n        this.used = used;\r\n    }\r\n\r\n    public double getUsage()\r\n    {\r\n        return usage;\r\n    }\r\n\r\n    public void setUsage(double usage)\r\n    {\r\n        this.usage = usage;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java",
    "content": "package com.ruoyi.framework.web.exception;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.apache.shiro.authz.AuthorizationException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.validation.BindException;\nimport org.springframework.web.HttpRequestMethodNotSupportedException;\nimport org.springframework.web.bind.MissingPathVariableException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\nimport org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;\nimport org.springframework.web.servlet.ModelAndView;\nimport com.ruoyi.common.core.domain.AjaxResult;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.common.exception.DemoModeException;\nimport com.ruoyi.common.exception.ServiceException;\nimport com.ruoyi.common.utils.ServletUtils;\nimport com.ruoyi.common.utils.StringUtils;\nimport com.ruoyi.common.utils.html.EscapeUtil;\nimport com.ruoyi.common.utils.security.PermissionUtils;\n\n/**\n * 全局异常处理器\n * \n * @author ruoyi\n */\n@RestControllerAdvice\npublic class GlobalExceptionHandler\n{\n    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);\n\n    /**\n     * 权限校验异常（ajax请求返回json，redirect请求跳转页面）\n     */\n    @ExceptionHandler(AuthorizationException.class)\n    public Object handleAuthorizationException(AuthorizationException e, HttpServletRequest request)\n    {\n        String requestURI = request.getRequestURI();\n        log.error(\"请求地址'{}',权限校验失败'{}'\", requestURI, e.getMessage());\n        if (ServletUtils.isAjaxRequest(request))\n        {\n            return AjaxResult.error(PermissionUtils.getMsg(e.getMessage()));\n        }\n        else\n        {\n            return new ModelAndView(\"error/unauth\");\n        }\n    }\n\n    /**\n     * 请求方式不支持\n     */\n    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)\n    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,\n            HttpServletRequest request)\n    {\n        String requestURI = request.getRequestURI();\n        log.error(\"请求地址'{}',不支持'{}'请求\", requestURI, e.getMethod());\n        return AjaxResult.error(e.getMessage());\n    }\n\n    /**\n     * 拦截未知的运行时异常\n     */\n    @ExceptionHandler(RuntimeException.class)\n    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)\n    {\n        String requestURI = request.getRequestURI();\n        log.error(\"请求地址'{}',发生未知异常.\", requestURI, e);\n        return AjaxResult.error(e.getMessage());\n    }\n\n    /**\n     * 系统异常\n     */\n    @ExceptionHandler(Exception.class)\n    public AjaxResult handleException(Exception e, HttpServletRequest request)\n    {\n        String requestURI = request.getRequestURI();\n        log.error(\"请求地址'{}',发生系统异常.\", requestURI, e);\n        return AjaxResult.error(e.getMessage());\n    }\n\n    /**\n     * 业务异常\n     */\n    @ExceptionHandler(ServiceException.class)\n    public Object handleServiceException(ServiceException e, HttpServletRequest request)\n    {\n        log.error(e.getMessage(), e);\n        if (ServletUtils.isAjaxRequest(request))\n        {\n            return AjaxResult.error(e.getMessage());\n        }\n        else\n        {\n            return new ModelAndView(\"error/service\", \"errorMessage\", e.getMessage());\n        }\n    }\n\n    /**\n     * 请求路径中缺少必需的路径变量\n     */\n    @ExceptionHandler(MissingPathVariableException.class)\n    public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)\n    {\n        String requestURI = request.getRequestURI();\n        log.error(\"请求路径中缺少必需的路径变量'{}',发生系统异常.\", requestURI, e);\n        return AjaxResult.error(String.format(\"请求路径中缺少必需的路径变量[%s]\", e.getVariableName()));\n    }\n\n    /**\n     * 请求参数类型不匹配\n     */\n    @ExceptionHandler(MethodArgumentTypeMismatchException.class)\n    public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,\n            HttpServletRequest request)\n    {\n        String requestURI = request.getRequestURI();\n        String value = Convert.toStr(e.getValue());\n        if (StringUtils.isNotEmpty(value))\n        {\n            value = EscapeUtil.clean(value);\n        }\n        log.error(\"请求参数类型不匹配'{}',发生系统异常.\", requestURI, e);\n        return AjaxResult.error(String.format(\"请求参数类型不匹配，参数[%s]要求类型为：'%s'，但输入值为：'%s'\", e.getName(), e.getRequiredType().getName(), value));\n    }\n\n    /**\n     * 自定义验证异常\n     */\n    @ExceptionHandler(BindException.class)\n    public AjaxResult handleBindException(BindException e)\n    {\n        log.error(e.getMessage(), e);\n        String message = e.getAllErrors().get(0).getDefaultMessage();\n        return AjaxResult.error(message);\n    }\n\n    /**\n     * 演示模式异常\n     */\n    @ExceptionHandler(DemoModeException.class)\n    public AjaxResult handleDemoModeException(DemoModeException e)\n    {\n        return AjaxResult.error(\"演示模式，不允许操作\");\n    }\n}\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/CacheService.java",
    "content": "package com.ruoyi.framework.web.service;\r\n\r\nimport java.util.Set;\r\nimport java.util.TreeSet;\r\nimport org.apache.commons.lang3.ArrayUtils;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.utils.CacheUtils;\r\n\r\n/**\r\n * 缓存操作处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class CacheService\r\n{\r\n    /**\r\n     * 获取所有缓存名称\r\n     * \r\n     * @return 缓存列表\r\n     */\r\n    public String[] getCacheNames()\r\n    {\r\n        String[] cacheNames = CacheUtils.getCacheNames();\r\n        return ArrayUtils.removeElement(cacheNames, Constants.SYS_AUTH_CACHE);\r\n    }\r\n\r\n    /**\r\n     * 根据缓存名称获取所有键名\r\n     * \r\n     * @param cacheName 缓存名称\r\n     * @return 键名列表\r\n     */\r\n    public Set<String> getCacheKeys(String cacheName)\r\n    {\r\n        return new TreeSet<>(CacheUtils.getCache(cacheName).keys());\r\n    }\r\n\r\n    /**\r\n     * 根据缓存名称和键名获取内容值\r\n     * \r\n     * @param cacheName 缓存名称\r\n     * @param cacheKey 键名\r\n     * @return 键值\r\n     */\r\n    public Object getCacheValue(String cacheName, String cacheKey)\r\n    {\r\n        return CacheUtils.get(cacheName, cacheKey);\r\n    }\r\n\r\n    /**\r\n     * 根据名称删除缓存信息\r\n     * \r\n     * @param cacheName 缓存名称\r\n     */\r\n    public void clearCacheName(String cacheName)\r\n    {\r\n        CacheUtils.removeAll(cacheName);\r\n    }\r\n\r\n    /**\r\n     * 根据名称和键名删除缓存信息\r\n     * \r\n     * @param cacheName 缓存名称\r\n     * @param cacheKey 键名\r\n     */\r\n    public void clearCacheKey(String cacheName, String cacheKey)\r\n    {\r\n        CacheUtils.remove(cacheName, cacheKey);\r\n    }\r\n\r\n    /**\r\n     * 清理所有缓存\r\n     */\r\n    public void clearAll()\r\n    {\r\n        String[] cacheNames = getCacheNames();\r\n        for (String cacheName : cacheNames)\r\n        {\r\n            CacheUtils.removeAll(cacheName);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/ConfigService.java",
    "content": "package com.ruoyi.framework.web.service;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.system.service.ISysConfigService;\r\n\r\n/**\r\n * RuoYi首创 html调用 thymeleaf 实现参数管理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service(\"config\")\r\npublic class ConfigService\r\n{\r\n    @Autowired\r\n    private ISysConfigService configService;\r\n\r\n    /**\r\n     * 根据键名查询参数配置信息\r\n     * \r\n     * @param configKey 参数键名\r\n     * @return 参数键值\r\n     */\r\n    public String getKey(String configKey)\r\n    {\r\n        return configService.selectConfigByKey(configKey);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/DictService.java",
    "content": "package com.ruoyi.framework.web.service;\r\n\r\nimport java.util.List;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.core.domain.entity.SysDictData;\r\nimport com.ruoyi.system.service.ISysDictDataService;\r\nimport com.ruoyi.system.service.ISysDictTypeService;\r\n\r\n/**\r\n * RuoYi首创 html调用 thymeleaf 实现字典读取\r\n * \r\n * @author ruoyi\r\n */\r\n@Service(\"dict\")\r\npublic class DictService\r\n{\r\n    @Autowired\r\n    private ISysDictTypeService dictTypeService;\r\n\r\n    @Autowired\r\n    private ISysDictDataService dictDataService;\r\n\r\n    /**\r\n     * 根据字典类型查询字典数据信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 参数键值\r\n     */\r\n    public List<SysDictData> getType(String dictType)\r\n    {\r\n        return dictTypeService.selectDictDataByType(dictType);\r\n    }\r\n\r\n    /**\r\n     * 根据字典类型和字典键值查询字典数据信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @param dictValue 字典键值\r\n     * @return 字典标签\r\n     */\r\n    public String getLabel(String dictType, String dictValue)\r\n    {\r\n        return dictDataService.selectDictLabel(dictType, dictValue);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java",
    "content": "package com.ruoyi.framework.web.service;\r\n\r\nimport java.beans.BeanInfo;\r\nimport java.beans.Introspector;\r\nimport java.beans.PropertyDescriptor;\r\nimport org.apache.shiro.SecurityUtils;\r\nimport org.apache.shiro.subject.Subject;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * RuoYi首创 js调用 thymeleaf 实现按钮权限可见性\r\n * \r\n * @author ruoyi\r\n */\r\n@Service(\"permission\")\r\npublic class PermissionService\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(PermissionService.class);\r\n\r\n    /** 没有权限，hidden用于前端隐藏按钮 */\r\n    public static final String NOACCESS = \"hidden\";\r\n\r\n    private static final String ROLE_DELIMETER = \",\";\r\n\r\n    private static final String PERMISSION_DELIMETER = \",\";\r\n\r\n    /**\r\n     * 验证用户是否具备某权限，无权限返回hidden用于前端隐藏（如需返回Boolean使用isPermitted）\r\n     * \r\n     * @param permission 权限字符串\r\n     * @return 用户是否具备某权限\r\n     */\r\n    public String hasPermi(String permission)\r\n    {\r\n        return isPermitted(permission) ? StringUtils.EMPTY : NOACCESS;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否不具备某权限，与 hasPermi逻辑相反。无权限返回hidden用于前端隐藏（如需返回Boolean使用isLacksPermitted）\r\n     *\r\n     * @param permission 权限字符串\r\n     * @return 用户是否不具备某权限\r\n     */\r\n    public String lacksPermi(String permission)\r\n    {\r\n        return isLacksPermitted(permission) ? StringUtils.EMPTY : NOACCESS;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否具有以下任意一个权限，无权限返回hidden用于隐藏（如需返回Boolean使用hasAnyPermissions）\r\n     *\r\n     * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表\r\n     * @return 用户是否具有以下任意一个权限\r\n     */\r\n    public String hasAnyPermi(String permissions)\r\n    {\r\n        return hasAnyPermissions(permissions, PERMISSION_DELIMETER) ? StringUtils.EMPTY : NOACCESS;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否具备某角色，无权限返回hidden用于隐藏（如需返回Boolean使用isRole）\r\n     * \r\n     * @param role 角色字符串\r\n     * @return 用户是否具备某角色\r\n     */\r\n    public String hasRole(String role)\r\n    {\r\n        return isRole(role) ? StringUtils.EMPTY : NOACCESS;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否不具备某角色，与hasRole逻辑相反。无权限返回hidden用于隐藏（如需返回Boolean使用isLacksRole）\r\n     * \r\n     * @param role 角色字符串\r\n     * @return 用户是否不具备某角色\r\n     */\r\n    public String lacksRole(String role)\r\n    {\r\n        return isLacksRole(role) ? StringUtils.EMPTY : NOACCESS;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否具有以下任意一个角色，无权限返回hidden用于隐藏（如需返回Boolean使用isAnyRoles）\r\n     *\r\n     * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表\r\n     * @return 用户是否具有以下任意一个角色\r\n     */\r\n    public String hasAnyRoles(String roles)\r\n    {\r\n        return isAnyRoles(roles, ROLE_DELIMETER) ? StringUtils.EMPTY : NOACCESS;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否认证通过或已记住的用户。\r\n     *\r\n     * @return 用户是否认证通过或已记住的用户\r\n     */\r\n    public boolean isUser()\r\n    {\r\n        Subject subject = SecurityUtils.getSubject();\r\n        return subject != null && subject.getPrincipal() != null;\r\n    }\r\n\r\n    /**\r\n     * 判断用户是否拥有某个权限\r\n     * \r\n     * @param permission 权限字符串\r\n     * @return 用户是否具备某权限\r\n     */\r\n    public boolean isPermitted(String permission)\r\n    {\r\n        return SecurityUtils.getSubject().isPermitted(permission);\r\n    }\r\n\r\n    /**\r\n     * 判断用户是否不具备某权限，与 isPermitted逻辑相反。\r\n     *\r\n     * @param permission 权限名称\r\n     * @return 用户是否不具备某权限\r\n     */\r\n    public boolean isLacksPermitted(String permission)\r\n    {\r\n        return isPermitted(permission) != true;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否具有以下任意一个权限。\r\n     *\r\n     * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表\r\n     * @return 用户是否具有以下任意一个权限\r\n     */\r\n    public boolean hasAnyPermissions(String permissions)\r\n    {\r\n        return hasAnyPermissions(permissions, PERMISSION_DELIMETER);\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否具有以下任意一个权限。\r\n     *\r\n     * @param permissions 以 delimeter 为分隔符的权限列表\r\n     * @param delimeter 权限列表分隔符\r\n     * @return 用户是否具有以下任意一个权限\r\n     */\r\n    public boolean hasAnyPermissions(String permissions, String delimeter)\r\n    {\r\n        Subject subject = SecurityUtils.getSubject();\r\n\r\n        if (subject != null)\r\n        {\r\n            if (delimeter == null || delimeter.length() == 0)\r\n            {\r\n                delimeter = PERMISSION_DELIMETER;\r\n            }\r\n\r\n            for (String permission : permissions.split(delimeter))\r\n            {\r\n                if (permission != null && subject.isPermitted(permission.trim()) == true)\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 判断用户是否拥有某个角色\r\n     * \r\n     * @param role 角色字符串\r\n     * @return 用户是否具备某角色\r\n     */\r\n    public boolean isRole(String role)\r\n    {\r\n        return SecurityUtils.getSubject().hasRole(role);\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否不具备某角色，与 isRole逻辑相反。\r\n     *\r\n     * @param role 角色名称\r\n     * @return 用户是否不具备某角色\r\n     */\r\n    public boolean isLacksRole(String role)\r\n    {\r\n        return isRole(role) != true;\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否具有以下任意一个角色。\r\n     *\r\n     * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表\r\n     * @return 用户是否具有以下任意一个角色\r\n     */\r\n    public boolean isAnyRoles(String roles)\r\n    {\r\n        return isAnyRoles(roles, ROLE_DELIMETER);\r\n    }\r\n\r\n    /**\r\n     * 验证用户是否具有以下任意一个角色。\r\n     *\r\n     * @param roles 以 delimeter 为分隔符的角色列表\r\n     * @param delimeter 角色列表分隔符\r\n     * @return 用户是否具有以下任意一个角色\r\n     */\r\n    public boolean isAnyRoles(String roles, String delimeter)\r\n    {\r\n        Subject subject = SecurityUtils.getSubject();\r\n        if (subject != null)\r\n        {\r\n            if (delimeter == null || delimeter.length() == 0)\r\n            {\r\n                delimeter = ROLE_DELIMETER;\r\n            }\r\n\r\n            for (String role : roles.split(delimeter))\r\n            {\r\n                if (subject.hasRole(role.trim()) == true)\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    /**\r\n     * 返回用户属性值\r\n     *\r\n     * @param property 属性名称\r\n     * @return 用户属性值\r\n     */\r\n    public Object getPrincipalProperty(String property)\r\n    {\r\n        Subject subject = SecurityUtils.getSubject();\r\n        if (subject != null)\r\n        {\r\n            Object principal = subject.getPrincipal();\r\n            try\r\n            {\r\n                BeanInfo bi = Introspector.getBeanInfo(principal.getClass());\r\n                for (PropertyDescriptor pd : bi.getPropertyDescriptors())\r\n                {\r\n                    if (pd.getName().equals(property) == true)\r\n                    {\r\n                        return pd.getReadMethod().invoke(principal, (Object[]) null);\r\n                    }\r\n                }\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                log.error(\"Error reading property [{}] from principal of type [{}]\", property, principal.getClass().getName());\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>ruoyi</artifactId>\n        <groupId>com.ruoyi</groupId>\n        <version>4.8.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>ruoyi-generator</artifactId>\n\n    <description>\n        generator代码生成\n    </description>\n\n    <dependencies>\n\n        <!-- velocity代码生成使用模板 -->\n        <dependency>\n            <groupId>org.apache.velocity</groupId>\n            <artifactId>velocity-engine-core</artifactId>\n        </dependency>\n\n        <!-- 通用工具-->\n        <dependency>\n            <groupId>com.ruoyi</groupId>\n            <artifactId>ruoyi-common</artifactId>\n        </dependency>\n\n        <!-- 阿里数据库连接池 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-4-starter</artifactId>\n        </dependency>\n\n    </dependencies>\n\n</project>"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java",
    "content": "package com.ruoyi.generator.config;\r\n\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\nimport org.springframework.context.annotation.PropertySource;\r\nimport org.springframework.stereotype.Component;\r\n\r\n/**\r\n * 读取代码生成相关配置\r\n * \r\n * @author ruoyi\r\n */\r\n@Component\r\n@ConfigurationProperties(prefix = \"gen\")\r\n@PropertySource(value = { \"classpath:generator.yml\" })\r\npublic class GenConfig\r\n{\r\n    /** 作者 */\r\n    public static String author;\r\n\r\n    /** 生成包路径 */\r\n    public static String packageName;\r\n\r\n    /** 自动去除表前缀 */\r\n    public static boolean autoRemovePre;\r\n\r\n    /** 表前缀 */\r\n    public static String tablePrefix;\r\n\r\n    /** 是否允许生成文件覆盖到本地（自定义路径） */\r\n    public static boolean allowOverwrite;\r\n\r\n    public static String getAuthor()\r\n    {\r\n        return author;\r\n    }\r\n\r\n    @Value(\"${author}\")\r\n    public void setAuthor(String author)\r\n    {\r\n        GenConfig.author = author;\r\n    }\r\n\r\n    public static String getPackageName()\r\n    {\r\n        return packageName;\r\n    }\r\n\r\n    @Value(\"${packageName}\")\r\n    public void setPackageName(String packageName)\r\n    {\r\n        GenConfig.packageName = packageName;\r\n    }\r\n\r\n    public static boolean getAutoRemovePre()\r\n    {\r\n        return autoRemovePre;\r\n    }\r\n\r\n    @Value(\"${autoRemovePre}\")\r\n    public void setAutoRemovePre(boolean autoRemovePre)\r\n    {\r\n        GenConfig.autoRemovePre = autoRemovePre;\r\n    }\r\n\r\n    public static String getTablePrefix()\r\n    {\r\n        return tablePrefix;\r\n    }\r\n\r\n    @Value(\"${tablePrefix}\")\r\n    public void setTablePrefix(String tablePrefix)\r\n    {\r\n        GenConfig.tablePrefix = tablePrefix;\r\n    }\r\n\r\n    public static boolean isAllowOverwrite()\r\n    {\r\n        return allowOverwrite;\r\n    }\r\n\r\n    @Value(\"${allowOverwrite}\")\r\n    public void setAllowOverwrite(boolean allowOverwrite)\r\n    {\r\n        GenConfig.allowOverwrite = allowOverwrite;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java",
    "content": "package com.ruoyi.generator.controller;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.apache.shiro.authz.annotation.RequiresRoles;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport com.alibaba.druid.DbType;\nimport com.alibaba.druid.sql.SQLUtils;\nimport com.alibaba.druid.sql.ast.SQLStatement;\nimport com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;\nimport com.alibaba.fastjson.JSON;\nimport com.ruoyi.common.annotation.Log;\nimport com.ruoyi.common.core.controller.BaseController;\nimport com.ruoyi.common.core.domain.AjaxResult;\nimport com.ruoyi.common.core.domain.CxSelect;\nimport com.ruoyi.common.core.page.TableDataInfo;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.common.enums.BusinessType;\nimport com.ruoyi.common.utils.StringUtils;\nimport com.ruoyi.common.utils.security.PermissionUtils;\nimport com.ruoyi.common.utils.sql.SqlUtil;\nimport com.ruoyi.generator.config.GenConfig;\nimport com.ruoyi.generator.domain.GenTable;\nimport com.ruoyi.generator.domain.GenTableColumn;\nimport com.ruoyi.generator.service.IGenTableColumnService;\nimport com.ruoyi.generator.service.IGenTableService;\n\n/**\n * 代码生成 操作处理\n * \n * @author ruoyi\n */\n@Controller\n@RequestMapping(\"/tool/gen\")\npublic class GenController extends BaseController\n{\n    private String prefix = \"tool/gen\";\n\n    @Autowired\n    private IGenTableService genTableService;\n\n    @Autowired\n    private IGenTableColumnService genTableColumnService;\n\n    @RequiresPermissions(\"tool:gen:view\")\n    @GetMapping()\n    public String gen()\n    {\n        return prefix + \"/gen\";\n    }\n\n    /**\n     * 查询代码生成列表\n     */\n    @RequiresPermissions(\"tool:gen:list\")\n    @PostMapping(\"/list\")\n    @ResponseBody\n    public TableDataInfo genList(GenTable genTable)\n    {\n        startPage();\n        List<GenTable> list = genTableService.selectGenTableList(genTable);\n        return getDataTable(list);\n    }\n\n    /**\n     * 查询数据库列表\n     */\n    @RequiresPermissions(\"tool:gen:list\")\n    @PostMapping(\"/db/list\")\n    @ResponseBody\n    public TableDataInfo dataList(GenTable genTable)\n    {\n        startPage();\n        List<GenTable> list = genTableService.selectDbTableList(genTable);\n        return getDataTable(list);\n    }\n\n    /**\n     * 查询数据表字段列表\n     */\n    @RequiresPermissions(\"tool:gen:list\")\n    @PostMapping(\"/column/list\")\n    @ResponseBody\n    public TableDataInfo columnList(GenTableColumn genTableColumn)\n    {\n        TableDataInfo dataInfo = new TableDataInfo();\n        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(genTableColumn);\n        dataInfo.setRows(list);\n        dataInfo.setTotal(list.size());\n        return dataInfo;\n    }\n\n    /**\n     * 导入表结构\n     */\n    @RequiresPermissions(\"tool:gen:list\")\n    @GetMapping(\"/importTable\")\n    public String importTable()\n    {\n        return prefix + \"/importTable\";\n    }\n\n    /**\n     * 创建表结构\n     */\n    @GetMapping(\"/createTable\")\n    public String createTable()\n    {\n        return prefix + \"/createTable\";\n    }\n\n    /**\n     * 导入表结构（保存）\n     */\n    @RequiresPermissions(\"tool:gen:list\")\n    @Log(title = \"代码生成\", businessType = BusinessType.IMPORT)\n    @PostMapping(\"/importTable\")\n    @ResponseBody\n    public AjaxResult importTableSave(String tables)\n    {\n        String[] tableNames = Convert.toStrArray(tables);\n        // 查询表信息\n        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);\n        String operName = Convert.toStr(PermissionUtils.getPrincipalProperty(\"loginName\"));\n        genTableService.importGenTable(tableList, operName);\n        return AjaxResult.success();\n    }\n\n    /**\n     * 修改代码生成业务\n     */\n    @RequiresPermissions(\"tool:gen:edit\")\n    @GetMapping(\"/edit/{tableId}\")\n    public String edit(@PathVariable(\"tableId\") Long tableId, ModelMap mmap)\n    {\n        GenTable table = genTableService.selectGenTableById(tableId);\n        List<GenTable> genTables = genTableService.selectGenTableAll();\n        List<CxSelect> cxSelect = new ArrayList<CxSelect>();\n        for (GenTable genTable : genTables)\n        {\n            if (!StringUtils.equals(table.getTableName(), genTable.getTableName()))\n            {\n                CxSelect cxTable = new CxSelect(genTable.getTableName(), genTable.getTableName() + '：' + genTable.getTableComment());\n                List<CxSelect> cxColumns = new ArrayList<CxSelect>();\n                for (GenTableColumn tableColumn : genTable.getColumns())\n                {\n                    cxColumns.add(new CxSelect(tableColumn.getColumnName(), tableColumn.getColumnName() + '：' + tableColumn.getColumnComment()));\n                }\n                cxTable.setS(cxColumns);\n                cxSelect.add(cxTable);\n            }\n        }\n        mmap.put(\"table\", table);\n        mmap.put(\"data\", JSON.toJSON(cxSelect));\n        return prefix + \"/edit\";\n    }\n\n    /**\n     * 修改保存代码生成业务\n     */\n    @RequiresPermissions(\"tool:gen:edit\")\n    @Log(title = \"代码生成\", businessType = BusinessType.UPDATE)\n    @PostMapping(\"/edit\")\n    @ResponseBody\n    public AjaxResult editSave(@Validated GenTable genTable)\n    {\n        genTableService.validateEdit(genTable);\n        genTableService.updateGenTable(genTable);\n        return AjaxResult.success();\n    }\n\n    @RequiresPermissions(\"tool:gen:remove\")\n    @Log(title = \"代码生成\", businessType = BusinessType.DELETE)\n    @PostMapping(\"/remove\")\n    @ResponseBody\n    public AjaxResult remove(String ids)\n    {\n        genTableService.deleteGenTableByIds(ids);\n        return AjaxResult.success();\n    }\n\n    @RequiresRoles(\"admin\")\n    @Log(title = \"创建表\", businessType = BusinessType.OTHER)\n    @PostMapping(\"/createTable\")\n    @ResponseBody\n    public AjaxResult create(String sql)\n    {\n        try\n        {\n            SqlUtil.filterKeyword(sql);\n            List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);\n            List<String> tableNames = new ArrayList<>();\n            for (SQLStatement sqlStatement : sqlStatements)\n            {\n                if (sqlStatement instanceof MySqlCreateTableStatement)\n                {\n                    MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;\n                    if (genTableService.createTable(createTableStatement.toString()))\n                    {\n                        String tableName = createTableStatement.getTableName().replaceAll(\"`\", \"\");\n                        tableNames.add(tableName);\n                    }\n                }\n            }\n            List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));\n            String operName = Convert.toStr(PermissionUtils.getPrincipalProperty(\"loginName\"));\n            genTableService.importGenTable(tableList, operName);\n            return AjaxResult.success();\n        }\n        catch (Exception e)\n        {\n            logger.error(e.getMessage(), e);\n            return AjaxResult.error(\"创建表结构异常\");\n        }\n    }\n\n    /**\n     * 预览代码\n     */\n    @RequiresPermissions(\"tool:gen:preview\")\n    @GetMapping(\"/preview/{tableId}\")\n    @ResponseBody\n    public AjaxResult preview(@PathVariable(\"tableId\") Long tableId) throws IOException\n    {\n        Map<String, String> dataMap = genTableService.previewCode(tableId);\n        return AjaxResult.success(dataMap);\n    }\n\n    /**\n     * 生成代码（下载方式）\n     */\n    @RequiresPermissions(\"tool:gen:code\")\n    @Log(title = \"代码生成\", businessType = BusinessType.GENCODE)\n    @GetMapping(\"/download/{tableName}\")\n    public void download(HttpServletResponse response, @PathVariable(\"tableName\") String tableName) throws IOException\n    {\n        byte[] data = genTableService.downloadCode(tableName);\n        genCode(response, data);\n    }\n\n    /**\n     * 生成代码（自定义路径）\n     */\n    @RequiresPermissions(\"tool:gen:code\")\n    @Log(title = \"代码生成\", businessType = BusinessType.GENCODE)\n    @GetMapping(\"/genCode/{tableName}\")\n    @ResponseBody\n    public AjaxResult genCode(@PathVariable(\"tableName\") String tableName)\n    {\n        if (!GenConfig.isAllowOverwrite())\n        {\n            return AjaxResult.error(\"【系统预设】不允许生成文件覆盖到本地\");\n        }\n        genTableService.generatorCode(tableName);\n        return AjaxResult.success();\n    }\n\n    /**\n     * 同步数据库\n     */\n    @RequiresPermissions(\"tool:gen:edit\")\n    @Log(title = \"代码生成\", businessType = BusinessType.UPDATE)\n    @GetMapping(\"/synchDb/{tableName}\")\n    @ResponseBody\n    public AjaxResult synchDb(@PathVariable(\"tableName\") String tableName)\n    {\n        genTableService.synchDb(tableName);\n        return AjaxResult.success();\n    }\n\n    /**\n     * 批量生成代码\n     */\n    @RequiresPermissions(\"tool:gen:code\")\n    @Log(title = \"代码生成\", businessType = BusinessType.GENCODE)\n    @GetMapping(\"/batchGenCode\")\n    @ResponseBody\n    public void batchGenCode(HttpServletResponse response, String tables) throws IOException\n    {\n        String[] tableNames = Convert.toStrArray(tables);\n        byte[] data = genTableService.downloadCode(tableNames);\n        genCode(response, data);\n    }\n\n    /**\n     * 生成zip文件\n     */\n    private void genCode(HttpServletResponse response, byte[] data) throws IOException\n    {\n        response.reset();\n        response.setHeader(\"Content-Disposition\", \"attachment; filename=\\\"ruoyi.zip\\\"\");\n        response.addHeader(\"Content-Length\", \"\" + data.length);\n        response.setContentType(\"application/octet-stream; charset=UTF-8\");\n        IOUtils.write(data, response.getOutputStream());\n    }\n}"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java",
    "content": "package com.ruoyi.generator.domain;\r\n\r\nimport java.util.List;\r\nimport jakarta.validation.Valid;\r\nimport jakarta.validation.constraints.NotBlank;\r\nimport org.apache.commons.lang3.ArrayUtils;\r\nimport com.ruoyi.common.constant.GenConstants;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 业务表 gen_table\r\n * \r\n * @author ruoyi\r\n */\r\npublic class GenTable extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 编号 */\r\n    private Long tableId;\r\n\r\n    /** 表名称 */\r\n    @NotBlank(message = \"表名称不能为空\")\r\n    private String tableName;\r\n\r\n    /** 表描述 */\r\n    @NotBlank(message = \"表描述不能为空\")\r\n    private String tableComment;\r\n\r\n    /** 关联父表的表名 */\r\n    private String subTableName;\r\n\r\n    /** 本表关联父表的外键名 */\r\n    private String subTableFkName;\r\n\r\n    /** 实体类名称(首字母大写) */\r\n    @NotBlank(message = \"实体类名称不能为空\")\r\n    private String className;\r\n\r\n    /** 使用的模板（crud单表操作 tree树表操作 sub主子表操作） */\r\n    private String tplCategory;\r\n\r\n    /** 生成包路径 */\r\n    @NotBlank(message = \"生成包路径不能为空\")\r\n    private String packageName;\r\n\r\n    /** 生成模块名 */\r\n    @NotBlank(message = \"生成模块名不能为空\")\r\n    private String moduleName;\r\n\r\n    /** 生成业务名 */\r\n    @NotBlank(message = \"生成业务名不能为空\")\r\n    private String businessName;\r\n\r\n    /** 生成功能名 */\r\n    @NotBlank(message = \"生成功能名不能为空\")\r\n    private String functionName;\r\n\r\n    /** 生成作者 */\r\n    @NotBlank(message = \"作者不能为空\")\r\n    private String functionAuthor;\r\n\r\n    /** 表单布局（单列 双列 三列） */\r\n    private int formColNum;\r\n\r\n    /** 生成代码方式（0zip压缩包 1自定义路径） */\r\n    private String genType;\r\n\r\n    /** 生成路径（不填默认项目路径） */\r\n    private String genPath;\r\n\r\n    /** 主键信息 */\r\n    private GenTableColumn pkColumn;\r\n\r\n    /** 子表信息 */\r\n    private GenTable subTable;\r\n\r\n    /** 表列信息 */\r\n    @Valid\r\n    private List<GenTableColumn> columns;\r\n\r\n    /** 其它生成选项 */\r\n    private String options;\r\n\r\n    /** 树编码字段 */\r\n    private String treeCode;\r\n\r\n    /** 树父编码字段 */\r\n    private String treeParentCode;\r\n\r\n    /** 树名称字段 */\r\n    private String treeName;\r\n\r\n    /** 上级菜单ID字段 */\r\n    private String parentMenuId;\r\n\r\n    /** 上级菜单名称字段 */\r\n    private String parentMenuName;\r\n\r\n    public Long getTableId()\r\n    {\r\n        return tableId;\r\n    }\r\n\r\n    public void setTableId(Long tableId)\r\n    {\r\n        this.tableId = tableId;\r\n    }\r\n\r\n    public String getTableName()\r\n    {\r\n        return tableName;\r\n    }\r\n\r\n    public void setTableName(String tableName)\r\n    {\r\n        this.tableName = tableName;\r\n    }\r\n\r\n    public String getTableComment()\r\n    {\r\n        return tableComment;\r\n    }\r\n\r\n    public void setTableComment(String tableComment)\r\n    {\r\n        this.tableComment = tableComment;\r\n    }\r\n\r\n    public String getSubTableName()\r\n    {\r\n        return subTableName;\r\n    }\r\n\r\n    public void setSubTableName(String subTableName)\r\n    {\r\n        this.subTableName = subTableName;\r\n    }\r\n\r\n    public String getSubTableFkName()\r\n    {\r\n        return subTableFkName;\r\n    }\r\n\r\n    public void setSubTableFkName(String subTableFkName)\r\n    {\r\n        this.subTableFkName = subTableFkName;\r\n    }\r\n\r\n    public String getClassName()\r\n    {\r\n        return className;\r\n    }\r\n\r\n    public void setClassName(String className)\r\n    {\r\n        this.className = className;\r\n    }\r\n\r\n    public String getTplCategory()\r\n    {\r\n        return tplCategory;\r\n    }\r\n\r\n    public void setTplCategory(String tplCategory)\r\n    {\r\n        this.tplCategory = tplCategory;\r\n    }\r\n\r\n    public String getPackageName()\r\n    {\r\n        return packageName;\r\n    }\r\n\r\n    public void setPackageName(String packageName)\r\n    {\r\n        this.packageName = packageName;\r\n    }\r\n\r\n    public String getModuleName()\r\n    {\r\n        return moduleName;\r\n    }\r\n\r\n    public void setModuleName(String moduleName)\r\n    {\r\n        this.moduleName = moduleName;\r\n    }\r\n\r\n    public String getBusinessName()\r\n    {\r\n        return businessName;\r\n    }\r\n\r\n    public void setBusinessName(String businessName)\r\n    {\r\n        this.businessName = businessName;\r\n    }\r\n\r\n    public String getFunctionName()\r\n    {\r\n        return functionName;\r\n    }\r\n\r\n    public void setFunctionName(String functionName)\r\n    {\r\n        this.functionName = functionName;\r\n    }\r\n\r\n    public String getFunctionAuthor()\r\n    {\r\n        return functionAuthor;\r\n    }\r\n\r\n    public void setFunctionAuthor(String functionAuthor)\r\n    {\r\n        this.functionAuthor = functionAuthor;\r\n    }\r\n\r\n    public int getFormColNum()\r\n    {\r\n        return formColNum;\r\n    }\r\n\r\n    public void setFormColNum(int formColNum)\r\n    {\r\n        this.formColNum = formColNum;\r\n    }\r\n\r\n    public String getGenType()\r\n    {\r\n        return genType;\r\n    }\r\n\r\n    public void setGenType(String genType)\r\n    {\r\n        this.genType = genType;\r\n    }\r\n\r\n    public String getGenPath()\r\n    {\r\n        return genPath;\r\n    }\r\n\r\n    public void setGenPath(String genPath)\r\n    {\r\n        this.genPath = genPath;\r\n    }\r\n\r\n    public GenTableColumn getPkColumn()\r\n    {\r\n        return pkColumn;\r\n    }\r\n\r\n    public void setPkColumn(GenTableColumn pkColumn)\r\n    {\r\n        this.pkColumn = pkColumn;\r\n    }\r\n\r\n    public GenTable getSubTable()\r\n    {\r\n        return subTable;\r\n    }\r\n\r\n    public void setSubTable(GenTable subTable)\r\n    {\r\n        this.subTable = subTable;\r\n    }\r\n\r\n    public List<GenTableColumn> getColumns()\r\n    {\r\n        return columns;\r\n    }\r\n\r\n    public void setColumns(List<GenTableColumn> columns)\r\n    {\r\n        this.columns = columns;\r\n    }\r\n\r\n    public String getOptions()\r\n    {\r\n        return options;\r\n    }\r\n\r\n    public void setOptions(String options)\r\n    {\r\n        this.options = options;\r\n    }\r\n\r\n    public String getTreeCode()\r\n    {\r\n        return treeCode;\r\n    }\r\n\r\n    public void setTreeCode(String treeCode)\r\n    {\r\n        this.treeCode = treeCode;\r\n    }\r\n\r\n    public String getTreeParentCode()\r\n    {\r\n        return treeParentCode;\r\n    }\r\n\r\n    public void setTreeParentCode(String treeParentCode)\r\n    {\r\n        this.treeParentCode = treeParentCode;\r\n    }\r\n\r\n    public String getTreeName()\r\n    {\r\n        return treeName;\r\n    }\r\n\r\n    public void setTreeName(String treeName)\r\n    {\r\n        this.treeName = treeName;\r\n    }\r\n\r\n    public String getParentMenuId()\r\n    {\r\n        return parentMenuId;\r\n    }\r\n\r\n    public void setParentMenuId(String parentMenuId)\r\n    {\r\n        this.parentMenuId = parentMenuId;\r\n    }\r\n\r\n    public String getParentMenuName()\r\n    {\r\n        return parentMenuName;\r\n    }\r\n\r\n    public void setParentMenuName(String parentMenuName)\r\n    {\r\n        this.parentMenuName = parentMenuName;\r\n    }\r\n\r\n    public boolean isSub()\r\n    {\r\n        return isSub(this.tplCategory);\r\n    }\r\n\r\n    public static boolean isSub(String tplCategory)\r\n    {\r\n        return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);\r\n    }\r\n\r\n    public boolean isTree()\r\n    {\r\n        return isTree(this.tplCategory);\r\n    }\r\n\r\n    public static boolean isTree(String tplCategory)\r\n    {\r\n        return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);\r\n    }\r\n\r\n    public boolean isCrud()\r\n    {\r\n        return isCrud(this.tplCategory);\r\n    }\r\n\r\n    public static boolean isCrud(String tplCategory)\r\n    {\r\n        return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);\r\n    }\r\n\r\n    public boolean isSuperColumn(String javaField)\r\n    {\r\n        return isSuperColumn(this.tplCategory, javaField);\r\n    }\r\n\r\n    public static boolean isSuperColumn(String tplCategory, String javaField)\r\n    {\r\n        if (isTree(tplCategory))\r\n        {\r\n            return StringUtils.equalsAnyIgnoreCase(javaField,\r\n                    ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY));\r\n        }\r\n        return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java",
    "content": "package com.ruoyi.generator.domain;\r\n\r\nimport jakarta.validation.constraints.NotBlank;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 代码生成业务字段表 gen_table_column\r\n * \r\n * @author ruoyi\r\n */\r\npublic class GenTableColumn extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 编号 */\r\n    private Long columnId;\r\n\r\n    /** 归属表编号 */\r\n    private Long tableId;\r\n\r\n    /** 列名称 */\r\n    private String columnName;\r\n\r\n    /** 列描述 */\r\n    private String columnComment;\r\n\r\n    /** 列类型 */\r\n    private String columnType;\r\n\r\n    /** JAVA类型 */\r\n    private String javaType;\r\n\r\n    /** JAVA字段名 */\r\n    @NotBlank(message = \"Java属性不能为空\")\r\n    private String javaField;\r\n\r\n    /** 是否主键（1是） */\r\n    private String isPk;\r\n\r\n    /** 是否自增（1是） */\r\n    private String isIncrement;\r\n\r\n    /** 是否必填（1是） */\r\n    private String isRequired;\r\n\r\n    /** 是否为插入字段（1是） */\r\n    private String isInsert;\r\n\r\n    /** 是否编辑字段（1是） */\r\n    private String isEdit;\r\n\r\n    /** 是否列表字段（1是） */\r\n    private String isList;\r\n\r\n    /** 是否查询字段（1是） */\r\n    private String isQuery;\r\n\r\n    /** 查询方式（EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围） */\r\n    private String queryType;\r\n\r\n    /** 显示类型（input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、upload上传控件、summernote富文本控件） */\r\n    private String htmlType;\r\n\r\n    /** 字典类型 */\r\n    private String dictType = \"\";\r\n\r\n    /** 排序 */\r\n    private Integer sort;\r\n\r\n    public void setColumnId(Long columnId)\r\n    {\r\n        this.columnId = columnId;\r\n    }\r\n\r\n    public Long getColumnId()\r\n    {\r\n        return columnId;\r\n    }\r\n\r\n    public void setTableId(Long tableId)\r\n    {\r\n        this.tableId = tableId;\r\n    }\r\n\r\n    public Long getTableId()\r\n    {\r\n        return tableId;\r\n    }\r\n\r\n    public void setColumnName(String columnName)\r\n    {\r\n        this.columnName = columnName;\r\n    }\r\n\r\n    public String getColumnName()\r\n    {\r\n        return columnName;\r\n    }\r\n\r\n    public void setColumnComment(String columnComment)\r\n    {\r\n        this.columnComment = columnComment;\r\n    }\r\n\r\n    public String getColumnComment()\r\n    {\r\n        return columnComment;\r\n    }\r\n\r\n    public void setColumnType(String columnType)\r\n    {\r\n        this.columnType = columnType;\r\n    }\r\n\r\n    public String getColumnType()\r\n    {\r\n        return columnType;\r\n    }\r\n\r\n    public void setJavaType(String javaType)\r\n    {\r\n        this.javaType = javaType;\r\n    }\r\n\r\n    public String getJavaType()\r\n    {\r\n        return javaType;\r\n    }\r\n\r\n    public void setJavaField(String javaField)\r\n    {\r\n        this.javaField = javaField;\r\n    }\r\n\r\n    public String getJavaField()\r\n    {\r\n        return javaField;\r\n    }\r\n\r\n    public String getCapJavaField()\r\n    {\r\n        return StringUtils.capitalize(javaField);\r\n    }\r\n\r\n    public void setIsPk(String isPk)\r\n    {\r\n        this.isPk = isPk;\r\n    }\r\n\r\n    public String getIsPk()\r\n    {\r\n        return isPk;\r\n    }\r\n\r\n    public boolean isPk()\r\n    {\r\n        return isPk(this.isPk);\r\n    }\r\n\r\n    public boolean isPk(String isPk)\r\n    {\r\n        return isPk != null && StringUtils.equals(\"1\", isPk);\r\n    }\r\n\r\n    public String getIsIncrement()\r\n    {\r\n        return isIncrement;\r\n    }\r\n\r\n    public void setIsIncrement(String isIncrement)\r\n    {\r\n        this.isIncrement = isIncrement;\r\n    }\r\n\r\n    public boolean isIncrement()\r\n    {\r\n        return isIncrement(this.isIncrement);\r\n    }\r\n\r\n    public boolean isIncrement(String isIncrement)\r\n    {\r\n        return isIncrement != null && StringUtils.equals(\"1\", isIncrement);\r\n    }\r\n\r\n    public void setIsRequired(String isRequired)\r\n    {\r\n        this.isRequired = isRequired;\r\n    }\r\n\r\n    public String getIsRequired()\r\n    {\r\n        return isRequired;\r\n    }\r\n\r\n    public boolean isRequired()\r\n    {\r\n        return isRequired(this.isRequired);\r\n    }\r\n\r\n    public boolean isRequired(String isRequired)\r\n    {\r\n        return isRequired != null && StringUtils.equals(\"1\", isRequired);\r\n    }\r\n\r\n    public void setIsInsert(String isInsert)\r\n    {\r\n        this.isInsert = isInsert;\r\n    }\r\n\r\n    public String getIsInsert()\r\n    {\r\n        return isInsert;\r\n    }\r\n\r\n    public boolean isInsert()\r\n    {\r\n        return isInsert(this.isInsert);\r\n    }\r\n\r\n    public boolean isInsert(String isInsert)\r\n    {\r\n        return isInsert != null && StringUtils.equals(\"1\", isInsert);\r\n    }\r\n\r\n    public void setIsEdit(String isEdit)\r\n    {\r\n        this.isEdit = isEdit;\r\n    }\r\n\r\n    public String getIsEdit()\r\n    {\r\n        return isEdit;\r\n    }\r\n\r\n    public boolean isEdit()\r\n    {\r\n        return isInsert(this.isEdit);\r\n    }\r\n\r\n    public boolean isEdit(String isEdit)\r\n    {\r\n        return isEdit != null && StringUtils.equals(\"1\", isEdit);\r\n    }\r\n\r\n    public void setIsList(String isList)\r\n    {\r\n        this.isList = isList;\r\n    }\r\n\r\n    public String getIsList()\r\n    {\r\n        return isList;\r\n    }\r\n\r\n    public boolean isList()\r\n    {\r\n        return isList(this.isList);\r\n    }\r\n\r\n    public boolean isList(String isList)\r\n    {\r\n        return isList != null && StringUtils.equals(\"1\", isList);\r\n    }\r\n\r\n    public void setIsQuery(String isQuery)\r\n    {\r\n        this.isQuery = isQuery;\r\n    }\r\n\r\n    public String getIsQuery()\r\n    {\r\n        return isQuery;\r\n    }\r\n\r\n    public boolean isQuery()\r\n    {\r\n        return isQuery(this.isQuery);\r\n    }\r\n\r\n    public boolean isQuery(String isQuery)\r\n    {\r\n        return isQuery != null && StringUtils.equals(\"1\", isQuery);\r\n    }\r\n\r\n    public void setQueryType(String queryType)\r\n    {\r\n        this.queryType = queryType;\r\n    }\r\n\r\n    public String getQueryType()\r\n    {\r\n        return queryType;\r\n    }\r\n\r\n    public String getHtmlType()\r\n    {\r\n        return htmlType;\r\n    }\r\n\r\n    public void setHtmlType(String htmlType)\r\n    {\r\n        this.htmlType = htmlType;\r\n    }\r\n\r\n    public void setDictType(String dictType)\r\n    {\r\n        this.dictType = dictType;\r\n    }\r\n\r\n    public String getDictType()\r\n    {\r\n        return dictType;\r\n    }\r\n\r\n    public void setSort(Integer sort)\r\n    {\r\n        this.sort = sort;\r\n    }\r\n\r\n    public Integer getSort()\r\n    {\r\n        return sort;\r\n    }\r\n\r\n    public boolean isSuperColumn()\r\n    {\r\n        return isSuperColumn(this.javaField);\r\n    }\r\n\r\n    public static boolean isSuperColumn(String javaField)\r\n    {\r\n        return StringUtils.equalsAnyIgnoreCase(javaField,\r\n                // BaseEntity\r\n                \"createBy\", \"createTime\", \"updateBy\", \"updateTime\", \"remark\",\r\n                // TreeEntity\r\n                \"parentName\", \"parentId\", \"orderNum\", \"ancestors\");\r\n    }\r\n\r\n    public boolean isUsableColumn()\r\n    {\r\n        return isUsableColumn(javaField);\r\n    }\r\n\r\n    public static boolean isUsableColumn(String javaField)\r\n    {\r\n        // isSuperColumn()中的名单用于避免生成多余Domain属性，若某些属性在生成页面时需要用到不能忽略，则放在此处白名单\r\n        return StringUtils.equalsAnyIgnoreCase(javaField, \"parentId\", \"orderNum\", \"remark\");\r\n    }\r\n\r\n    public String readConverterExp()\r\n    {\r\n        String remarks = StringUtils.substringBetween(this.columnComment, \"（\", \"）\");\r\n        StringBuffer sb = new StringBuffer();\r\n        if (StringUtils.isNotEmpty(remarks))\r\n        {\r\n            for (String value : remarks.split(\" \"))\r\n            {\r\n                if (StringUtils.isNotEmpty(value))\r\n                {\r\n                    Object startStr = value.subSequence(0, 1);\r\n                    String endStr = value.substring(1);\r\n                    sb.append(\"\").append(startStr).append(\"=\").append(endStr).append(\",\");\r\n                }\r\n            }\r\n            return sb.deleteCharAt(sb.length() - 1).toString();\r\n        }\r\n        else\r\n        {\r\n            return this.columnComment;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java",
    "content": "package com.ruoyi.generator.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.generator.domain.GenTableColumn;\r\n\r\n/**\r\n * 业务字段 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface GenTableColumnMapper\r\n{\r\n    /**\r\n     * 根据表名称查询列信息\r\n     * \r\n     * @param tableName 表名称\r\n     * @return 列信息\r\n     */\r\n    public List<GenTableColumn> selectDbTableColumnsByName(String tableName);\r\n\r\n    /**\r\n     * 查询业务字段列表\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 业务字段集合\r\n     */\r\n    public List<GenTableColumn> selectGenTableColumnListByTableId(GenTableColumn genTableColumn);\r\n\r\n    /**\r\n     * 新增业务字段\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 结果\r\n     */\r\n    public int insertGenTableColumn(GenTableColumn genTableColumn);\r\n\r\n    /**\r\n     * 修改业务字段\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 结果\r\n     */\r\n    public int updateGenTableColumn(GenTableColumn genTableColumn);\r\n\r\n    /**\r\n     * 删除业务字段\r\n     * \r\n     * @param genTableColumns 列数据\r\n     * @return 结果\r\n     */\r\n    public int deleteGenTableColumns(List<GenTableColumn> genTableColumns);\r\n\r\n    /**\r\n     * 批量删除业务字段\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteGenTableColumnByIds(Long[] ids);\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java",
    "content": "package com.ruoyi.generator.mapper;\n\nimport java.util.List;\nimport com.ruoyi.generator.domain.GenTable;\n\n/**\n * 业务 数据层\n * \n * @author ruoyi\n */\npublic interface GenTableMapper\n{\n    /**\n     * 查询业务列表\n     * \n     * @param genTable 业务信息\n     * @return 业务集合\n     */\n    public List<GenTable> selectGenTableList(GenTable genTable);\n\n    /**\n     * 查询据库列表\n     * \n     * @param genTable 业务信息\n     * @return 数据库表集合\n     */\n    public List<GenTable> selectDbTableList(GenTable genTable);\n\n    /**\n     * 查询据库列表\n     * \n     * @param tableNames 表名称组\n     * @return 数据库表集合\n     */\n    public List<GenTable> selectDbTableListByNames(String[] tableNames);\n\n    /**\n     * 查询所有表信息\n     * \n     * @return 表信息集合\n     */\n    public List<GenTable> selectGenTableAll();\n\n    /**\n     * 查询表ID业务信息\n     * \n     * @param id 业务ID\n     * @return 业务信息\n     */\n    public GenTable selectGenTableById(Long id);\n\n    /**\n     * 查询表名称业务信息\n     * \n     * @param tableName 表名称\n     * @return 业务信息\n     */\n    public GenTable selectGenTableByName(String tableName);\n\n    /**\n     * 新增业务\n     * \n     * @param genTable 业务信息\n     * @return 结果\n     */\n    public int insertGenTable(GenTable genTable);\n\n    /**\n     * 修改业务\n     * \n     * @param genTable 业务信息\n     * @return 结果\n     */\n    public int updateGenTable(GenTable genTable);\n\n    /**\n     * 批量删除业务\n     * \n     * @param ids 需要删除的数据ID\n     * @return 结果\n     */\n    public int deleteGenTableByIds(Long[] ids);\n\n    /**\n     * 创建表\n     *\n     * @param sql\n     * @return 结果\n     */\n    public int createTable(String sql);\n}"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java",
    "content": "package com.ruoyi.generator.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.generator.domain.GenTableColumn;\r\n\r\n/**\r\n * 业务字段 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface IGenTableColumnService\r\n{\r\n    /**\r\n     * 查询业务字段列表\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 业务字段集合\r\n     */\r\n    public List<GenTableColumn> selectGenTableColumnListByTableId(GenTableColumn genTableColumn);\r\n\r\n    /**\r\n     * 新增业务字段\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 结果\r\n     */\r\n    public int insertGenTableColumn(GenTableColumn genTableColumn);\r\n\r\n    /**\r\n     * 修改业务字段\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 结果\r\n     */\r\n    public int updateGenTableColumn(GenTableColumn genTableColumn);\r\n\r\n    /**\r\n     * 删除业务字段信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteGenTableColumnByIds(String ids);\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java",
    "content": "package com.ruoyi.generator.service;\n\nimport java.util.List;\nimport java.util.Map;\nimport com.ruoyi.generator.domain.GenTable;\n\n/**\n * 业务 服务层\n * \n * @author ruoyi\n */\npublic interface IGenTableService\n{\n    /**\n     * 查询业务列表\n     * \n     * @param genTable 业务信息\n     * @return 业务集合\n     */\n    public List<GenTable> selectGenTableList(GenTable genTable);\n\n    /**\n     * 查询据库列表\n     * \n     * @param genTable 业务信息\n     * @return 数据库表集合\n     */\n    public List<GenTable> selectDbTableList(GenTable genTable);\n\n    /**\n     * 查询据库列表\n     * \n     * @param tableNames 表名称组\n     * @return 数据库表集合\n     */\n    public List<GenTable> selectDbTableListByNames(String[] tableNames);\n\n    /**\n     * 查询所有表信息\n     * \n     * @return 表信息集合\n     */\n    public List<GenTable> selectGenTableAll();\n\n    /**\n     * 查询业务信息\n     * \n     * @param id 业务ID\n     * @return 业务信息\n     */\n    public GenTable selectGenTableById(Long id);\n\n    /**\n     * 修改业务\n     * \n     * @param genTable 业务信息\n     * @return 结果\n     */\n    public void updateGenTable(GenTable genTable);\n\n    /**\n     * 删除业务信息\n     * \n     * @param ids 需要删除的数据ID\n     * @return 结果\n     */\n    public void deleteGenTableByIds(String ids);\n\n    /**\n     * 创建表\n     *\n     * @param sql 创建表语句\n     * @return 结果\n     */\n    public boolean createTable(String sql);\n\n    /**\n     * 导入表结构\n     *\n     * @param tableList 导入表列表\n     * @param operName 操作人员\n     */\n    public void importGenTable(List<GenTable> tableList, String operName);\n\n    /**\n     * 预览代码\n     * \n     * @param tableId 表编号\n     * @return 预览数据列表\n     */\n    public Map<String, String> previewCode(Long tableId);\n\n    /**\n     * 生成代码（下载方式）\n     * \n     * @param tableName 表名称\n     * @return 数据\n     */\n    public byte[] downloadCode(String tableName);\n\n    /**\n     * 生成代码（自定义路径）\n     * \n     * @param tableName 表名称\n     */\n    public void generatorCode(String tableName);\n    \n    /**\n     * 同步数据库\n     * \n     * @param tableName 表名称\n     */\n    public void synchDb(String tableName);\n\n    /**\n     * 批量生成代码（下载方式）\n     * \n     * @param tableNames 表数组\n     * @return 数据\n     */\n    public byte[] downloadCode(String[] tableNames);\n\n    /**\n     * 修改保存参数校验\n     * \n     * @param genTable 业务信息\n     */\n    public void validateEdit(GenTable genTable);\n}\n"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableColumnServiceImpl.java",
    "content": "package com.ruoyi.generator.service.impl;\r\n\r\nimport java.util.List;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.generator.domain.GenTableColumn;\r\nimport com.ruoyi.generator.mapper.GenTableColumnMapper;\r\nimport com.ruoyi.generator.service.IGenTableColumnService;\r\n\r\n/**\r\n * 业务字段 服务层实现\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class GenTableColumnServiceImpl implements IGenTableColumnService\r\n{\r\n    @Autowired\r\n    private GenTableColumnMapper genTableColumnMapper;\r\n\r\n    /**\r\n     * 查询业务字段列表\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 业务字段集合\r\n     */\r\n    @Override\r\n    public List<GenTableColumn> selectGenTableColumnListByTableId(GenTableColumn genTableColumn)\r\n    {\r\n        return genTableColumnMapper.selectGenTableColumnListByTableId(genTableColumn);\r\n    }\r\n\r\n    /**\r\n     * 新增业务字段\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertGenTableColumn(GenTableColumn genTableColumn)\r\n    {\r\n        return genTableColumnMapper.insertGenTableColumn(genTableColumn);\r\n    }\r\n\r\n    /**\r\n     * 修改业务字段\r\n     * \r\n     * @param genTableColumn 业务字段信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int updateGenTableColumn(GenTableColumn genTableColumn)\r\n    {\r\n        return genTableColumnMapper.updateGenTableColumn(genTableColumn);\r\n    }\r\n\r\n    /**\r\n     * 删除业务字段对象\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deleteGenTableColumnByIds(String ids)\r\n    {\r\n        return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableServiceImpl.java",
    "content": "package com.ruoyi.generator.service.impl;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.velocity.Template;\nimport org.apache.velocity.VelocityContext;\nimport org.apache.velocity.app.Velocity;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.ruoyi.common.constant.Constants;\nimport com.ruoyi.common.constant.GenConstants;\nimport com.ruoyi.common.core.text.CharsetKit;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.common.exception.ServiceException;\nimport com.ruoyi.common.utils.StringUtils;\nimport com.ruoyi.generator.domain.GenTable;\nimport com.ruoyi.generator.domain.GenTableColumn;\nimport com.ruoyi.generator.mapper.GenTableColumnMapper;\nimport com.ruoyi.generator.mapper.GenTableMapper;\nimport com.ruoyi.generator.service.IGenTableService;\nimport com.ruoyi.generator.util.GenUtils;\nimport com.ruoyi.generator.util.VelocityInitializer;\nimport com.ruoyi.generator.util.VelocityUtils;\n\n/**\n * 业务 服务层实现\n * \n * @author ruoyi\n */\n@Service\npublic class GenTableServiceImpl implements IGenTableService\n{\n    private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);\n\n    @Autowired\n    private GenTableMapper genTableMapper;\n\n    @Autowired\n    private GenTableColumnMapper genTableColumnMapper;\n\n    /**\n     * 查询业务信息\n     * \n     * @param id 业务ID\n     * @return 业务信息\n     */\n    @Override\n    public GenTable selectGenTableById(Long id)\n    {\n        GenTable genTable = genTableMapper.selectGenTableById(id);\n        setTableFromOptions(genTable);\n        return genTable;\n    }\n\n    /**\n     * 查询业务列表\n     * \n     * @param genTable 业务信息\n     * @return 业务集合\n     */\n    @Override\n    public List<GenTable> selectGenTableList(GenTable genTable)\n    {\n        return genTableMapper.selectGenTableList(genTable);\n    }\n\n    /**\n     * 查询据库列表\n     * \n     * @param genTable 业务信息\n     * @return 数据库表集合\n     */\n    @Override\n    public List<GenTable> selectDbTableList(GenTable genTable)\n    {\n        return genTableMapper.selectDbTableList(genTable);\n    }\n\n    /**\n     * 查询据库列表\n     * \n     * @param tableNames 表名称组\n     * @return 数据库表集合\n     */\n    @Override\n    public List<GenTable> selectDbTableListByNames(String[] tableNames)\n    {\n        return genTableMapper.selectDbTableListByNames(tableNames);\n    }\n\n    /**\n     * 查询所有表信息\n     * \n     * @return 表信息集合\n     */\n    @Override\n    public List<GenTable> selectGenTableAll()\n    {\n        return genTableMapper.selectGenTableAll();\n    }\n\n    /**\n     * 修改业务\n     * \n     * @param genTable 业务信息\n     * @return 结果\n     */\n    @Override\n    @Transactional\n    public void updateGenTable(GenTable genTable)\n    {\n        String options = JSON.toJSONString(genTable.getParams());\n        genTable.setOptions(options);\n        int row = genTableMapper.updateGenTable(genTable);\n        if (row > 0)\n        {\n            for (GenTableColumn genTableColumn : genTable.getColumns())\n            {\n                genTableColumnMapper.updateGenTableColumn(genTableColumn);\n            }\n        }\n    }\n\n    /**\n     * 删除业务对象\n     * \n     * @param ids 需要删除的数据ID\n     * @return 结果\n     */\n    @Override\n    @Transactional\n    public void deleteGenTableByIds(String ids)\n    {\n        genTableMapper.deleteGenTableByIds(Convert.toLongArray(ids));\n        genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));\n    }\n\n    /**\n     * 创建表\n     *\n     * @param sql 创建表语句\n     * @return 结果\n     */\n    @Override\n    public boolean createTable(String sql)\n    {\n        return genTableMapper.createTable(sql) == 0;\n    }\n\n    /**\n     * 导入表结构\n     *\n     * @param tableList 导入表列表\n     * @param operName 操作人员\n     */\n    @Override\n    @Transactional\n    public void importGenTable(List<GenTable> tableList, String operName)\n    {\n        try\n        {\n            for (GenTable table : tableList)\n            {\n                String tableName = table.getTableName();\n                GenUtils.initTable(table, operName);\n                int row = genTableMapper.insertGenTable(table);\n                if (row > 0)\n                {\n                    // 保存列信息\n                    List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);\n                    for (GenTableColumn column : genTableColumns)\n                    {\n                        GenUtils.initColumnField(column, table);\n                        genTableColumnMapper.insertGenTableColumn(column);\n                    }\n                }\n            }\n        }\n        catch (Exception e)\n        {\n            throw new ServiceException(\"导入失败：\" + e.getMessage());\n        }\n    }\n\n    /**\n     * 预览代码\n     * \n     * @param tableId 表编号\n     * @return 预览数据列表\n     */\n    @Override\n    public Map<String, String> previewCode(Long tableId)\n    {\n        Map<String, String> dataMap = new LinkedHashMap<>();\n        // 查询表信息\n        GenTable table = genTableMapper.selectGenTableById(tableId);\n        // 设置主子表信息\n        setSubTable(table);\n        // 设置主键列信息\n        setPkColumn(table);\n        VelocityInitializer.initVelocity();\n\n        VelocityContext context = VelocityUtils.prepareContext(table);\n\n        // 获取模板列表\n        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());\n        for (String template : templates)\n        {\n            // 渲染模板\n            StringWriter sw = new StringWriter();\n            Template tpl = Velocity.getTemplate(template, Constants.UTF8);\n            tpl.merge(context, sw);\n            dataMap.put(template, sw.toString());\n        }\n        return dataMap;\n    }\n\n    /**\n     * 生成代码（下载方式）\n     * \n     * @param tableName 表名称\n     * @return 数据\n     */\n    @Override\n    public byte[] downloadCode(String tableName)\n    {\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        ZipOutputStream zip = new ZipOutputStream(outputStream);\n        generatorCode(tableName, zip);\n        IOUtils.closeQuietly(zip);\n        return outputStream.toByteArray();\n    }\n\n    /**\n     * 生成代码（自定义路径）\n     * \n     * @param tableName 表名称\n     */\n    @Override\n    public void generatorCode(String tableName)\n    {\n        // 查询表信息\n        GenTable table = genTableMapper.selectGenTableByName(tableName);\n        // 设置主子表信息\n        setSubTable(table);\n        // 设置主键列信息\n        setPkColumn(table);\n\n        VelocityInitializer.initVelocity();\n\n        VelocityContext context = VelocityUtils.prepareContext(table);\n\n        // 获取模板列表\n        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());\n        for (String template : templates)\n        {\n            if (!StringUtils.contains(template, \"sql.vm\"))\n            {\n                // 渲染模板\n                StringWriter sw = new StringWriter();\n                Template tpl = Velocity.getTemplate(template, Constants.UTF8);\n                tpl.merge(context, sw);\n                try\n                {\n                    String path = getGenPath(table, template);\n                    FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);\n                }\n                catch (IOException e)\n                {\n                    throw new ServiceException(\"渲染模板失败，表名：\" + table.getTableName());\n                }\n            }\n        }\n    }\n\n    /**\n     * 同步数据库\n     * \n     * @param tableName 表名称\n     */\n    @Override\n    @Transactional\n    public void synchDb(String tableName)\n    {\n        GenTable table = genTableMapper.selectGenTableByName(tableName);\n        List<GenTableColumn> tableColumns = table.getColumns();\n        Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));\n\n        List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);\n        if (StringUtils.isEmpty(dbTableColumns))\n        {\n            throw new ServiceException(\"同步数据失败，原表结构不存在\");\n        }\n        List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());\n\n        dbTableColumns.forEach(column -> {\n            GenUtils.initColumnField(column, table);\n            if (tableColumnMap.containsKey(column.getColumnName()))\n            {\n                GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());\n                column.setColumnId(prevColumn.getColumnId());\n                if (column.isList())\n                {\n                    // 如果是列表，继续保留查询方式/字典类型选项\n                    column.setDictType(prevColumn.getDictType());\n                    column.setQueryType(prevColumn.getQueryType());\n                }\n                if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()\n                        && (column.isInsert() || column.isEdit())\n                        && ((column.isUsableColumn()) || (!column.isSuperColumn())))\n                {\n                    // 如果是(新增/修改&非主键/非忽略及父属性)，继续保留必填/显示类型选项\n                    column.setIsRequired(prevColumn.getIsRequired());\n                    column.setHtmlType(prevColumn.getHtmlType());\n                }\n                genTableColumnMapper.updateGenTableColumn(column);\n            }\n            else\n            {\n                genTableColumnMapper.insertGenTableColumn(column);\n            }\n        });\n\n        List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());\n        if (StringUtils.isNotEmpty(delColumns))\n        {\n            genTableColumnMapper.deleteGenTableColumns(delColumns);\n        }\n    }\n\n    /**\n     * 批量生成代码（下载方式）\n     * \n     * @param tableNames 表数组\n     * @return 数据\n     */\n    @Override\n    public byte[] downloadCode(String[] tableNames)\n    {\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        ZipOutputStream zip = new ZipOutputStream(outputStream);\n        for (String tableName : tableNames)\n        {\n            generatorCode(tableName, zip);\n        }\n        IOUtils.closeQuietly(zip);\n        return outputStream.toByteArray();\n    }\n\n    /**\n     * 查询表信息并生成代码\n     */\n    private void generatorCode(String tableName, ZipOutputStream zip)\n    {\n        // 查询表信息\n        GenTable table = genTableMapper.selectGenTableByName(tableName);\n        // 设置主子表信息\n        setSubTable(table);\n        // 设置主键列信息\n        setPkColumn(table);\n\n        VelocityInitializer.initVelocity();\n\n        VelocityContext context = VelocityUtils.prepareContext(table);\n\n        // 获取模板列表\n        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());\n        for (String template : templates)\n        {\n            // 渲染模板\n            StringWriter sw = new StringWriter();\n            Template tpl = Velocity.getTemplate(template, Constants.UTF8);\n            tpl.merge(context, sw);\n            try\n            {\n                // 添加到zip\n                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));\n                IOUtils.write(sw.toString(), zip, Constants.UTF8);\n                IOUtils.closeQuietly(sw);\n                zip.flush();\n                zip.closeEntry();\n            }\n            catch (IOException e)\n            {\n                log.error(\"渲染模板失败，表名：\" + table.getTableName(), e);\n            }\n        }\n    }\n\n    /**\n     * 修改保存参数校验\n     * \n     * @param genTable 业务信息\n     */\n    @Override\n    public void validateEdit(GenTable genTable)\n    {\n        if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))\n        {\n            String options = JSON.toJSONString(genTable.getParams());\n            JSONObject paramsObj = JSONObject.parseObject(options);\n            if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))\n            {\n                throw new ServiceException(\"树编码字段不能为空\");\n            }\n            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE)))\n            {\n                throw new ServiceException(\"树父编码字段不能为空\");\n            }\n            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME)))\n            {\n                throw new ServiceException(\"树名称字段不能为空\");\n            }\n        }\n        else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))\n        {\n            if (StringUtils.isEmpty(genTable.getSubTableName()))\n            {\n                throw new ServiceException(\"关联子表的表名不能为空\");\n            }\n            else if (StringUtils.isEmpty(genTable.getSubTableFkName()))\n            {\n                throw new ServiceException(\"子表关联的外键名不能为空\");\n            }\n        }\n    }\n\n    /**\n     * 设置主键列信息\n     * \n     * @param table 业务表信息\n     */\n    public void setPkColumn(GenTable table)\n    {\n        for (GenTableColumn column : table.getColumns())\n        {\n            if (column.isPk())\n            {\n                table.setPkColumn(column);\n                break;\n            }\n        }\n        if (StringUtils.isNull(table.getPkColumn()))\n        {\n            table.setPkColumn(table.getColumns().get(0));\n        }\n        if (GenConstants.TPL_SUB.equals(table.getTplCategory()))\n        {\n            for (GenTableColumn column : table.getSubTable().getColumns())\n            {\n                if (column.isPk())\n                {\n                    table.getSubTable().setPkColumn(column);\n                    break;\n                }\n            }\n            if (StringUtils.isNull(table.getSubTable().getPkColumn()))\n            {\n                table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));\n            }\n        }\n    }\n\n    /**\n     * 设置主子表信息\n     * \n     * @param table 业务表信息\n     */\n    public void setSubTable(GenTable table)\n    {\n        String subTableName = table.getSubTableName();\n        if (StringUtils.isNotEmpty(subTableName))\n        {\n            table.setSubTable(genTableMapper.selectGenTableByName(subTableName));\n        }\n    }\n\n    /**\n     * 设置代码生成其他选项值\n     * \n     * @param genTable 设置后的生成对象\n     */\n    public void setTableFromOptions(GenTable genTable)\n    {\n        JSONObject paramsObj = JSONObject.parseObject(genTable.getOptions());\n        if (StringUtils.isNotNull(paramsObj))\n        {\n            String treeCode = paramsObj.getString(GenConstants.TREE_CODE);\n            String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);\n            String treeName = paramsObj.getString(GenConstants.TREE_NAME);\n            String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID);\n            String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);\n\n            genTable.setTreeCode(treeCode);\n            genTable.setTreeParentCode(treeParentCode);\n            genTable.setTreeName(treeName);\n            genTable.setParentMenuId(parentMenuId);\n            genTable.setParentMenuName(parentMenuName);\n        }\n    }\n\n    /**\n     * 获取代码生成地址\n     * \n     * @param table 业务表信息\n     * @param template 模板文件路径\n     * @return 生成地址\n     */\n    public static String getGenPath(GenTable table, String template)\n    {\n        String genPath = table.getGenPath();\n        if (StringUtils.equals(genPath, \"/\"))\n        {\n            return System.getProperty(\"user.dir\") + File.separator + \"src\" + File.separator + VelocityUtils.getFileName(template, table);\n        }\n        return genPath + File.separator + VelocityUtils.getFileName(template, table);\n    }\n}"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java",
    "content": "package com.ruoyi.generator.util;\r\n\r\nimport java.util.Arrays;\r\nimport org.apache.commons.lang3.RegExUtils;\r\nimport com.ruoyi.common.constant.GenConstants;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.generator.config.GenConfig;\r\nimport com.ruoyi.generator.domain.GenTable;\r\nimport com.ruoyi.generator.domain.GenTableColumn;\r\n\r\n/**\r\n * 代码生成器 工具类\r\n * \r\n * @author ruoyi\r\n */\r\npublic class GenUtils\r\n{\r\n    /**\r\n     * 初始化表信息\r\n     */\r\n    public static void initTable(GenTable genTable, String operName)\r\n    {\r\n        genTable.setClassName(convertClassName(genTable.getTableName()));\r\n        genTable.setPackageName(GenConfig.getPackageName());\r\n        genTable.setModuleName(getModuleName(GenConfig.getPackageName()));\r\n        genTable.setBusinessName(getBusinessName(genTable.getTableName()));\r\n        genTable.setFunctionName(replaceText(genTable.getTableComment()));\r\n        genTable.setFunctionAuthor(GenConfig.getAuthor());\r\n        genTable.setCreateBy(operName);\r\n    }\r\n\r\n    /**\r\n     * 初始化列属性字段\r\n     */\r\n    public static void initColumnField(GenTableColumn column, GenTable table)\r\n    {\r\n        String dataType = getDbType(column.getColumnType());\r\n        String columnName = column.getColumnName();\r\n        column.setTableId(table.getTableId());\r\n        column.setCreateBy(table.getCreateBy());\r\n        // 设置java字段名\r\n        column.setJavaField(StringUtils.toCamelCase(columnName));\r\n        // 设置默认类型\r\n        column.setJavaType(GenConstants.TYPE_STRING);\r\n        column.setQueryType(GenConstants.QUERY_EQ);\r\n\r\n        if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))\r\n        {\r\n            // 字符串长度超过500设置为文本域\r\n            Integer columnLength = getColumnLength(column.getColumnType());\r\n            String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;\r\n            column.setHtmlType(htmlType);\r\n        }\r\n        else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType))\r\n        {\r\n            column.setJavaType(GenConstants.TYPE_DATE);\r\n            column.setHtmlType(GenConstants.HTML_DATETIME);\r\n        }\r\n        else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType))\r\n        {\r\n            column.setHtmlType(GenConstants.HTML_INPUT);\r\n\r\n            // 如果是浮点型 统一用BigDecimal\r\n            String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), \"(\", \")\"), \",\");\r\n            if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)\r\n            {\r\n                column.setJavaType(GenConstants.TYPE_BIGDECIMAL);\r\n            }\r\n            // 如果是整形\r\n            else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)\r\n            {\r\n                column.setJavaType(GenConstants.TYPE_INTEGER);\r\n            }\r\n            // 长整形\r\n            else\r\n            {\r\n                column.setJavaType(GenConstants.TYPE_LONG);\r\n            }\r\n        }\r\n\r\n        // 插入字段（默认所有字段都需要插入）\r\n        column.setIsInsert(GenConstants.REQUIRE);\r\n\r\n        // 编辑字段\r\n        if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk())\r\n        {\r\n            column.setIsEdit(GenConstants.REQUIRE);\r\n        }\r\n        // 列表字段\r\n        if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk())\r\n        {\r\n            column.setIsList(GenConstants.REQUIRE);\r\n        }\r\n        // 查询字段\r\n        if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk())\r\n        {\r\n            column.setIsQuery(GenConstants.REQUIRE);\r\n        }\r\n\r\n        // 查询字段类型\r\n        if (StringUtils.endsWithIgnoreCase(columnName, \"name\"))\r\n        {\r\n            column.setQueryType(GenConstants.QUERY_LIKE);\r\n        }\r\n        // 状态字段设置单选框\r\n        if (StringUtils.endsWithIgnoreCase(columnName, \"status\"))\r\n        {\r\n            column.setHtmlType(GenConstants.HTML_RADIO);\r\n        }\r\n        // 类型&性别字段设置下拉框\r\n        else if (StringUtils.endsWithIgnoreCase(columnName, \"type\")\r\n                || StringUtils.endsWithIgnoreCase(columnName, \"sex\"))\r\n        {\r\n            column.setHtmlType(GenConstants.HTML_SELECT);\r\n        }\r\n        // 文件字段设置上传控件\r\n        else if (StringUtils.endsWithIgnoreCase(columnName, \"file\"))\r\n        {\r\n            column.setHtmlType(GenConstants.HTML_UPLOAD);\r\n        }\r\n        // 内容字段设置富文本控件\r\n        else if (StringUtils.endsWithIgnoreCase(columnName, \"content\"))\r\n        {\r\n            column.setHtmlType(GenConstants.HTML_SUMMERNOTE);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 校验数组是否包含指定值\r\n     * \r\n     * @param arr 数组\r\n     * @param targetValue 值\r\n     * @return 是否包含\r\n     */\r\n    public static boolean arraysContains(String[] arr, String targetValue)\r\n    {\r\n        return Arrays.asList(arr).contains(targetValue);\r\n    }\r\n\r\n    /**\r\n     * 获取模块名\r\n     * \r\n     * @param packageName 包名\r\n     * @return 模块名\r\n     */\r\n    public static String getModuleName(String packageName)\r\n    {\r\n        int lastIndex = packageName.lastIndexOf(\".\");\r\n        int nameLength = packageName.length();\r\n        return StringUtils.substring(packageName, lastIndex + 1, nameLength);\r\n    }\r\n\r\n    /**\r\n     * 获取业务名\r\n     * \r\n     * @param tableName 表名\r\n     * @return 业务名\r\n     */\r\n    public static String getBusinessName(String tableName)\r\n    {\r\n        int lastIndex = tableName.lastIndexOf(\"_\");\r\n        int nameLength = tableName.length();\r\n        return StringUtils.substring(tableName, lastIndex + 1, nameLength);\r\n    }\r\n\r\n    /**\r\n     * 表名转换成Java类名\r\n     * \r\n     * @param tableName 表名称\r\n     * @return 类名\r\n     */\r\n    public static String convertClassName(String tableName)\r\n    {\r\n        boolean autoRemovePre = GenConfig.getAutoRemovePre();\r\n        String tablePrefix = GenConfig.getTablePrefix();\r\n        if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))\r\n        {\r\n            String[] searchList = StringUtils.split(tablePrefix, \",\");\r\n            tableName = replaceFirst(tableName, searchList);\r\n        }\r\n        return StringUtils.convertToCamelCase(tableName);\r\n    }\r\n\r\n    /**\r\n     * 批量替换前缀\r\n     * \r\n     * @param replacementm 替换值\r\n     * @param searchList 替换列表\r\n     * @return\r\n     */\r\n    public static String replaceFirst(String replacementm, String[] searchList)\r\n    {\r\n        String text = replacementm;\r\n        for (String searchString : searchList)\r\n        {\r\n            if (replacementm.startsWith(searchString))\r\n            {\r\n                text = replacementm.replaceFirst(searchString, \"\");\r\n                break;\r\n            }\r\n        }\r\n        return text;\r\n    }\r\n\r\n    /**\r\n     * 关键字替换\r\n     * \r\n     * @param text 需要被替换的名字\r\n     * @return 替换后的名字\r\n     */\r\n    public static String replaceText(String text)\r\n    {\r\n        return RegExUtils.replaceAll(text, \"(?:表|若依)\", \"\");\r\n    }\r\n\r\n    /**\r\n     * 获取数据库类型字段\r\n     * \r\n     * @param columnType 列类型\r\n     * @return 截取后的列类型\r\n     */\r\n    public static String getDbType(String columnType)\r\n    {\r\n        if (StringUtils.indexOf(columnType, \"(\") > 0)\r\n        {\r\n            return StringUtils.substringBefore(columnType, \"(\");\r\n        }\r\n        else\r\n        {\r\n            return columnType;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取字段长度\r\n     * \r\n     * @param columnType 列类型\r\n     * @return 截取后的列类型\r\n     */\r\n    public static Integer getColumnLength(String columnType)\r\n    {\r\n        if (StringUtils.indexOf(columnType, \"(\") > 0)\r\n        {\r\n            String length = StringUtils.substringBetween(columnType, \"(\", \")\");\r\n            return Integer.valueOf(length);\r\n        }\r\n        else\r\n        {\r\n            return 0;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java",
    "content": "package com.ruoyi.generator.util;\r\n\r\nimport java.util.Properties;\r\nimport org.apache.velocity.app.Velocity;\r\nimport com.ruoyi.common.constant.Constants;\r\n\r\n/**\r\n * VelocityEngine工厂\r\n * \r\n * @author ruoyi\r\n */\r\npublic class VelocityInitializer\r\n{\r\n    /**\r\n     * 初始化vm方法\r\n     */\r\n    public static void initVelocity()\r\n    {\r\n        Properties p = new Properties();\r\n        try\r\n        {\r\n            // 加载classpath目录下的vm文件\r\n            p.setProperty(\"resource.loader.file.class\", \"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader\");\r\n            // 定义字符集\r\n            p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);\r\n            // 初始化Velocity引擎，指定配置Properties\r\n            Velocity.init(p);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new RuntimeException(e);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java",
    "content": "package com.ruoyi.generator.util;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport org.apache.velocity.VelocityContext;\nimport com.alibaba.fastjson.JSONObject;\nimport com.ruoyi.common.constant.GenConstants;\nimport com.ruoyi.common.utils.DateUtils;\nimport com.ruoyi.common.utils.StringUtils;\nimport com.ruoyi.generator.config.GenConfig;\nimport com.ruoyi.generator.domain.GenTable;\nimport com.ruoyi.generator.domain.GenTableColumn;\n\npublic class VelocityUtils\n{\n    /** 项目空间路径 */\n    private static final String PROJECT_PATH = \"main/java\";\n\n    /** mybatis空间路径 */\n    private static final String MYBATIS_PATH = \"main/resources/mapper\";\n\n    /** html空间路径 */\n    private static final String TEMPLATES_PATH = \"main/resources/templates\";\n    \n    /** 默认上级菜单，系统工具 */\n    private static final String DEFAULT_PARENT_MENU_ID = \"3\";\n\n    /**\n     * 设置模板变量信息\n     * \n     * @return 模板列表\n     */\n    public static VelocityContext prepareContext(GenTable genTable)\n    {\n        String moduleName = genTable.getModuleName();\n        String businessName = genTable.getBusinessName();\n        String packageName = genTable.getPackageName();\n        String tplCategory = genTable.getTplCategory();\n        String functionName = genTable.getFunctionName();\n\n        VelocityContext velocityContext = new VelocityContext();\n        velocityContext.put(\"tplCategory\", genTable.getTplCategory());\n        velocityContext.put(\"tableName\", genTable.getTableName());\n        velocityContext.put(\"functionName\", StringUtils.isNotEmpty(functionName) ? functionName : \"【请填写功能名称】\");\n        velocityContext.put(\"ClassName\", genTable.getClassName());\n        velocityContext.put(\"className\", StringUtils.uncapitalize(genTable.getClassName()));\n        velocityContext.put(\"moduleName\", genTable.getModuleName());\n        velocityContext.put(\"businessName\", genTable.getBusinessName());\n        velocityContext.put(\"basePackage\", getPackagePrefix(packageName));\n        velocityContext.put(\"packageName\", packageName);\n        velocityContext.put(\"author\", genTable.getFunctionAuthor());\n        velocityContext.put(\"colXsNum\", getColXsNum(genTable.getFormColNum()));\n        velocityContext.put(\"colSmNum\", getColSmNum(genTable.getFormColNum()));\n        velocityContext.put(\"datetime\", DateUtils.getDate());\n        velocityContext.put(\"pkColumn\", genTable.getPkColumn());\n        velocityContext.put(\"importList\", getImportList(genTable));\n        velocityContext.put(\"permissionPrefix\", getPermissionPrefix(moduleName, businessName));\n        velocityContext.put(\"columns\", genTable.getColumns());\n        velocityContext.put(\"table\", genTable);\n        setMenuVelocityContext(velocityContext, genTable);\n        if (GenConstants.TPL_TREE.equals(tplCategory))\n        {\n            setTreeVelocityContext(velocityContext, genTable);\n        }\n        if (GenConstants.TPL_SUB.equals(tplCategory))\n        {\n            setSubVelocityContext(velocityContext, genTable);\n        }\n        return velocityContext;\n    }\n\n    public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)\n    {\n        String options = genTable.getOptions();\n        JSONObject paramsObj = JSONObject.parseObject(options);\n        String parentMenuId = getParentMenuId(paramsObj);\n        context.put(\"parentMenuId\", parentMenuId);\n    }\n\n    public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)\n    {\n        String options = genTable.getOptions();\n        JSONObject paramsObj = JSONObject.parseObject(options);\n        String treeCode = getTreecode(paramsObj);\n        String treeParentCode = getTreeParentCode(paramsObj);\n        String treeName = getTreeName(paramsObj);\n\n        context.put(\"treeCode\", treeCode);\n        context.put(\"treeParentCode\", treeParentCode);\n        context.put(\"treeName\", treeName);\n        context.put(\"expandColumn\", getExpandColumn(genTable));\n        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))\n        {\n            context.put(\"tree_parent_code\", paramsObj.getString(GenConstants.TREE_PARENT_CODE));\n        }\n        if (paramsObj.containsKey(GenConstants.TREE_NAME))\n        {\n            context.put(\"tree_name\", paramsObj.getString(GenConstants.TREE_NAME));\n        }\n    }\n\n    public static void setSubVelocityContext(VelocityContext context, GenTable genTable)\n    {\n        GenTable subTable = genTable.getSubTable();\n        String subTableName = genTable.getSubTableName();\n        String subTableFkName = genTable.getSubTableFkName();\n        String subClassName = genTable.getSubTable().getClassName();\n        String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);\n\n        context.put(\"subTable\", subTable);\n        context.put(\"subTableName\", subTableName);\n        context.put(\"subTableFkName\", subTableFkName);\n        context.put(\"subTableFkClassName\", subTableFkClassName);\n        context.put(\"subTableFkclassName\", StringUtils.uncapitalize(subTableFkClassName));\n        context.put(\"subClassName\", subClassName);\n        context.put(\"subclassName\", StringUtils.uncapitalize(subClassName));\n        context.put(\"subImportList\", getImportList(genTable.getSubTable()));\n    }\n\n    /**\n     * 获取模板信息\n     * \n     * @return 模板列表\n     */\n    public static List<String> getTemplateList(String tplCategory)\n    {\n        List<String> templates = new ArrayList<String>();\n        templates.add(\"vm/java/domain.java.vm\");\n        templates.add(\"vm/java/mapper.java.vm\");\n        templates.add(\"vm/java/service.java.vm\");\n        templates.add(\"vm/java/serviceImpl.java.vm\");\n        templates.add(\"vm/java/controller.java.vm\");\n        templates.add(\"vm/xml/mapper.xml.vm\");\n        if (GenConstants.TPL_CRUD.equals(tplCategory))\n        {\n            templates.add(\"vm/html/list.html.vm\");\n        }\n        else if (GenConstants.TPL_TREE.equals(tplCategory))\n        {\n            templates.add(\"vm/html/tree.html.vm\");\n            templates.add(\"vm/html/list-tree.html.vm\");\n        }\n        else if (GenConstants.TPL_SUB.equals(tplCategory))\n        {\n            templates.add(\"vm/html/list.html.vm\");\n            templates.add(\"vm/java/sub-domain.java.vm\");\n        }\n        templates.add(\"vm/html/add.html.vm\");\n        templates.add(\"vm/html/edit.html.vm\");\n        templates.add(\"vm/sql/sql.vm\");\n        return templates;\n    }\n\n    /**\n     * 获取文件名\n     */\n    public static String getFileName(String template, GenTable genTable)\n    {\n        // 文件名称\n        String fileName = \"\";\n        // 包路径\n        String packageName = genTable.getPackageName();\n        // 模块名\n        String moduleName = genTable.getModuleName();\n        // 大写类名\n        String className = genTable.getClassName();\n        // 业务名称\n        String businessName = genTable.getBusinessName();\n\n        String javaPath = PROJECT_PATH + \"/\" + StringUtils.replace(packageName, \".\", \"/\");\n        String mybatisPath = MYBATIS_PATH + \"/\" + moduleName;\n        String htmlPath = TEMPLATES_PATH + \"/\" + moduleName + \"/\" + businessName;\n\n        if (template.contains(\"domain.java.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/domain/{}.java\", javaPath, className);\n        }\n        if (template.contains(\"sub-domain.java.vm\") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))\n        {\n            fileName = StringUtils.format(\"{}/domain/{}.java\", javaPath, genTable.getSubTable().getClassName());\n        }\n        else if (template.contains(\"mapper.java.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/mapper/{}Mapper.java\", javaPath, className);\n        }\n        else if (template.contains(\"service.java.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/service/I{}Service.java\", javaPath, className);\n        }\n        else if (template.contains(\"serviceImpl.java.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/service/impl/{}ServiceImpl.java\", javaPath, className);\n        }\n        else if (template.contains(\"controller.java.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/controller/{}Controller.java\", javaPath, className);\n        }\n        else if (template.contains(\"mapper.xml.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/{}Mapper.xml\", mybatisPath, className);\n        }\n        else if (template.contains(\"list.html.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/{}.html\", htmlPath, businessName);\n        }\n        else if (template.contains(\"list-tree.html.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/{}.html\", htmlPath, businessName);\n        }\n        else if (template.contains(\"tree.html.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/tree.html\", htmlPath);\n        }\n        else if (template.contains(\"add.html.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/add.html\", htmlPath);\n        }\n        else if (template.contains(\"edit.html.vm\"))\n        {\n            fileName = StringUtils.format(\"{}/edit.html\", htmlPath);\n        }\n        else if (template.contains(\"sql.vm\"))\n        {\n            fileName = businessName + \"Menu.sql\";\n        }\n        return fileName;\n    }\n\n    /**\n     * 获取项目文件路径\n     * \n     * @return 路径\n     */\n    public static String getProjectPath()\n    {\n        String packageName = GenConfig.getPackageName();\n        StringBuffer projectPath = new StringBuffer();\n        projectPath.append(\"main/java/\");\n        projectPath.append(packageName.replace(\".\", \"/\"));\n        projectPath.append(\"/\");\n        return projectPath.toString();\n    }\n\n    /**\n     * 获取包前缀\n     * \n     * @param packageName 包名称\n     * @return 包前缀名称\n     */\n    public static String getPackagePrefix(String packageName)\n    {\n        int lastIndex = packageName.lastIndexOf(\".\");\n        return StringUtils.substring(packageName, 0, lastIndex);\n    }\n\n    /**\n     * 根据列类型获取导入包\n     * \n     * @param genTable 业务表对象\n     * @return 返回需要导入的包列表\n     */\n    public static HashSet<String> getImportList(GenTable genTable)\n    {\n        List<GenTableColumn> columns = genTable.getColumns();\n        GenTable subGenTable = genTable.getSubTable();\n        HashSet<String> importList = new HashSet<String>();\n        if (StringUtils.isNotNull(subGenTable))\n        {\n            importList.add(\"java.util.List\");\n        }\n        for (GenTableColumn column : columns)\n        {\n            if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType()))\n            {\n                importList.add(\"java.util.Date\");\n                importList.add(\"com.fasterxml.jackson.annotation.JsonFormat\");\n            }\n            else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType()))\n            {\n                importList.add(\"java.math.BigDecimal\");\n            }\n        }\n        return importList;\n    }\n\n    /**\n     * 获取权限前缀\n     * \n     * @param moduleName 模块名称\n     * @param businessName 业务名称\n     * @return 返回权限前缀\n     */\n    public static String getPermissionPrefix(String moduleName, String businessName)\n    {\n        return StringUtils.format(\"{}:{}\", moduleName, businessName);\n    }\n\n    /**\n     * 获取上级菜单ID字段\n     * \n     * @param paramsObj 生成其他选项\n     * @return 上级菜单ID字段\n     */\n    public static String getParentMenuId(JSONObject paramsObj)\n    {\n        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)\n                && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID)))\n        {\n            return paramsObj.getString(GenConstants.PARENT_MENU_ID);\n        }\n        return DEFAULT_PARENT_MENU_ID;\n    }\n\n    /**\n     * 获取树编码\n     * \n     * @param paramsObj 生成其他选项\n     * @return 树编码\n     */\n    public static String getTreecode(JSONObject paramsObj)\n    {\n        if (paramsObj.containsKey(GenConstants.TREE_CODE))\n        {\n            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));\n        }\n        return StringUtils.EMPTY;\n    }\n\n    /**\n     * 获取树父编码\n     * \n     * @param paramsObj 生成其他选项\n     * @return 树父编码\n     */\n    public static String getTreeParentCode(JSONObject paramsObj)\n    {\n        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))\n        {\n            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));\n        }\n        return StringUtils.EMPTY;\n    }\n\n    /**\n     * 获取树名称\n     * \n     * @param paramsObj 生成其他选项\n     * @return 树名称\n     */\n    public static String getTreeName(JSONObject paramsObj)\n    {\n        if (paramsObj.containsKey(GenConstants.TREE_NAME))\n        {\n            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));\n        }\n        return StringUtils.EMPTY;\n    }\n\n    /**\n     * 获取需要在哪一列上面显示展开按钮\n     * \n     * @param genTable 业务表对象\n     * @return 展开按钮列序号\n     */\n    public static int getExpandColumn(GenTable genTable)\n    {\n        String options = genTable.getOptions();\n        JSONObject paramsObj = JSONObject.parseObject(options);\n        String treeName = paramsObj.getString(GenConstants.TREE_NAME);\n        int num = 0;\n        for (GenTableColumn column : genTable.getColumns())\n        {\n            if (column.isList())\n            {\n                num++;\n                String columnName = column.getColumnName();\n                if (columnName.equals(treeName))\n                {\n                    break;\n                }\n            }\n        }\n        return num;\n    }\n\n    /**\n     * 获取表单排列网格\n     * \n     * @param formColNum 表单布局方式\n     * @return 排列类样式\n     */\n    public static String getColXsNum(int formColNum)\n    {\n        String colXsNum = \"col-xs-12\";\n        if (formColNum == 2)\n        {\n            return \"col-xs-6\";\n        }\n        else if (formColNum == 3)\n        {\n            return \"col-xs-4\";\n        }\n        return colXsNum;\n    }\n\n    /**\n     * 获取表单label网格\n     * \n     * @param formColNum 表单布局方式\n     * @return 网格类样式\n     */\n    public static String getColSmNum(int formColNum)\n    {\n        String colSmNum = \"col-sm-3\";\n        if (formColNum == 2 || formColNum == 3)\n        {\n            return \"col-sm-4\";\n        }\n        return colSmNum;\n    }\n}\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/generator.yml",
    "content": "\r\n# 代码生成\r\ngen:\r\n  # 作者\r\n  author: ruoyi\r\n  # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool\r\n  packageName: com.ruoyi.system\r\n  # 自动去除表前缀，默认是false\r\n  autoRemovePre: false\r\n  # 表前缀（生成类名不会包含表前缀，多个用逗号分隔）\r\n  tablePrefix: sys_\r\n  # 是否允许生成文件覆盖到本地（自定义路径），默认不允许\r\n  allowOverwrite: false"
  },
  {
    "path": "ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.generator.mapper.GenTableColumnMapper\">\r\n    \r\n    <resultMap type=\"GenTableColumn\" id=\"GenTableColumnResult\">\r\n        <id     property=\"columnId\"       column=\"column_id\"      />\r\n        <result property=\"tableId\"        column=\"table_id\"       />\r\n        <result property=\"columnName\"     column=\"column_name\"    />\r\n        <result property=\"columnComment\"  column=\"column_comment\" />\r\n        <result property=\"columnType\"     column=\"column_type\"    />\r\n        <result property=\"javaType\"       column=\"java_type\"      />\r\n        <result property=\"javaField\"      column=\"java_field\"     />\r\n        <result property=\"isPk\"           column=\"is_pk\"          />\r\n        <result property=\"isIncrement\"    column=\"is_increment\"   />\r\n        <result property=\"isRequired\"     column=\"is_required\"    />\r\n        <result property=\"isInsert\"       column=\"is_insert\"      />\r\n        <result property=\"isEdit\"         column=\"is_edit\"        />\r\n        <result property=\"isList\"         column=\"is_list\"        />\r\n        <result property=\"isQuery\"        column=\"is_query\"       />\r\n        <result property=\"queryType\"      column=\"query_type\"     />\r\n        <result property=\"htmlType\"       column=\"html_type\"      />\r\n        <result property=\"dictType\"       column=\"dict_type\"      />\r\n        <result property=\"sort\"           column=\"sort\"           />\r\n        <result property=\"createBy\"       column=\"create_by\"      />\r\n        <result property=\"createTime\"     column=\"create_time\"    />\r\n        <result property=\"updateBy\"       column=\"update_by\"      />\r\n        <result property=\"updateTime\"     column=\"update_time\"    />\r\n    </resultMap>\r\n\t\r\n\t<sql id=\"selectGenTableColumnVo\">\r\n        select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column\r\n    </sql>\r\n\t\r\n    <select id=\"selectGenTableColumnListByTableId\" parameterType=\"GenTableColumn\" resultMap=\"GenTableColumnResult\">\r\n        <include refid=\"selectGenTableColumnVo\"/>\r\n        where table_id = #{tableId}\r\n        order by sort\r\n    </select>\r\n    \r\n    <select id=\"selectDbTableColumnsByName\" parameterType=\"String\" resultMap=\"GenTableColumnResult\">\r\n\t\tselect column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type\r\n\t\tfrom information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})\r\n\t\torder by ordinal_position\r\n\t</select>\r\n    \r\n    <insert id=\"insertGenTableColumn\" parameterType=\"GenTableColumn\" useGeneratedKeys=\"true\" keyProperty=\"columnId\">\r\n        insert into gen_table_column (\r\n\t\t\t<if test=\"tableId != null and tableId != ''\">table_id,</if>\r\n\t\t\t<if test=\"columnName != null and columnName != ''\">column_name,</if>\r\n\t\t\t<if test=\"columnComment != null and columnComment != ''\">column_comment,</if>\r\n\t\t\t<if test=\"columnType != null and columnType != ''\">column_type,</if>\r\n\t\t\t<if test=\"javaType != null and javaType != ''\">java_type,</if>\r\n\t\t\t<if test=\"javaField != null  and javaField != ''\">java_field,</if>\r\n\t\t\t<if test=\"isPk != null and isPk != ''\">is_pk,</if>\r\n\t\t\t<if test=\"isIncrement != null and isIncrement != ''\">is_increment,</if>\r\n\t\t\t<if test=\"isRequired != null and isRequired != ''\">is_required,</if>\r\n\t\t\t<if test=\"isInsert != null and isInsert != ''\">is_insert,</if>\r\n\t\t\t<if test=\"isEdit != null and isEdit != ''\">is_edit,</if>\r\n\t\t\t<if test=\"isList != null and isList != ''\">is_list,</if>\r\n\t\t\t<if test=\"isQuery != null and isQuery != ''\">is_query,</if>\r\n\t\t\t<if test=\"queryType != null and queryType != ''\">query_type,</if>\r\n\t\t\t<if test=\"htmlType != null and htmlType != ''\">html_type,</if>\r\n\t\t\t<if test=\"dictType != null and dictType != ''\">dict_type,</if>\r\n\t\t\t<if test=\"sort != null\">sort,</if>\r\n\t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n\t\t\tcreate_time\r\n         )values(\r\n\t\t\t<if test=\"tableId != null and tableId != ''\">#{tableId},</if>\r\n\t\t\t<if test=\"columnName != null and columnName != ''\">#{columnName},</if>\r\n\t\t\t<if test=\"columnComment != null and columnComment != ''\">#{columnComment},</if>\r\n\t\t\t<if test=\"columnType != null and columnType != ''\">#{columnType},</if>\r\n\t\t\t<if test=\"javaType != null and javaType != ''\">#{javaType},</if>\r\n\t\t\t<if test=\"javaField != null and javaField != ''\">#{javaField},</if>\r\n\t\t\t<if test=\"isPk != null and isPk != ''\">#{isPk},</if>\r\n\t\t\t<if test=\"isIncrement != null and isIncrement != ''\">#{isIncrement},</if>\r\n\t\t\t<if test=\"isRequired != null and isRequired != ''\">#{isRequired},</if>\r\n\t\t\t<if test=\"isInsert != null and isInsert != ''\">#{isInsert},</if>\r\n\t\t\t<if test=\"isEdit != null and isEdit != ''\">#{isEdit},</if>\r\n\t\t\t<if test=\"isList != null and isList != ''\">#{isList},</if>\r\n\t\t\t<if test=\"isQuery != null and isQuery != ''\">#{isQuery},</if>\r\n\t\t\t<if test=\"queryType != null and queryType != ''\">#{queryType},</if>\r\n\t\t\t<if test=\"htmlType != null and htmlType != ''\">#{htmlType},</if>\r\n\t\t\t<if test=\"dictType != null and dictType != ''\">#{dictType},</if>\r\n\t\t\t<if test=\"sort != null\">#{sort},</if>\r\n\t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n\t\t\tsysdate()\r\n         )\r\n    </insert>\r\n\t \r\n    <update id=\"updateGenTableColumn\" parameterType=\"GenTableColumn\">\r\n        update gen_table_column\r\n        <set>\r\n            column_comment = #{columnComment},\r\n            java_type = #{javaType},\r\n            java_field = #{javaField},\r\n            is_insert = #{isInsert},\r\n            is_edit = #{isEdit},\r\n            is_list = #{isList},\r\n            is_query = #{isQuery},\r\n            is_required = #{isRequired},\r\n            query_type = #{queryType},\r\n            html_type = #{htmlType},\r\n            dict_type = #{dictType},\r\n            sort = #{sort},\r\n            update_by = #{updateBy},\r\n            update_time = sysdate()\r\n        </set>\r\n        where column_id = #{columnId}\r\n    </update>\r\n\r\n    <delete id=\"deleteGenTableColumnByIds\" parameterType=\"Long\">\r\n        delete from gen_table_column where table_id in \r\n        <foreach collection=\"array\" item=\"tableId\" open=\"(\" separator=\",\" close=\")\">\r\n            #{tableId}\r\n        </foreach>\r\n    </delete>\r\n\r\n    <delete id=\"deleteGenTableColumns\">\r\n        delete from gen_table_column where column_id in \r\n        <foreach collection=\"list\" item=\"item\" open=\"(\" separator=\",\" close=\")\">\r\n            #{item.columnId}\r\n        </foreach>\r\n    </delete>\r\n\r\n</mapper>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.ruoyi.generator.mapper.GenTableMapper\">\n\n\t<resultMap type=\"GenTable\" id=\"GenTableResult\">\n\t    <id     property=\"tableId\"        column=\"table_id\"          />\n\t\t<result property=\"tableName\"      column=\"table_name\"        />\n\t\t<result property=\"tableComment\"   column=\"table_comment\"     />\n\t\t<result property=\"subTableName\"   column=\"sub_table_name\"    />\n\t\t<result property=\"subTableFkName\" column=\"sub_table_fk_name\" />\n\t\t<result property=\"className\"      column=\"class_name\"        />\n\t\t<result property=\"tplCategory\"    column=\"tpl_category\"      />\n\t\t<result property=\"packageName\"    column=\"package_name\"      />\n\t\t<result property=\"moduleName\"     column=\"module_name\"       />\n\t\t<result property=\"businessName\"   column=\"business_name\"     />\n\t\t<result property=\"functionName\"   column=\"function_name\"     />\n\t\t<result property=\"functionAuthor\" column=\"function_author\"   />\n\t\t<result property=\"formColNum\"     column=\"form_col_num\"      />\n\t\t<result property=\"genType\"        column=\"gen_type\"          />\n\t\t<result property=\"genPath\"        column=\"gen_path\"          />\n\t\t<result property=\"options\"        column=\"options\"           />\n\t\t<result property=\"createBy\"       column=\"create_by\"         />\n\t\t<result property=\"createTime\"     column=\"create_time\"       />\n\t\t<result property=\"updateBy\"       column=\"update_by\"         />\n\t\t<result property=\"updateTime\"     column=\"update_time\"       />\n\t\t<result property=\"remark\"         column=\"remark\"            />\n\t\t<collection  property=\"columns\"   javaType=\"java.util.List\"  resultMap=\"GenTableColumnResult\" />\n\t</resultMap>\n\t\n\t<resultMap type=\"GenTableColumn\" id=\"GenTableColumnResult\">\n        <id     property=\"columnId\"       column=\"column_id\"      />\n        <result property=\"tableId\"        column=\"table_id\"       />\n        <result property=\"columnName\"     column=\"column_name\"    />\n        <result property=\"columnComment\"  column=\"column_comment\" />\n        <result property=\"columnType\"     column=\"column_type\"    />\n        <result property=\"javaType\"       column=\"java_type\"      />\n        <result property=\"javaField\"      column=\"java_field\"     />\n        <result property=\"isPk\"           column=\"is_pk\"          />\n        <result property=\"isIncrement\"    column=\"is_increment\"   />\n        <result property=\"isRequired\"     column=\"is_required\"    />\n        <result property=\"isInsert\"       column=\"is_insert\"      />\n        <result property=\"isEdit\"         column=\"is_edit\"        />\n        <result property=\"isList\"         column=\"is_list\"        />\n        <result property=\"isQuery\"        column=\"is_query\"       />\n        <result property=\"queryType\"      column=\"query_type\"     />\n        <result property=\"htmlType\"       column=\"html_type\"      />\n        <result property=\"dictType\"       column=\"dict_type\"      />\n        <result property=\"sort\"           column=\"sort\"           />\n        <result property=\"createBy\"       column=\"create_by\"      />\n        <result property=\"createTime\"     column=\"create_time\"    />\n        <result property=\"updateBy\"       column=\"update_by\"      />\n        <result property=\"updateTime\"     column=\"update_time\"    />\n    </resultMap>\n\t\n\t<sql id=\"selectGenTableVo\">\n        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, form_col_num, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table\n    </sql>\n    \n    <select id=\"selectGenTableList\" parameterType=\"GenTable\" resultMap=\"GenTableResult\">\n\t\t<include refid=\"selectGenTableVo\"/>\n\t\t<where>\n\t\t\t<if test=\"tableName != null and tableName != ''\">\n\t\t\t\tAND lower(table_name) like lower(concat('%', #{tableName}, '%'))\n\t\t\t</if>\n\t\t\t<if test=\"tableComment != null and tableComment != ''\">\n\t\t\t\tAND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))\n\t\t\t</if>\n\t\t\t<if test=\"params.beginTime != null and params.beginTime != ''\">\n\t\t\t\tand date_format(create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')\n\t\t\t</if>\n\t\t\t<if test=\"params.endTime != null and params.endTime != ''\">\n\t\t\t\tand date_format(create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')\n\t\t\t</if>\n\t\t</where>\n\t</select>\n\n\t<select id=\"selectDbTableList\" parameterType=\"GenTable\" resultMap=\"GenTableResult\">\n\t\tselect table_name, table_comment, create_time, update_time from information_schema.tables\n\t\twhere table_schema = (select database())\n\t\tAND table_name NOT LIKE 'qrtz\\_%' AND table_name NOT LIKE 'gen\\_%'\n\t\tAND table_name NOT IN (select table_name from gen_table)\n\t\t<if test=\"tableName != null and tableName != ''\">\n\t\t\tAND lower(table_name) like lower(concat('%', #{tableName}, '%'))\n\t\t</if>\n\t\t<if test=\"tableComment != null and tableComment != ''\">\n\t\t\tAND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))\n\t\t</if>\n        order by create_time desc\n\t</select>\n\t\n\t<select id=\"selectDbTableListByNames\" resultMap=\"GenTableResult\">\n\t\tselect table_name, table_comment, create_time, update_time from information_schema.tables\n\t\twhere table_name NOT LIKE 'qrtz\\_%' and table_name NOT LIKE 'gen\\_%' and table_schema = (select database())\n\t\tand table_name in\n\t    <foreach collection=\"array\" item=\"name\" open=\"(\" separator=\",\" close=\")\">\n \t\t\t#{name}\n        </foreach> \n\t</select>\n\t\n\t<select id=\"selectTableByName\" parameterType=\"String\" resultMap=\"GenTableResult\">\n\t\tselect table_name, table_comment, create_time, update_time from information_schema.tables\n\t\twhere table_comment <![CDATA[ <> ]]> '' and table_schema = (select database())\n\t\tand table_name = #{tableName}\n\t</select>\n\t\n\t<select id=\"selectGenTableById\" parameterType=\"Long\" resultMap=\"GenTableResult\">\n\t    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.form_col_num, t.gen_type, t.gen_path, t.options, t.remark,\n\t\t\t   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort\n\t\tFROM gen_table t\n\t\t\t LEFT JOIN gen_table_column c ON t.table_id = c.table_id\n\t\twhere t.table_id = #{tableId} order by c.sort\n\t</select>\n\t\n\t<select id=\"selectGenTableByName\" parameterType=\"String\" resultMap=\"GenTableResult\">\n\t    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.form_col_num, t.gen_type, t.gen_path, t.options, t.remark,\n\t\t\t   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort\n\t\tFROM gen_table t\n\t\t\t LEFT JOIN gen_table_column c ON t.table_id = c.table_id\n\t\twhere t.table_name = #{tableName} order by c.sort\n\t</select>\n\t\n\t<select id=\"selectGenTableAll\" parameterType=\"String\" resultMap=\"GenTableResult\">\n\t    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.form_col_num, t.gen_type, t.gen_path, t.options, t.remark,\n\t\t\t   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort\n\t\tFROM gen_table t\n\t\t\t LEFT JOIN gen_table_column c ON t.table_id = c.table_id\n\t\torder by c.sort\n\t</select>\n\t\n\t<insert id=\"insertGenTable\" parameterType=\"GenTable\" useGeneratedKeys=\"true\" keyProperty=\"tableId\">\n        insert into gen_table (\n\t\t\t<if test=\"tableName != null\">table_name,</if>\n\t\t\t<if test=\"tableComment != null and tableComment != ''\">table_comment,</if>\n\t\t\t<if test=\"className != null and className != ''\">class_name,</if>\n\t\t\t<if test=\"tplCategory != null and tplCategory != ''\">tpl_category,</if>\n\t\t\t<if test=\"packageName != null and packageName != ''\">package_name,</if>\n\t\t\t<if test=\"moduleName != null and moduleName != ''\">module_name,</if>\n\t\t\t<if test=\"businessName != null and businessName != ''\">business_name,</if>\n\t\t\t<if test=\"functionName != null and functionName != ''\">function_name,</if>\n\t\t\t<if test=\"functionAuthor != null and functionAuthor != ''\">function_author,</if>\n\t\t\t<if test=\"formColNum != null\">form_col_num,</if>\n\t\t\t<if test=\"genType != null and genType != ''\">gen_type,</if>\n\t\t\t<if test=\"genPath != null and genPath != ''\">gen_path,</if>\n\t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\n\t\t\tcreate_time\n         )values(\n\t\t\t<if test=\"tableName != null\">#{tableName},</if>\n\t\t\t<if test=\"tableComment != null and tableComment != ''\">#{tableComment},</if>\n\t\t\t<if test=\"className != null and className != ''\">#{className},</if>\n\t\t\t<if test=\"tplCategory != null and tplCategory != ''\">#{tplCategory},</if>\n\t\t\t<if test=\"packageName != null and packageName != ''\">#{packageName},</if>\n\t\t\t<if test=\"moduleName != null and moduleName != ''\">#{moduleName},</if>\n\t\t\t<if test=\"businessName != null and businessName != ''\">#{businessName},</if>\n\t\t\t<if test=\"functionName != null and functionName != ''\">#{functionName},</if>\n\t\t\t<if test=\"functionAuthor != null and functionAuthor != ''\">#{functionAuthor},</if>\n\t\t\t<if test=\"formColNum != null\">#{formColNum},</if>\n\t\t\t<if test=\"genType != null and genType != ''\">#{genType},</if>\n\t\t\t<if test=\"genPath != null and genPath != ''\">#{genPath},</if>\n\t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\n\t\t\tsysdate()\n         )\n    </insert>\n    \n    <update id=\"createTable\">\n        ${sql}\n    </update>\n    \n    <update id=\"updateGenTable\" parameterType=\"GenTable\">\n        update gen_table\n        <set>\n            <if test=\"tableName != null\">table_name = #{tableName},</if>\n            <if test=\"tableComment != null and tableComment != ''\">table_comment = #{tableComment},</if>\n            <if test=\"subTableName != null\">sub_table_name = #{subTableName},</if>\n            <if test=\"subTableFkName != null\">sub_table_fk_name = #{subTableFkName},</if>\n            <if test=\"className != null and className != ''\">class_name = #{className},</if>\n            <if test=\"functionAuthor != null and functionAuthor != ''\">function_author = #{functionAuthor},</if>\n            <if test=\"formColNum != null\">form_col_num = #{formColNum},</if>\n            <if test=\"genType != null and genType != ''\">gen_type = #{genType},</if>\n            <if test=\"genPath != null and genPath != ''\">gen_path = #{genPath},</if>\n            <if test=\"tplCategory != null and tplCategory != ''\">tpl_category = #{tplCategory},</if>\n            <if test=\"packageName != null and packageName != ''\">package_name = #{packageName},</if>\n            <if test=\"moduleName != null and moduleName != ''\">module_name = #{moduleName},</if>\n            <if test=\"businessName != null and businessName != ''\">business_name = #{businessName},</if>\n            <if test=\"functionName != null and functionName != ''\">function_name = #{functionName},</if>\n            <if test=\"options != null and options != ''\">options = #{options},</if>\n            <if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\n            <if test=\"remark != null\">remark = #{remark},</if>\n            update_time = sysdate()\n        </set>\n        where table_id = #{tableId}\n    </update>\n    \n    <delete id=\"deleteGenTableByIds\" parameterType=\"Long\">\n        delete from gen_table where table_id in \n        <foreach collection=\"array\" item=\"tableId\" open=\"(\" separator=\",\" close=\")\">\n            #{tableId}\n        </foreach>\n    </delete>\n\n</mapper> "
  },
  {
    "path": "ruoyi-generator/src/main/resources/templates/tool/gen/createTable.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <th:block th:include=\"include :: header('创建表结构')\"/>\r\n</head>\r\n<body>\r\n<div class=\"main-content\">\r\n    <label class=\"col-sm-6 control-label\">创建表语句(支持多个建表语句)：</label>\r\n    <div class=\"col-sm-11 col\">\r\n        <textarea class=\"form-control\" id=\"text_create\" name=\"\" placeholder=\"请输入文本\" rows=\"12\" type=\"text\"></textarea>\r\n    </div>\r\n</div>\r\n<th:block th:include=\"include :: footer\"/>\r\n\r\n<script type=\"text/javascript\">\r\n    var prefix = ctx + \"tool/gen\";\r\n\r\n    /* 创建表结构 */\r\n    function submitHandler() {\r\n        var rows = $(\"#text_create\").val();\r\n        if (rows.length == 0) {\r\n            $.modal.alertWarning(\"请输入建表语句\");\r\n            return;\r\n        }\r\n        var data = {\"sql\": rows};\r\n        $.operate.save(prefix + \"/createTable\", data);\r\n    }\r\n</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/templates/tool/gen/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改生成信息')\" />\r\n\t<th:block th:include=\"include :: select2-css\" />\r\n\t<style type=\"text/css\">\r\n\t    .select-table table{table-layout:fixed;}.table>thead>tr>th{text-align:center;}.select-table .table td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.form-control{padding:3px 6px 4px;height:30px;}.icheckbox-blue{top:0px;left:6px;}.form-control.select2-hidden-accessible{position:static!important;}.select-table table label.error{position: inherit;}select + label.error{z-index:1;right:40px;}\r\n\t</style>\r\n</head>\r\n<body class=\"gray-bg\" style=\"font: 14px Helvetica Neue, Helvetica, PingFang SC, 微软雅黑, Tahoma, Arial, sans-serif !important;\">\r\n    <section class=\"section-content\">\r\n    <div class=\"row\">\r\n        <div class=\"col-xs-12\">\r\n            <div class=\"ibox float-e-margins\">\r\n                <div class=\"ibox-content\" style=\"border-style:none;\">\r\n                    <div class=\"nav-tabs-custom\">\r\n                        <ul class=\"nav nav-tabs\">\r\n                            <li><a href=\"#tab-basic\" data-toggle=\"tab\" aria-expanded=\"false\">基本信息</a></li>\r\n                            <li class=\"active\"><a href=\"#tab-field\" data-toggle=\"tab\" aria-expanded=\"true\">字段信息</a></li>\r\n                            <li><a href=\"#tab-gen\" data-toggle=\"tab\" aria-expanded=\"false\">生成信息</a></li>\r\n                            <li class=\"pull-right header\">\r\n\t\t\t\t\t\t\t\t<i class=\"fa fa-code\"></i> 生成配置\r\n\t\t\t\t\t\t\t</li>\r\n                        </ul>\r\n                        <form id=\"form-gen-edit\" class=\"form-horizontal\" th:object=\"${table}\">\r\n                        <input name=\"tableId\" type=\"hidden\" th:field=\"*{tableId}\" />\r\n                        <div class=\"tab-content\">\r\n                            <!-- 基本信息 -->\r\n                            <div class=\"tab-pane\" id=\"tab-basic\">\r\n\t\t\t\t            <div class=\"row mt20\">\r\n\t\t\t\t            \t<div class=\"col-sm-6\">\r\n\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\">表名称：</label>\r\n\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t                            <input name=\"tableName\" class=\"form-control\" type=\"text\" placeholder=\"请输入表名称\" maxlength=\"200\" th:field=\"*{tableName}\" required>\r\n\t\t\t\t                        </div>\r\n\t\t\t\t                    </div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\">表描述：</label>\r\n\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t                            <input name=\"tableComment\" class=\"form-control\" type=\"text\" placeholder=\"请输入表描述\" maxlength=\"500\" th:field=\"*{tableComment}\" required>\r\n\t\t\t\t                        </div>\r\n\t\t\t\t                    </div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t            </div>\r\n\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\">实体类名称：</label>\r\n\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t                            <input name=\"className\" class=\"form-control\" type=\"text\" placeholder=\"请输入实体类名称\" maxlength=\"100\" th:field=\"*{className}\" required>\r\n\t\t\t\t                        </div>\r\n\t\t\t\t                    </div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\">作者：</label>\r\n\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t                            <input name=\"functionAuthor\" class=\"form-control\" type=\"text\" placeholder=\"请输入作者\" maxlength=\"50\" th:field=\"*{functionAuthor}\" required>\r\n\t\t\t\t                        </div>\r\n\t\t\t\t                    </div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t            </div>\r\n\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t                <div class=\"col-sm-12\">\r\n\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t                        <label class=\"col-xs-2 control-label\">备注：</label>\r\n\t\t\t\t                        <div class=\"col-xs-10\">\r\n\t\t\t\t                            <textarea name=\"remark\" maxlength=\"500\" class=\"form-control\" rows=\"3\"></textarea>\r\n\t\t\t\t                        </div>\r\n\t\t\t\t                    </div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t            </div>\r\n                            </div>\r\n                            \r\n                            <!-- 字段信息 -->\r\n                            <div class=\"tab-pane active\" id=\"tab-field\">\r\n                                <div class=\"select-table table-striped\" style=\"margin-top: 0px;padding-top: 0px;padding-bottom: 0px;\">\r\n\t\t\t\t\t\t\t\t    <table id=\"bootstrap-table\" data-use-row-attr-func=\"true\" data-reorderable-rows=\"true\"></table>\r\n\t\t\t\t\t\t\t\t</div>\r\n                            </div>\r\n                            \r\n                            <!-- 生成信息 -->\r\n                            <div class=\"tab-pane\" id=\"tab-gen\">\r\n\t\t\t\t\t            <div class=\"row mt20\">\r\n\t\t\t\t\t            \t<div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\">生成模板：</label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <select class='form-control' id=\"tplCategory\" name='tplCategory' style=\"width: 100%\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"crud\" th:field=\"*{tplCategory}\">单表（增删改查）</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"tree\" th:field=\"*{tplCategory}\">树表（增删改查）</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"sub\" th:field=\"*{tplCategory}\">主子表（增删改查）</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"生成在哪个java包下，例如 com.ruoyi.project.system\">生成包路径：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <input name=\"packageName\" class=\"form-control\" type=\"text\" placeholder=\"请输入生成包路径\" maxlength=\"100\" th:field=\"*{packageName}\" required>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"可理解为子系统名，例如 system\">生成模块名：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <input name=\"moduleName\" class=\"form-control\" type=\"text\" placeholder=\"请输入生成模块名\" maxlength=\"30\" th:field=\"*{moduleName}\" required>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"可理解为功能英文名，例如 user\">生成业务名：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <input name=\"businessName\" class=\"form-control\" type=\"text\" placeholder=\"请输入生成业务名\" maxlength=\"50\" th:field=\"*{businessName}\" required>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"用作类描述，例如 用户\">生成功能名：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <input name=\"functionName\" class=\"form-control\" type=\"text\" placeholder=\"请输入生成功能名\" maxlength=\"50\" th:field=\"*{functionName}\" required>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"选择表单的栅格布局方式\">表单布局：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <select class='form-control' id=\"formColNum\" name='formColNum' style=\"width: 100%\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"1\" th:field=\"*{formColNum}\">单列</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"2\" th:field=\"*{formColNum}\">双列</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"3\" th:field=\"*{formColNum}\">三列</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label\" title=\"默认为zip压缩包下载，也可以自定义生成路径\">生成代码方式：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n                                                <label class=\"radio-box\"> <input type=\"radio\" name=\"genType\" value=\"0\" th:field=\"*{genType}\" /> zip压缩包 </label> \r\n                                                <label class=\"radio-box\"> <input type=\"radio\" name=\"genType\" value=\"1\" th:field=\"*{genType}\" /> 自定义路径</label> \r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"分配到指定菜单下，例如 系统管理\">上级菜单：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <input id=\"parentMenuId\" name=\"params[parentMenuId]\" type=\"hidden\" th:value=\"*{parentMenuId}\"/>\r\n\t\t\t\t\t                            <div class=\"input-group\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <input id=\"parentMenuName\" name=\"params[parentMenuName]\" class=\"form-control\" type=\"text\" onclick=\"selectMenuTree()\" placeholder=\"请选择上级菜单\" maxlength=\"50\" th:value=\"*{parentMenuName}\" required>\r\n\t\t\t\t\t\t\t\t\t\t\t        <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n\t\t\t\t\t\t\t\t\t\t\t    </div>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            <div class=\"hidden row\" id=\"pathinfo\">\r\n\t\t\t\t\t                <div class=\"col-sm-12\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-xs-2 control-label\" title=\"填写磁盘绝对路径，若不填写，则生成到当前Web项目下\">生成基础路径：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t\t                    <div class=\"col-xs-10\">\r\n\t\t\t\t\t\t                        <div class=\"input-group input-group-sm\">\r\n\t\t\t\t\t\t                            <input id=\"genPath\" name=\"genPath\" class=\"form-control\" type=\"text\" th:field=\"*{genPath}\" placeholder=\"请输入项目路径\" maxlength=\"200\">\r\n\t\t\t\t\t\t                            <div class=\"input-group-btn\">\r\n\t\t\t\t\t\t                               <button type=\"button\" class=\"btn btn-default dropdown-toggle\" data-toggle=\"dropdown\">最近路径快速选择 <span class=\"caret\"></span></button>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ul class=\"dropdown-menu dropdown-menu-right\" role=\"menu\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li><a href=\"javascript:$('#genPath').val('/')\"><i class=\"fa fa-refresh\"></i>恢复默认的生成基础路径</a></li>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\r\n\t\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            <div class=\"hidden\" id=\"subInfo\">\r\n\t\t\t\t\t            <h4 class=\"form-header h4\">关联信息</h4>\r\n\t\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"关联子表的表名， 如：sys_user\">关联子表的表名：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <select class='type form-control' id=\"subTableName\" name='subTableName' th:attr='data-value=*{subTableName}' style=\"width: 100%\">\r\n\t\t\t\t\t                                <option value=\"\">---请选择---</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"子表关联的外键名， 如：user_id\">子表关联的外键名：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <select class='router form-control' id=\"subTableFkName\" name='subTableFkName' th:attr='data-value=*{subTableFkName}' style=\"width: 100%\">\r\n\t\t\t\t\t                                <option value=\"\">---请选择---</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            <div class=\"hidden\" id=\"otherInfo\">\r\n\t\t\t\t\t            <h4 class=\"form-header h4\">其他信息</h4>\r\n\t\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"树显示的编码字段名， 如：dept_id\">树编码字段：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <select class='form-control' id=\"treeCode\" name='params[treeCode]' style=\"width: 100%\">\r\n\t\t\t\t\t                                <option value=\"\">---请选择---</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option th:each=\"column : ${table.columns}\" th:text=\"${column.columnName + '：' + column.columnComment}\" th:value=\"${column.columnName}\" th:field=\"*{treeCode}\"></option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"树显示的父编码字段名， 如：parent_Id\">树父编码字段：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <select class='form-control' id=\"treeParentCode\" name='params[treeParentCode]' style=\"width: 100%\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"\">---请选择---</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option th:each=\"column : ${table.columns}\" th:text=\"${column.columnName + '：' + column.columnComment}\" th:value=\"${column.columnName}\" th:field=\"*{treeParentCode}\"></option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            <div class=\"row\">\r\n\t\t\t\t\t                <div class=\"col-sm-6\">\r\n\t\t\t\t\t                    <div class=\"form-group\">\r\n\t\t\t\t\t                        <label class=\"col-sm-4 control-label is-required\" title=\"树节点的显示名称字段名， 如：dept_name\">树名称字段：<i class=\"fa fa-question-circle-o\"></i></label>\r\n\t\t\t\t\t                        <div class=\"col-sm-8\">\r\n\t\t\t\t\t                            <select class='form-control' id=\"treeName\" name='params[treeName]' style=\"width: 100%\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option value=\"\">---请选择---</option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t    <option th:each=\"column : ${table.columns}\" th:text=\"${column.columnName + '：' + column.columnComment}\" th:value=\"${column.columnName}\" th:field=\"*{treeName}\"></option>\r\n\t\t\t\t\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t                        </div>\r\n\t\t\t\t\t                    </div>\r\n\t\t\t\t\t                </div>\r\n\t\t\t\t\t            </div>\r\n\t\t\t\t\t            </div>\r\n                            </div>\r\n                        </div>\r\n                        </form>\r\n                    </div>\r\n                </div>\r\n               <div class=\"box-footer\">\r\n\t\t\t       <div class=\"col-sm-offset-5 col-sm-6\">\r\n\t\t\t           <button type=\"button\" class=\"btn btn-sm btn-primary\" onclick=\"submitHandler()\"><i class=\"fa fa-check\"></i>保 存</button>&nbsp;\r\n\t\t\t           <button type=\"button\" class=\"btn btn-sm btn-danger\" onclick=\"closeItem()\"><i class=\"fa fa-reply-all\"></i>关 闭 </button>\r\n\t\t\t       </div>\r\n           \t   </div>\r\n            </div>\r\n        </div>\r\n    </div>\r\n\t</section>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: select2-js\" />\r\n    <th:block th:include=\"include :: bootstrap-table-reorder-rows-js\" />\r\n    <script th:src=\"@{/js/jquery.tmpl.js}\"></script>\r\n    <th:block th:include=\"include :: jquery-cxselect-js\" />\r\n    <script th:inline=\"javascript\">\r\n\t    /* 用户信息-修改 */\r\n\t    $(\"#form-table-edit\").validate({\r\n\t    \trules: {\r\n\t    \t    tableName: {\r\n\t    \t        required: true,\r\n\t    \t    },\r\n\t    \t},\r\n\t\t\tfocusCleanup: true\r\n\t\t});\r\n\t    \r\n\t    /* 表级联信息 */\r\n   \t\tvar data = [[${data}]];\r\n    \t$('#subInfo').cxSelect({\r\n    \t  selects: ['type', 'router'],\r\n    \t  jsonValue: 'v',\r\n    \t  data: data\r\n    \t});\r\n\t    \r\n\t    function submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.saveTab(prefix + \"/edit\", $(\"#form-gen-edit\").serializeArray());\r\n\t        }\r\n\t    }\r\n\t    \r\n\t    var prefix = ctx + \"tool/gen\";\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/column/list\",\r\n\t\t        sidePagination: \"client\",\r\n\t\t        sortName: \"sort\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        height: $(window).height() - 166,\r\n\t\t        pagination: false,\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        onLoadSuccess: onLoadSuccess,\r\n\t\t        onReorderRow: onReorderRow,\r\n\t\t        columns: [{\r\n                    title: \"序号\",\r\n                    width: \"5%\",\r\n                    formatter: function (value, row, index) {\r\n                    \t// 编号隐藏域\r\n                    \tvar columnIdHtml = $.common.sprintf(\"<input type='hidden' name='columns[%s].columnId' value='%s'>\", index, row.columnId);\r\n                    \t// 排序隐藏域\r\n                    \tvar sortHtml = $.common.sprintf(\"<input type='hidden' name='columns[%s].sort' value='%s' id='columns_sort_%s'>\", index, row.sort, row.columnId);\r\n                    \treturn columnIdHtml + sortHtml + $.table.serialNumber(index);\r\n                    },\r\n                    cellStyle: function(value, row, index) {\r\n                        return { css: { \"cursor\": \"move\" } };\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            field: 'columnName',\r\n\t\t            title: '字段列名',\r\n\t\t            width: \"10%\",\r\n\t\t            class: \"nodrag\",\r\n\t\t            cellStyle: function(value, row, index) {\r\n                        return { css: { \"cursor\": \"default\" } };\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'columnComment',\r\n\t\t            title: '字段描述',\r\n\t\t            width: \"10%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar html = $.common.sprintf(\"<input class='form-control' type='text' name='columns[%s].columnComment' value='%s'>\", index, value);\r\n\t\t        \t\treturn html;\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'columnType',\r\n\t\t            title: '物理类型',\r\n\t\t            width: \"10%\",\r\n\t\t            class: \"nodrag\",\r\n\t\t            cellStyle: function(value, row, index) {\r\n                        return { css: { \"cursor\": \"default\" } };\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'javaType',\r\n\t\t            title: 'Java类型',\r\n\t\t            width: \"10%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t        \t\tvar data = [{ index: index, javaType: value }];\r\n\t\t                return $(\"#javaTypeTpl\").tmpl(data).html();\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'javaField',\r\n\t\t            title: 'Java属性',\r\n\t\t            width: \"10%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t        \t\tvar html = $.common.sprintf(\"<input class='form-control' type='text' name='columns[%s].javaField' value='%s' required>\", index, value);\r\n\t\t        \t\treturn html;\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'isInsert',\r\n\t\t            title: '插入',\r\n\t\t            width: \"5%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar isCheck = value == 1 ? 'checked' : '';\r\n\t\t            \tvar html = $.common.sprintf(\"<label class='check-box'><input type='checkbox' name='columns[%s].isInsert' value='1' %s></label>\", index, isCheck);\r\n\t\t        \t\treturn html;\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'isEdit',\r\n\t\t            title: '编辑',\r\n\t\t            width: \"5%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar isCheck = value == 1 ? 'checked' : '';\r\n\t\t            \tvar html = $.common.sprintf(\"<label class='check-box'><input type='checkbox' name='columns[%s].isEdit' value='1' %s></label>\", index, isCheck);\r\n\t\t        \t\treturn html;\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'isList',\r\n\t\t            title: '列表',\r\n\t\t            width: \"5%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar isCheck = value == 1 ? 'checked' : '';\r\n\t\t            \tvar html = $.common.sprintf(\"<label class='check-box'><input type='checkbox' name='columns[%s].isList' value='1' %s></label>\", index, isCheck);\r\n\t\t        \t\treturn html;\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'isQuery',\r\n\t\t            title: '查询',\r\n\t\t            width: \"5%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar isCheck = value == 1 ? 'checked' : '';\r\n\t\t            \tvar html = $.common.sprintf(\"<label class='check-box'><input type='checkbox' name='columns[%s].isQuery' value='1' %s></label>\", index, isCheck);\r\n\t\t        \t\treturn html;\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'queryType',\r\n\t\t            title: '查询方式',\r\n\t\t            width: \"10%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar data = [{ index: index, queryType: value }];\r\n\t\t                return $(\"#queryTypeTpl\").tmpl(data).html();\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'isRequired',\r\n\t\t            title: '必填',\r\n\t\t            width: \"5%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar isCheck = value == 1 ? 'checked' : '';\r\n\t\t            \tvar html = $.common.sprintf(\"<label class='check-box'><input type='checkbox' name='columns[%s].isRequired' value='1' %s></label>\", index, isCheck);\r\n\t\t        \t\treturn html;\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'htmlType',\r\n\t\t            title: '显示类型',\r\n\t\t            width: \"12%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t            \tvar data = [{ index: index, htmlType: value }];\r\n\t\t                return $(\"#htmlTypeTpl\").tmpl(data).html();\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'dictType',\r\n\t\t            title: '字典类型',\r\n\t\t            width: \"13%\",\r\n\t\t            formatter: function (value, row, index) {\r\n\t\t        \t\tvar html = $.common.sprintf(\"<input class='form-control' type='text' name='columns[%s].dictType' value='%s' id='columns_dict_%s'>\", index, (value === undefined ? '' : value), row.columnId);\r\n\t\t        \t\treturn \"<div class='input-group'>\" + html + \"<span class='input-group-addon input-sm' onclick='selectDictTree(\" + row.columnId + \", this)'><i class='fa fa-search'></i></span></div>\";\r\n\t\t        \t},\r\n\t\t        \tcellStyle: function(value, row, index) {\r\n                        return { css: { \"cursor\": \"default\" } };\r\n                    }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t\t\r\n\t\t// 当所有数据被加载时触发处理函数\r\n\t\tfunction onLoadSuccess(data){\r\n\t\t\t$.fn.select2.defaults.set( \"theme\", \"bootstrap\" );\r\n\t\t\t$(\"select.form-control\").each(function () {\r\n\t\t\t\t$(this).select2().on(\"change\", function () {\r\n\t\t\t\t\t$(this).valid();\r\n\t\t\t\t})\r\n\t\t\t})\r\n\t\t\t$(\".check-box\").each(function() {\r\n\t            $(this).iCheck({\r\n\t                checkboxClass: 'icheckbox-blue'\r\n            \t})\r\n        \t})\r\n        }\r\n\t\t\r\n\t\t// 当拖拽结束后处理函数\r\n\t\tfunction onReorderRow(data) {\r\n\t        for (var i = 0; i < data.length; i++) {\r\n\t\t\t    $(\"#columns_sort_\" + data[i].columnId).val(i+1);\r\n\t\t\t}\r\n       }\r\n\t\t\r\n\t\t$(function() {\r\n            var tplCategory = $(\"#tplCategory option:selected\").val();\r\n            tplCategoryVisible(tplCategory);\r\n            var genType = $('input[name=\"genType\"]:checked').val();\r\n            pathInfoVisible(genType);\r\n        });\r\n\t\t\r\n\t\t$('#tplCategory').on('select2:select', function (event) {\r\n\t\t\tvar tplCategory = $(event.target).val();\r\n\t\t\ttplCategoryVisible(tplCategory);\r\n\t\t});\r\n\t\t\r\n\t\tfunction tplCategoryVisible(tplCategory) {\r\n\t\t\tif(\"crud\" == tplCategory){\r\n\t\t\t\t$(\"#treeCode\").select2(\"val\", [\"\"]);\r\n\t\t\t\t$(\"#treeParentCode\").select2(\"val\", [\"\"]);\r\n\t\t\t\t$(\"#treeName\").select2(\"val\", [\"\"]);\r\n\t\t\t\t$(\"#otherInfo\").addClass(\"hidden\");\r\n\t\t\t\t$(\"#subInfo\").addClass(\"hidden\");\r\n\t\t\t} else if(\"tree\" == tplCategory){\r\n\t\t\t\t$(\"#otherInfo\").removeClass(\"hidden\");\r\n\t\t\t\t$(\"#treeCode\").attr(\"required\", \"true\");\r\n\t\t\t\t$(\"#treeParentCode\").attr(\"required\", \"true\");\r\n\t\t\t\t$(\"#treeName\").attr(\"required\", \"true\");\r\n\t\t\t\t$(\"#subInfo\").addClass(\"hidden\");\r\n\t\t\t} else if(\"sub\" == tplCategory){\r\n\t\t\t\t$(\"#subInfo\").removeClass(\"hidden\");\r\n\t\t\t\t$(\"#treeCode\").select2(\"val\", [\"\"]);\r\n\t\t\t\t$(\"#treeParentCode\").select2(\"val\", [\"\"]);\r\n\t\t\t\t$(\"#treeName\").select2(\"val\", [\"\"]);\r\n\t\t\t\t$(\"#subTableName\").attr(\"required\", \"true\");\r\n\t\t\t\t$(\"#subTableFkName\").attr(\"required\", \"true\");\r\n\t\t\t\t$(\"#otherInfo\").addClass(\"hidden\");\r\n\t\t\t}\r\n        }\r\n\t\t\r\n\t\t$('input').on('ifChecked', function(event){\r\n\t\t\tvar genType = $(event.target).val();\r\n\t\t\tpathInfoVisible(genType);\r\n\t\t});\r\n\t\t\r\n\t\tfunction pathInfoVisible(genType) {\r\n\t\t\tif(\"0\" == genType){\r\n\t\t\t\t$(\"#genPath\").val(\"/\");\r\n\t\t\t\t$(\"#pathinfo\").addClass(\"hidden\");\r\n\t\t\t} else if(\"1\" == genType){\r\n\t\t\t\t$(\"#pathinfo\").removeClass(\"hidden\");\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t// 选择字典处理函数\r\n\t\tfunction selectDictTree(columnId, obj) {\r\n\t\t\tvar dictType = $.common.nullToStr($(obj).parent().find(\"input\").val());\r\n        \tvar url = ctx + \"system/dict/selectDictTree/\" + columnId + \"/\" + dictType;\r\n\t\t\tvar options = {\r\n\t\t\t\ttitle: '选择字典类型',\r\n\t\t\t\twidth: \"380\",\r\n\t\t\t\turl: url,\r\n\t\t\t\tcallBack: doDictSubmit\r\n\t\t\t};\r\n\t\t\t$.modal.openOptions(options);\r\n\t\t}\r\n\t\t\r\n\t\t// 选择菜单处理函数\r\n        function selectMenuTree() {\r\n        \tvar parentMenuId = $(\"#parentMenuId\").val();\r\n        \tvar menuId = parentMenuId > 0 ? parentMenuId : 1;\r\n        \tvar url = ctx + \"system/menu/selectMenuTree/\" + menuId;\r\n\t\t\tvar options = {\r\n\t\t\t\ttitle: '菜单选择',\r\n\t\t\t\twidth: \"380\",\r\n\t\t\t\turl: url,\r\n\t\t\t\tcallBack: doMenuSubmit\r\n\t\t\t};\r\n\t\t\t$.modal.openOptions(options);\r\n\t\t}\r\n\t\t\r\n\t\tfunction doDictSubmit(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\tvar columnId = body.find('#columnId').val();\r\n   \t\t\tvar dictType = body.find('#dictType').val();\r\n   \t\t\t$.modal.close(index);\r\n   \t\t\t$(\"#columns_dict_\" + columnId).val(dictType);\r\n\t\t}\r\n\t\t\r\n\t\tfunction doMenuSubmit(index, layero){\r\n\t\t\tvar body = $.modal.getChildFrame(index);\r\n   \t\t\t$(\"#parentMenuId\").val(body.find('#treeId').val());\r\n   \t\t\t$(\"#parentMenuName\").val(body.find('#treeName').val());\r\n   \t\t\t$.modal.close(index);\r\n\t\t}\r\n    </script>\r\n</body>\r\n</html>\r\n\r\n\r\n<!-- java类型 -->\r\n<script id=\"javaTypeTpl\" type=\"text/x-jquery-tmpl\">\r\n<div>\r\n<select class='form-control' name='columns[${index}].javaType'>\r\n    <option value=\"Long\" {{if javaType===\"Long\"}}selected{{/if}}>Long</option>\r\n    <option value=\"String\" {{if javaType===\"String\"}}selected{{/if}}>String</option>\r\n    <option value=\"Integer\" {{if javaType===\"Integer\"}}selected{{/if}}>Integer</option>\r\n    <option value=\"Double\" {{if javaType===\"Double\"}}selected{{/if}}>Double</option>\r\n    <option value=\"BigDecimal\" {{if javaType===\"BigDecimal\"}}selected{{/if}}>BigDecimal</option>\r\n    <option value=\"Date\" {{if javaType===\"Date\"}}selected{{/if}}>Date</option>\r\n</select>\r\n</div>\r\n</script>\r\n\r\n<!-- 查询方式 -->\r\n<script id=\"queryTypeTpl\" type=\"text/x-jquery-tmpl\">\r\n<div>\r\n<select class='form-control' name='columns[${index}].queryType'>\r\n    <option value=\"EQ\" {{if queryType===\"EQ\"}}selected{{/if}}>=</option>\r\n    <option value=\"NE\" {{if queryType===\"NE\"}}selected{{/if}}>!=</option>\r\n    <option value=\"GT\" {{if queryType===\"GT\"}}selected{{/if}}>></option>\r\n    <option value=\"GTE\" {{if queryType===\"GTE\"}}selected{{/if}}>>=</option>\r\n    <option value=\"LT\" {{if queryType===\"LT\"}}selected{{/if}}><</option>\r\n    <option value=\"LTE\" {{if queryType===\"LTE\"}}selected{{/if}}><=</option>\r\n    <option value=\"LIKE\" {{if queryType===\"LIKE\"}}selected{{/if}}>Like</option>\r\n    <option value=\"BETWEEN\" {{if queryType===\"BETWEEN\"}}selected{{/if}}>Between</option>\r\n</select>\r\n</div>\r\n</script>\r\n\r\n<!-- 显示类型 -->\r\n<script id=\"htmlTypeTpl\" type=\"text/x-jquery-tmpl\">\r\n<div>\r\n<select class='form-control' name='columns[${index}].htmlType'>\r\n    <option value=\"input\" {{if htmlType===\"input\"}}selected{{/if}}>文本框</option>\r\n    <option value=\"textarea\" {{if htmlType===\"textarea\"}}selected{{/if}}>文本域</option>\r\n    <option value=\"select\" {{if htmlType===\"select\"}}selected{{/if}}>下拉框</option>\r\n    <option value=\"radio\" {{if htmlType===\"radio\"}}selected{{/if}}>单选框</option>\r\n    <option value=\"checkbox\" {{if htmlType===\"checkbox\"}}selected{{/if}}>复选框</option>\r\n    <option value=\"summernote\" {{if htmlType===\"summernote\"}}selected{{/if}}>富文本</option>\r\n    <option value=\"datetime\" {{if htmlType===\"datetime\"}}selected{{/if}}>日期控件</option>\r\n    <option value=\"upload\" {{if htmlType===\"upload\"}}selected{{/if}}>上传控件</option>\r\n</select>\r\n</div>\r\n</script>\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/templates/tool/gen/gen.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n\t<th:block th:include=\"include :: header('代码生成列表')\" />\n</head>\n<body class=\"gray-bg\">\n    <div class=\"container-div\">\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-sm-12 search-collapse\">\n\t\t\t\t<form id=\"gen-form\">\n\t\t\t\t\t<div class=\"select-list\">\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t表名称：<input type=\"text\" name=\"tableName\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t表描述：<input type=\"text\" name=\"tableComment\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li class=\"select-time\">\n\t\t\t\t\t\t\t\t<label>表时间： </label>\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[beginTime]\"/>\n\t\t\t\t\t\t\t\t<span>-</span>\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[endTime]\"/>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t\t\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\n\t\t\t     <a class=\"btn btn-success multiple disabled\" onclick=\"javascript:batchGenCode()\" shiro:hasPermission=\"tool:gen:code\">\n\t\t\t        <i class=\"fa fa-download\"></i> 生成\n\t\t\t    </a>\n\t\t\t\t<a class=\"btn btn-success\" onclick=\"createTable()\" shiro:hasRole=\"admin\">\n\t\t\t\t\t<i class=\"fa fa-plus\"></i> 创建\n\t\t\t\t</a>\n\t\t\t\t<a class=\"btn btn-info\" onclick=\"importTable()\">\n\t\t\t        <i class=\"fa fa-upload\"></i> 导入\n\t\t\t    </a>\n\t\t\t    <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.editTab()\" shiro:hasPermission=\"tool:gen:edit\">\n\t\t            <i class=\"fa fa-edit\"></i> 修改\n\t\t        </a>\n\t\t\t    <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"tool:gen:remove\">\n\t\t            <i class=\"fa fa-remove\"></i> 删除\n\t\t        </a>\n\t\t    </div>\n\t\t\n\t\t    <div class=\"col-sm-12 select-table table-striped\">\n\t\t\t    <table id=\"bootstrap-table\"></table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<th:block th:include=\"include :: footer\" />\n\t<th:block th:include=\"include :: bootstrap-table-export-js\" />\n\t<script th:src=\"@{/ajax/libs/highlight/highlight.min.js}\"></script>\n\t<script th:inline=\"javascript\">\n\t\tvar prefix = ctx + \"tool/gen\";\n\t\tvar editFlag = [[${@permission.hasPermi('tool:gen:edit')}]];\n\t\tvar removeFlag = [[${@permission.hasPermi('tool:gen:remove')}]];\n\t\tvar previewFlag = [[${@permission.hasPermi('tool:gen:preview')}]];\n\t\tvar codeFlag = [[${@permission.hasPermi('tool:gen:code')}]];\n\t\n\t\t$(function() {\n\t\t    var options = {\n\t\t        url: prefix + \"/list\",\n\t\t        updateUrl: prefix + \"/edit/{id}\",\n\t\t        removeUrl: prefix + \"/remove\",\n\t\t        sortName: \"createTime\",\n\t\t        sortOrder: \"desc\",\n\t\t        showExport: true,\n\t\t        modalName: \"生成配置\",\n\t\t        rememberSelected: true,\n\t\t        uniqueId: \"tableId\",\n\t\t        columns: [{\n\t\t        \tfield: 'state',\n\t\t            checkbox: true\n\t\t        },\n\t\t        {\n\t\t            field: 'tableId',\n\t\t            title: '编号',\n\t\t            visible: false\n\t\t        },\n\t\t        {\n                    title: \"序号\",\n                    formatter: function (value, row, index) {\n                 \t    return $.table.serialNumber(index);\n                    }\n                },\n\t\t        {\n\t\t            field: 'tableName',\n\t\t            title: '表名称',\n\t\t            sortable: true,\n\t\t            formatter: function(value, row, index) {\n                    \treturn $.table.tooltip(value);\n                    }\n\t\t        },\n\t\t        {\n\t\t            field: 'tableComment',\n\t\t            title: '表描述',\n\t\t            sortable: true,\n\t\t            formatter: function(value, row, index) {\n                    \treturn $.table.tooltip(value, 15);\n                    }\n\t\t        },\n\t\t        {\n\t\t            field: 'className',\n\t\t            title: '实体类名称',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t            field: 'createTime',\n\t\t            title: '创建时间',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t            field: 'updateTime',\n\t\t            title: '更新时间',\n\t\t            sortable: true\n\t\t        },\n\t\t        {\n\t\t            title: '操作',\n\t\t            align: 'center',\n\t\t            formatter: function(value, row, index) {\n\t\t                var actions = [];\n\t\t                actions.push('<a class=\"btn btn-info btn-xs ' + previewFlag + '\" href=\"javascript:void(0)\" onclick=\"preview(\\'' + row.tableId + '\\')\"><i class=\"fa fa-search\"></i>预览</a> ');\n\t\t                actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.editTab(\\'' + row.tableId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\n\t\t                actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.tableId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a> ');\n\t\t                actions.push('<a class=\"btn btn-warning btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"synchDb(\\'' + row.tableName + '\\')\"><i class=\"fa fa-refresh\"></i>同步</a> ');\n\t\t                actions.push('<a class=\"btn btn-primary btn-xs ' + codeFlag + '\" href=\"javascript:void(0)\" onclick=\"genCode(\\'' + row.tableName + '\\',\\'' + row.genType + '\\')\"><i class=\"fa fa-bug\"></i>生成代码</a> ');\n\t\t                return actions.join('');\n\t\t            }\n\t\t        }]\n\t\t    };\n\t\t    $.table.init(options);\n\t\t});\n\t\t\n\t\t// 预览代码\n\t\tfunction preview(tableId) {\n\t\t\tvar preViewUrl = prefix + \"/preview/\" + tableId;\n\t\t\t$.modal.loading(\"正在加载数据，请稍候...\");\n\t\t\t$.get(preViewUrl, function(result) {\n\t\t\t\tif (result.code == web_status.SUCCESS) {\n\t\t\t\t\t var items = [];\n\t\t                $.each(result.data, function(index, value) {\n\t\t                    var templateName = index.substring(index.lastIndexOf(\"/\") + 1, index.length).replace(/\\.vm/g, \"\");\n\t\t                    if(!$.common.equals(\"sql\", templateName) && !$.common.equals(\"tree.html\", templateName) && !$.common.equals(\"sub-domain.java\", templateName)){\n\t\t                        var codeName = templateName.replace(\".\", \"\");\n\t\t                        var language = templateName.substring(templateName.lastIndexOf(\".\") + 1);\n\t\t                        var highCode = hljs.highlight(language, value).value;\n\t\t                        items.push({\n\t\t                            title: templateName , content: \"<pre class=\\\"layui-code\\\"><a style=\\\"float:right\\\" href=\\\"javascript:copyText('\" + codeName + \"')\\\"><i class=\\\"fa fa-copy\\\"></i> 复制</a><code id=\\\"\" + codeName + \"\\\">\" + highCode + \"</code></pre><textarea id=\\\"t_\" + codeName + \"\\\" style='position: absolute;top: 0;left: 0;opacity: 0;z-index: -10;'></textarea><script>function copyText(codeName){var text = document.getElementById(codeName).innerText;var input = document.getElementById(\\\"t_\\\"+codeName);input.value = text;input.select();document.execCommand(\\\"copy\\\");$.modal.msgSuccess(\\\"复制成功\\\");}<\\/script>\"\n\t\t                        })\n\t\t                    }\n\t\t                });\n\t\t                top.layer.tab({\n                            area: ['90%', '90%'],\n                            shadeClose: true,\n                            success: function(layero, index){\n                                parent.loadCss(ctx + \"ajax/libs/highlight/default.min.css\");\n                            },\n\t                        tab: items\n\t\t                });\n\t\t\t\t} else {\n\t\t\t\t\t$.modal.alertError(result.msg);\n\t\t\t\t}\n\t\t\t\t$.modal.closeLoading();\n\t\t\t});\n\t\t}\n\t\n\t\t// 生成代码\n\t\tfunction genCode(tableName, genType) {\n\t\t    $.modal.confirm(\"确定要生成\" + tableName + \"表代码吗？\", function() {\n\t\t    \tif(genType === \"0\") {\n\t\t\t    \tlocation.href = prefix + \"/download/\" + tableName;\n\t\t\t        layer.msg('执行成功,正在生成代码请稍候…', { icon: 1 });\n\t\t\t\t} else if(genType === \"1\") {\n\t\t\t\t\t$.operate.get(prefix + \"/genCode/\" + tableName);\n\t\t\t\t}\n\t\t    })\n\t\t}\n\t\t\n\t\t// 同步数据库\n\t\tfunction synchDb(tableName){\n\t\t\t$.modal.confirm(\"确认要强制同步\" + tableName + \"表结构吗？\", function() {\n\t\t\t    $.operate.get(prefix + \"/synchDb/\" + tableName);\n\t\t\t})\n\t\t}\n\t\n\t\t// 批量生成代码\n\t\tfunction batchGenCode() {\n\t\t    var rows = $.table.selectColumns(\"tableName\");\n\t\t    if (rows.length == 0) {\n\t\t        $.modal.alertWarning(\"请选择要生成的数据\");\n\t\t        return;\n\t\t    }\n\t\t    $.modal.confirm(\"确认要生成选中的\" + rows.length + \"条数据吗?\", function() {\n\t\t    \tlocation.href = prefix + \"/batchGenCode?tables=\" + rows;\n\t\t        layer.msg('执行成功,正在生成代码请稍候…', { icon: 1 });\n\t\t    });\n\t\t}\n\n\t\t// 导入表结构\n\t\tfunction importTable() {\n\t\t\tvar importTableUrl = prefix + \"/importTable\";\n\t\t\t$.modal.open(\"导入表结构\", importTableUrl);\n\t\t}\n\n\t\t// 创建表结构\n\t\tfunction createTable() {\n\t\t\tvar creatTableUrl = prefix + \"/createTable\";\n\t\t\t$.modal.open(\"创建表结构\", creatTableUrl);\n\t\t}\n\t</script>\n</body>\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/templates/tool/gen/importTable.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('导入表结构')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n    <div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"gen-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t表名称：<input type=\"text\" name=\"tableName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t表描述：<input type=\"text\" name=\"tableComment\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t    <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"tool/gen\";\r\n\t\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/db/list\",\r\n\t\t        showSearch: false,\r\n\t\t        showRefresh: false,\r\n\t\t        showToggle: false,\r\n\t\t        showColumns: false,\r\n\t\t        clickToSelect: true,\r\n\t\t        rememberSelected: true,\r\n\t\t        uniqueId: \"tableName\",\r\n\t\t        columns: [{\r\n\t\t        \tfield: 'state',\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n                    title: \"序号\",\r\n                    formatter: function (value, row, index) {\r\n                 \t    return $.table.serialNumber(index);\r\n                    }\r\n                },\r\n\t\t        {\r\n\t\t            field: 'tableName',\r\n\t\t            title: '表名称',\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'tableComment',\r\n\t\t            title: '表描述',\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'updateTime',\r\n\t\t            title: '更新时间'\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t\t\r\n\t\t/* 导入表结构-选择表结构-提交 */\r\n\t\tfunction submitHandler() {\r\n\t\t\tvar rows = $.table.selectColumns(\"tableName\");\r\n\t\t\tif (rows.length == 0) {\r\n       \t\t\t$.modal.alertWarning(\"请至少选择一条记录\");\r\n       \t\t\treturn;\r\n       \t\t}\r\n\t\t\tvar data = {\"tables\": rows.join()};\r\n\t\t\t$.operate.save(prefix + \"/importTable\", data);\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/html/add.html.vm",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n    <th:block th:include=\"include :: header('新增${functionName}')\" />\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"datetime\")\r\n    <th:block th:include=\"include :: datetimepicker-css\" />\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"upload\")\r\n    <th:block th:include=\"include :: bootstrap-fileinput-css\"/>\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"summernote\")\r\n    <th:block th:include=\"include :: summernote-css\" />\r\n#break\r\n#end\r\n#end\r\n</head>\r\n<body class=\"white-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n        <form class=\"form-horizontal m\" id=\"form-${businessName}-add\">\r\n#if($table.sub)\r\n            <h4 class=\"form-header h4\">${functionName}信息</h4>\r\n#end\r\n#foreach($column in $columns)\r\n#set($field=$column.javaField)\r\n#if($column.insert && !$column.pk)\r\n#if(($column.usableColumn) || (!$column.superColumn))\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#set($dictType=$column.dictType)\r\n#if(\"\" != $treeParentCode && $column.javaField == $treeParentCode)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"input-group\">\r\n#set($BusinessName=$businessName.substring(0,1).toUpperCase() + ${businessName.substring(1)})\r\n#set($treeId = \"${className}?.${treeCode}\")\r\n                            <input id=\"treeId\" name=\"${treeParentCode}\" type=\"hidden\" th:value=\"${${treeId}}\"/>\r\n                            <input class=\"form-control\" type=\"text\" onclick=\"select${BusinessName}Tree()\" id=\"treeName\" readonly=\"true\" th:value=\"${${treeName}}\"#if($column.required) required#end>\r\n                            <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"input\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <input name=\"${field}\" class=\"form-control\" type=\"text\"#if($column.required) required#end>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"upload\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <input type=\"hidden\" name=\"${field}\">\r\n                        <div class=\"file-loading\">\r\n                            <input class=\"form-control file-upload\" id=\"${field}\" name=\"file\" type=\"file\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"summernote\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <input type=\"hidden\" class=\"form-control\" name=\"${field}\">\r\n                        <div class=\"summernote\" id=\"${field}\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"select\" && \"\" != $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <select name=\"${field}\" class=\"form-control\" th:with=\"type=${@dict.getType('${dictType}')}\"#if($column.required) required#end>\r\n                            <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n                        </select>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"select\" && $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                       <select name=\"${field}\" class=\"form-control\"#if($column.required) required#end>\r\n                            <option value=\"\">所有</option>\r\n                        </select>\r\n                        <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 代码生成请选择字典属性</span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"checkbox\" && \"\" != $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\" th:with=\"type=${@dict.getType('${dictType}')}\">\r\n                        <label th:each=\"dict : ${type}\" class=\"check-box\">\r\n                            <input name=\"${field}\" type=\"checkbox\" th:value=\"${dict.dictValue}\" th:text=\"${dict.dictLabel}\"#if($column.required) required#end>\r\n                        </label>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"checkbox\" && $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <label class=\"check-box\">\r\n                            <input name=\"${field}\" type=\"checkbox\"#if($column.required) required#end> 无\r\n                        </label>\r\n                        <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 代码生成请选择字典属性</span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"radio\" && \"\" != $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('${dictType}')}\">\r\n                            <input type=\"radio\" th:id=\"${'${field}_' + dict.dictCode}\" name=\"${field}\" th:value=\"${dict.dictValue}\" th:checked=\"${dict.default}\"#if($column.required) required#end>\r\n                            <label th:for=\"${'${field}_' + dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"radio\" && $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"radio-box\">\r\n                            <input type=\"radio\" name=\"${field}\" value=\"\"#if($column.required) required#end>\r\n                            <label th:for=\"${field}\" th:text=\"未知\"></label>\r\n                        </div>\r\n                        <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 代码生成请选择字典属性</span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"datetime\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"input-group date\">\r\n                            <input name=\"${field}\" class=\"form-control\" placeholder=\"yyyy-MM-dd\" type=\"text\"#if($column.required) required#end>\r\n                            <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"textarea\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <textarea name=\"${field}\" class=\"form-control\"#if($column.required) required#end></textarea>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#end\r\n#end\r\n#end\r\n#end\r\n#if($table.sub)\r\n            <h4 class=\"form-header h4\">${subTable.functionName}信息</h4>\r\n            <div class=\"row\">\r\n                <div class=\"col-xs-12\">\r\n                    <button type=\"button\" class=\"btn btn-white btn-sm\" onclick=\"addRow()\"><i class=\"fa fa-plus\"> 增加</i></button>\r\n                    <button type=\"button\" class=\"btn btn-white btn-sm\" onclick=\"sub.delRow()\"><i class=\"fa fa-minus\"> 删除</i></button>\r\n                    <div class=\"col-sm-12 select-table table-striped\">\r\n                        <table id=\"bootstrap-table\"></table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#end\r\n        </form>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"datetime\")\r\n    <th:block th:include=\"include :: datetimepicker-js\" />\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"upload\")\r\n    <th:block th:include=\"include :: bootstrap-fileinput-js\"/>\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"summernote\")\r\n    <th:block th:include=\"include :: summernote-js\" />\r\n#break\r\n#end\r\n#end\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"${moduleName}/${businessName}\"\r\n#if($table.sub)\r\n#foreach($column in $subTable.columns)\r\n#if(${column.dictType} != '')\r\n        var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]];\r\n#end\r\n#end\r\n#end\r\n        $(\"#form-${businessName}-add\").validate({\r\n            focusCleanup: true\r\n        });\r\n\r\n        function submitHandler() {\r\n            if ($.validate.form()) {\r\n                $.operate.save(prefix + \"/add\", $('#form-${businessName}-add').serialize());\r\n            }\r\n        }\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"datetime\")\r\n\r\n        $(\"input[name='$column.javaField']\").datetimepicker({\r\n            format: \"yyyy-mm-dd\",\r\n            minView: \"month\",\r\n            autoclose: true\r\n        });\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == \"upload\")\r\n\r\n        $(\".file-upload\").fileinput({\r\n            uploadUrl: ctx + 'common/upload',\r\n            maxFileCount: 1,\r\n            autoReplace: true\r\n        }).on('fileuploaded', function (event, data, previewId, index) {\r\n            $(\"input[name='\" + event.currentTarget.id + \"']\").val(data.response.url)\r\n        }).on('fileremoved', function (event, id, index) {\r\n            $(\"input[name='\" + event.currentTarget.id + \"']\").val('')\r\n        })\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == \"summernote\")\r\n\r\n        $(function() {\r\n            $('.summernote').summernote({\r\n                lang: 'zh-CN',\r\n                dialogsInBody: true,\r\n                callbacks: {\r\n                    onChange: function(contents, $edittable) {\r\n                        $(\"input[name='\" + this.id + \"']\").val(contents);\r\n                    },\r\n                    onImageUpload: function(files) {\r\n                        var obj = this;\r\n                    \tvar data = new FormData();\r\n                    \tdata.append(\"file\", files[0]);\r\n                    \t$.ajax({\r\n                            type: \"post\",\r\n                            url: ctx + \"common/upload\",\r\n                    \t\tdata: data,\r\n                    \t\tcache: false,\r\n                    \t\tcontentType: false,\r\n                    \t\tprocessData: false,\r\n                    \t\tdataType: 'json',\r\n                    \t\tsuccess: function(result) {\r\n                    \t\t    if (result.code == web_status.SUCCESS) {\r\n                    \t\t        $('#' + obj.id).summernote('insertImage', result.url);\r\n                    \t\t    } else {\r\n                    \t\t        $.modal.alertError(result.msg);\r\n                    \t\t    }\r\n                    \t\t},\r\n                    \t\terror: function(error) {\r\n                    \t\t    $.modal.alertWarning(\"图片上传失败。\");\r\n                    \t\t}\r\n                    \t});\r\n                    }\r\n                }\r\n            });\r\n        });\r\n#break\r\n#end\r\n#end\r\n#if($table.tree)\r\n\r\n        /*${functionName}-新增-选择父${functionName}树*/\r\n        function select${BusinessName}Tree() {\r\n            var options = {\r\n                title: '${functionName}选择',\r\n                width: \"380\",\r\n                url: prefix + \"/select${BusinessName}Tree/\" + $(\"#treeId\").val(),\r\n                callBack: doSubmit\r\n            };\r\n            $.modal.openOptions(options);\r\n        }\r\n\r\n        function doSubmit(index, layero){\r\n            var body = $.modal.getChildFrame(index);\r\n            $(\"#treeId\").val(body.find('#treeId').val());\r\n            $(\"#treeName\").val(body.find('#treeName').val());\r\n            $.modal.close(index);\r\n        }\r\n#end\r\n#if($table.sub)\r\n\r\n        $(function() {\r\n            var options = {\r\n                pagination: false,\r\n                showSearch: false,\r\n                showRefresh: false,\r\n                showToggle: false,\r\n                showColumns: false,\r\n                sidePagination: \"client\",\r\n                columns: [{\r\n                    checkbox: true\r\n                },\r\n                {\r\n                    field: 'index',\r\n                    align: 'center',\r\n                    title: \"序号\",\r\n                    formatter: function (value, row, index) {\r\n                    \tvar columnIndex = $.common.sprintf(\"<input type='hidden' name='index' value='%s'>\", $.table.serialNumber(index));\r\n                    \treturn columnIndex + $.table.serialNumber(index);\r\n                    }\r\n                },\r\n#foreach($column in $subTable.columns)\r\n#set($dictType=$column.dictType)\r\n#set($javaField=$column.javaField)\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#if($column.pk || $javaField == ${subTableFkclassName})\r\n#elseif($column.list && \"\" != $dictType)\r\n                {\r\n                    field: '${javaField}',\r\n                    align: 'center',\r\n                    title: '${comment}',\r\n                    formatter: function(value, row, index) {\r\n                        var name = $.common.sprintf(\"${subclassName}List[%s].${javaField}\", index);\r\n                        return $.common.dictToSelect(${javaField}Datas, value, name);\r\n                    }\r\n                },\r\n#else\r\n                {\r\n                    field: '${javaField}',\r\n                    align: 'center',\r\n                    title: '${comment}',\r\n                    formatter: function(value, row, index) {\r\n                        var html = $.common.sprintf(\"<input class='form-control' type='text' name='${subclassName}List[%s].${javaField}' value='%s'>\", index, value);\r\n                        return html;\r\n                    }\r\n                },\r\n#end\r\n#end\r\n                {\r\n                    title: '操作',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                        var value = $.common.isNotEmpty(row.index) ? row.index : $.table.serialNumber(index);\r\n                        return '<a class=\"btn btn-danger btn-xs\" href=\"javascript:void(0)\" onclick=\"sub.delRowByIndex(\\'' + value + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>';\r\n                    }\r\n                }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n\r\n        function addRow() {\r\n            var count = $(\"#\" + table.options.id).bootstrapTable('getData').length;\r\n            var row = {\r\n                index: $.table.serialNumber(count),\r\n#foreach($column in $subTable.columns)\r\n#set($javaField=$column.javaField)\r\n#if($column.pk || $javaField == ${subTableFkclassName})\r\n#else\r\n                ${javaField}: \"\",\r\n#end\r\n#end\r\n            }\r\n            sub.addRow(row);\r\n        }\r\n#end\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/html/edit.html.vm",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n    <th:block th:include=\"include :: header('修改${functionName}')\" />\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == \"datetime\")\r\n    <th:block th:include=\"include :: datetimepicker-css\" />\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"upload\")\r\n    <th:block th:include=\"include :: bootstrap-fileinput-css\"/>\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"summernote\")\r\n    <th:block th:include=\"include :: summernote-css\" />\r\n#break\r\n#end\r\n#end\r\n</head>\r\n<body class=\"white-bg\">\r\n    <div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n        <form class=\"form-horizontal m\" id=\"form-${businessName}-edit\" th:object=\"${${className}}\">\r\n#if($table.sub)\r\n            <h4 class=\"form-header h4\">${functionName}信息</h4>\r\n#end\r\n            <input name=\"${pkColumn.javaField}\" th:field=\"*{${pkColumn.javaField}}\" type=\"hidden\">\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.pk)\r\n#if(($column.usableColumn) || (!$column.superColumn))\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#set($field=$column.javaField)\r\n#set($dictType=$column.dictType)\r\n#if(\"\" != $treeParentCode && $column.javaField == $treeParentCode)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"input-group\">\r\n#set($BusinessName=$businessName.substring(0,1).toUpperCase() + ${businessName.substring(1)})\r\n                            <input id=\"treeId\" name=\"${treeParentCode}\" type=\"hidden\" th:field=\"*{${treeParentCode}}\" />\r\n                            <input class=\"form-control\" type=\"text\" onclick=\"select${BusinessName}Tree()\" id=\"treeName\" readonly=\"true\" th:field=\"*{parentName}\"#if($column.required) required#end>\r\n                            <span class=\"input-group-addon\"><i class=\"fa fa-search\"></i></span>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"input\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <input name=\"${field}\" th:field=\"*{${field}}\" class=\"form-control\" type=\"text\"#if($column.required) required#end>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"upload\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <input type=\"hidden\" name=\"${field}\" th:field=\"*{${field}}\">\r\n                       <div class=\"file-loading\">\r\n                            <input class=\"form-control file-upload\" id=\"${field}\" name=\"file\" type=\"file\">\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"summernote\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <input type=\"hidden\" class=\"form-control\" th:field=\"*{${field}}\">\r\n                        <div class=\"summernote\" id=\"${field}\"></div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"select\" && \"\" != $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <select name=\"${field}\" class=\"form-control\" th:with=\"type=${@dict.getType('${dictType}')}\"#if($column.required) required#end>\r\n                            <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\" th:field=\"*{${field}}\"></option>\r\n                        </select>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"select\" && $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                        <div class=\"col-sm-8\">\r\n                            <select name=\"${field}\" class=\"form-control\"#if($column.required) required#end>\r\n                                <option value=\"\">所有</option>\r\n                            </select>\r\n                            <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 代码生成请选择字典属性</span>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"checkbox\" && \"\" != $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\" th:with=\"type=${@dict.getType('${dictType}')}\">\r\n                        <label th:each=\"dict : ${type}\" class=\"check-box\">\r\n                            <input name=\"${field}\" type=\"checkbox\" th:value=\"${dict.dictValue}\" th:text=\"${dict.dictLabel}\" th:attr=\"checked=${${className}.${field}.contains(dict.dictValue)?true:false}\"#if($column.required) required#end>\r\n                        </label>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"checkbox\" && $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <label class=\"check-box\">\r\n                            <input name=\"${field}\" type=\"checkbox\"#if($column.required) required#end> 无\r\n                        </label>\r\n                        <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 代码生成请选择字典属性</span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"radio\" && \"\" != $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"radio-box\" th:each=\"dict : ${@dict.getType('${dictType}')}\">\r\n                            <input type=\"radio\" th:id=\"${'${field}_' + dict.dictCode}\" name=\"${field}\" th:value=\"${dict.dictValue}\" th:field=\"*{${field}}\"#if($column.required) required#end>\r\n                            <label th:for=\"${'${field}_' + dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"radio\" && $dictType)\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"radio-box\">\r\n                            <input type=\"radio\" name=\"${field}\" value=\"\"#if($column.required) required#end>\r\n                            <label th:for=\"${field}\" th:text=\"未知\"></label>\r\n                        </div>\r\n                        <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 代码生成请选择字典属性</span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"datetime\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <div class=\"input-group date\">\r\n                            <input name=\"${field}\" th:value=\"${#dates.format(${className}.${field}, 'yyyy-MM-dd')}\" class=\"form-control\" placeholder=\"yyyy-MM-dd\" type=\"text\"#if($column.required) required#end>\r\n                            <span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#elseif($column.htmlType == \"textarea\")\r\n            <div class=\"${colXsNum}\">\r\n                <div class=\"form-group\">\r\n                    <label class=\"${colSmNum} control-label#if($column.required) is-required#end\">${comment}：</label>\r\n                    <div class=\"col-sm-8\">\r\n                        <textarea name=\"${field}\" class=\"form-control\"#if($column.required) required#end>[[*{${field}}]]</textarea>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#end\r\n#end\r\n#end\r\n#end\r\n#if($table.sub)\r\n            <h4 class=\"form-header h4\">${subTable.functionName}信息</h4>\r\n            <div class=\"row\">\r\n                <div class=\"col-sm-12\">\r\n                    <button type=\"button\" class=\"btn btn-white btn-sm\" onclick=\"addRow()\"><i class=\"fa fa-plus\"> 增加</i></button>\r\n                    <button type=\"button\" class=\"btn btn-white btn-sm\" onclick=\"sub.delRow()\"><i class=\"fa fa-minus\"> 删除</i></button>\r\n                    <div class=\"col-sm-12 select-table table-striped\">\r\n                        <table id=\"bootstrap-table\"></table>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n#end\r\n        </form>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == \"datetime\")\r\n    <th:block th:include=\"include :: datetimepicker-js\" />\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"upload\")\r\n    <th:block th:include=\"include :: bootstrap-fileinput-js\"/>\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == \"summernote\")\r\n    <th:block th:include=\"include :: summernote-js\" />\r\n#break\r\n#end\r\n#end\r\n    <script th:inline=\"javascript\">\r\n        var prefix = ctx + \"${moduleName}/${businessName}\";\r\n#if($table.sub)\r\n#foreach($column in $subTable.columns)\r\n#if(${column.dictType} != '')\r\n        var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]];\r\n#end\r\n#end\r\n#end\r\n        $(\"#form-${businessName}-edit\").validate({\r\n            focusCleanup: true\r\n        });\r\n\r\n        function submitHandler() {\r\n            if ($.validate.form()) {\r\n                $.operate.save(prefix + \"/edit\", $('#form-${businessName}-edit').serialize());\r\n            }\r\n        }\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == \"datetime\")\r\n\r\n        $(\"input[name='$column.javaField']\").datetimepicker({\r\n            format: \"yyyy-mm-dd\",\r\n            minView: \"month\",\r\n            autoclose: true\r\n        });\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == \"upload\")\r\n\r\n        $(\".file-upload\").each(function (i) {\r\n            var val = $(\"input[name='\" + this.id + \"']\").val()\r\n            $(this).fileinput({\r\n                'uploadUrl': ctx + 'common/upload',\r\n                initialPreviewAsData: true,\r\n                initialPreview: [val],\r\n                maxFileCount: 1,\r\n                autoReplace: true\r\n            }).on('fileuploaded', function (event, data, previewId, index) {\r\n                $(\"input[name='\" + event.currentTarget.id + \"']\").val(data.response.url)\r\n            }).on('fileremoved', function (event, id, index) {\r\n                $(\"input[name='\" + event.currentTarget.id + \"']\").val('')\r\n            })\r\n            $(this).fileinput('_initFileActions');\r\n        });\r\n#break\r\n#end\r\n#end\r\n#foreach($column in $columns)\r\n#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == \"summernote\")\r\n\r\n        $(function() {\r\n            $('.summernote').each(function(i) {\r\n                $('#' + this.id).summernote({\r\n                    lang: 'zh-CN',\r\n                    dialogsInBody: true,\r\n                    callbacks: {\r\n                        onChange: function(contents, $edittable) {\r\n                            $(\"input[name='\" + this.id + \"']\").val(contents);\r\n                        },\r\n                        onImageUpload: function(files) {\r\n                            var obj = this;\r\n                            var data = new FormData();\r\n                            data.append(\"file\", files[0]);\r\n                            $.ajax({\r\n                                type: \"post\",\r\n                                url: ctx + \"common/upload\",\r\n                                data: data,\r\n                                cache: false,\r\n                                contentType: false,\r\n                                processData: false,\r\n                                dataType: 'json',\r\n                                success: function(result) {\r\n                                    if (result.code == web_status.SUCCESS) {\r\n                                        $('#' + obj.id).summernote('insertImage', result.url);\r\n                                    } else {\r\n                                        $.modal.alertError(result.msg);\r\n                                    }\r\n                                },\r\n                                error: function(error) {\r\n                                    $.modal.alertWarning(\"图片上传失败。\");\r\n                                }\r\n                            });\r\n                        }\r\n                    }\r\n                });\r\n                var content = $(\"input[name='\" + this.id + \"']\").val();\r\n                $('#' + this.id).summernote('code', content);\r\n            })\r\n        });\r\n#break\r\n#end\r\n#end\r\n#if($table.tree)\r\n\r\n        /*${functionName}-编辑-选择父${functionName}树*/\r\n        function select${BusinessName}Tree() {\r\n            var options = {\r\n                title: '${functionName}选择',\r\n                width: \"380\",\r\n                url: prefix + \"/select${BusinessName}Tree/\" + $(\"#treeId\").val(),\r\n                callBack: doSubmit\r\n            };\r\n            $.modal.openOptions(options);\r\n        }\r\n\r\n        function doSubmit(index, layero){\r\n            var body = $.modal.getChildFrame(index);\r\n            $(\"#treeId\").val(body.find('#treeId').val());\r\n            $(\"#treeName\").val(body.find('#treeName').val());\r\n            $.modal.close(index);\r\n        }\r\n#end\r\n#if($table.sub)\r\n\r\n        $(function() {\r\n            var options = {\r\n                data: [[${${className}.${subclassName}List}]],\r\n                pagination: false,\r\n                showSearch: false,\r\n                showRefresh: false,\r\n                showToggle: false,\r\n                showColumns: false,\r\n                sidePagination: \"client\",\r\n                columns: [{\r\n                    checkbox: true\r\n                },\r\n                {\r\n                    field: 'index',\r\n                    align: 'center',\r\n                    title: \"序号\",\r\n                    formatter: function (value, row, index) {\r\n                    \tvar columnIndex = $.common.sprintf(\"<input type='hidden' name='index' value='%s'>\", $.table.serialNumber(index));\r\n                    \treturn columnIndex + $.table.serialNumber(index);\r\n                    }\r\n                },\r\n#foreach($column in $subTable.columns)\r\n#set($dictType=$column.dictType)\r\n#set($javaField=$column.javaField)\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#if($column.pk || $javaField == ${subTableFkclassName})\r\n#elseif($column.list && \"\" != $dictType)\r\n                {\r\n                    field: '${javaField}',\r\n                    align: 'center',\r\n                    title: '${comment}',\r\n                    formatter: function(value, row, index) {\r\n                        var name = $.common.sprintf(\"${subclassName}List[%s].${javaField}\", index);\r\n                        return $.common.dictToSelect(${javaField}Datas, value, name);\r\n                    }\r\n                },\r\n#else\r\n                {\r\n                    field: '${javaField}',\r\n                    align: 'center',\r\n                    title: '${comment}',\r\n                    formatter: function(value, row, index) {\r\n                        var html = $.common.sprintf(\"<input class='form-control' type='text' name='${subclassName}List[%s].${javaField}' value='%s'>\", index, value);\r\n                        return html;\r\n                    }\r\n                },\r\n\r\n#end\r\n#end\r\n                {\r\n                    title: '操作',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                        var value = $.common.isNotEmpty(row.index) ? row.index : $.table.serialNumber(index);\r\n                        return '<a class=\"btn btn-danger btn-xs\" href=\"javascript:void(0)\" onclick=\"sub.delRowByIndex(\\'' + value + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>';\r\n                    }\r\n                }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n\r\n        function addRow() {\r\n            var count = $(\"#\" + table.options.id).bootstrapTable('getData').length;\r\n            var row = {\r\n                index: $.table.serialNumber(count),\r\n#foreach($column in $subTable.columns)\r\n#set($javaField=$column.javaField)\r\n#if($column.pk || $javaField == ${subTableFkclassName})\r\n#else\r\n                ${javaField}: \"\",\r\n#end\r\n#end\r\n            }\r\n            sub.addRow(row);\r\n        }\r\n#end\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/html/list-tree.html.vm",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n    <th:block th:include=\"include :: header('${functionName}列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12 search-collapse\">\r\n                <form id=\"formId\">\r\n                    <div class=\"select-list\">\r\n                        <ul>\r\n#foreach($column in $columns)\r\n#if($column.query)\r\n#set($dictType=$column.dictType)\r\n#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else  \r\n#set($comment=$column.columnComment)\r\n#end  \r\n#if($column.htmlType == \"input\")\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <input type=\"text\" name=\"${column.javaField}\"/>\r\n                            </li>\r\n#elseif(($column.htmlType == \"select\" || $column.htmlType == \"radio\") && \"\" != $dictType)\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <select name=\"${column.javaField}\" th:with=\"type=${@dict.getType('${dictType}')}\">\r\n                                    <option value=\"\">所有</option>\r\n                                    <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n                                </select>\r\n                            </li>\r\n#elseif(($column.htmlType == \"select\" || $column.htmlType == \"radio\") && $dictType)\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <select name=\"${column.javaField}\">\r\n                                    <option value=\"\">所有</option>\r\n                                    <option value=\"-1\">代码生成请选择字典属性</option>\r\n                                </select>\r\n                            </li>\r\n#elseif($column.htmlType == \"datetime\" && $column.queryType != \"BETWEEN\")\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <input type=\"text\" class=\"time-input\" placeholder=\"请选择${comment}\" name=\"${column.javaField}\"/>\r\n                            </li>\r\n#elseif($column.htmlType == \"datetime\" && $column.queryType == \"BETWEEN\")\r\n                            <li class=\"select-time\">\r\n                                <label>${comment}：</label>\r\n                                <input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[begin${AttrName}]\"/>\r\n                                <span>-</span>\r\n                                <input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[end${AttrName}]\"/>\r\n                            </li>                \r\n#end\r\n#end\r\n#end\r\n                            <li>\r\n                                <a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.treeTable.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n                                <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n                            </li>\r\n                        </ul>\r\n                    </div>\r\n                </form>\r\n            </div>\r\n\r\n            <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n                <a class=\"btn btn-success\" onclick=\"$.operate.add()\" shiro:hasPermission=\"${permissionPrefix}:add\">\r\n                    <i class=\"fa fa-plus\"></i> 新增\r\n                </a>\r\n                <a class=\"btn btn-primary\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"${permissionPrefix}:edit\">\r\n                    <i class=\"fa fa-edit\"></i> 修改\r\n                </a>\r\n                <a class=\"btn btn-info\" id=\"expandAllBtn\">\r\n                    <i class=\"fa fa-exchange\"></i> 展开/折叠\r\n                </a>\r\n            </div>\r\n            <div class=\"col-sm-12 select-table table-striped\">\r\n                <table id=\"bootstrap-tree-table\"></table>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script th:inline=\"javascript\">\r\n        var addFlag = [[${@permission.hasPermi('${permissionPrefix}:add')}]];\r\n        var editFlag = [[${@permission.hasPermi('${permissionPrefix}:edit')}]];\r\n        var removeFlag = [[${@permission.hasPermi('${permissionPrefix}:remove')}]];\r\n#foreach($column in $columns)\r\n#if(${column.dictType} != '')\r\n        var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]];\r\n#end\r\n#end\r\n        var prefix = ctx + \"${moduleName}/${businessName}\";\r\n\r\n        $(function() {\r\n            var options = {\r\n                code: \"${treeCode}\",\r\n                parentCode: \"${treeParentCode}\",\r\n                expandColumn: \"${expandColumn}\",\r\n                uniqueId: \"${pkColumn.javaField}\",\r\n                url: prefix + \"/list\",\r\n                createUrl: prefix + \"/add/{id}\",\r\n                updateUrl: prefix + \"/edit/{id}\",\r\n                removeUrl: prefix + \"/remove/{id}\",\r\n                modalName: \"${functionName}\",\r\n                columns: [{\r\n                    field: 'selectItem',\r\n                    radio: true\r\n                },\r\n#foreach($column in $columns)\r\n#set($dictType=$column.dictType)\r\n#set($javaField=$column.javaField)\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#if($column.pk)\r\n#elseif($column.list && \"\" != $dictType)\r\n                {\r\n                    field: '${javaField}',\r\n                    title: '${comment}',\r\n                    align: 'left',\r\n                    formatter: function(value, row, index) {\r\n                        return $.table.selectDictLabel#if($column.htmlType == \"checkbox\")s#end(${javaField}Datas, value);\r\n                    }\r\n                },\r\n#elseif($column.list && \"\" != $javaField)\r\n                {\r\n                    field: '${javaField}',\r\n                    title: '${comment}',\r\n                    align: 'left'\r\n                },\r\n#end                \r\n#end\r\n                {\r\n                    title: '操作',\r\n                    align: 'center',\r\n                    align: 'left',\r\n                    formatter: function(value, row, index) {\r\n                        var actions = [];\r\n                        actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.${pkColumn.javaField} + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-info  btn-xs ' + addFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.add(\\'' + row.${pkColumn.javaField} + '\\')\"><i class=\"fa fa-plus\"></i>新增</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.${pkColumn.javaField} + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n                        return actions.join('');\r\n                    }\r\n                }]\r\n            };\r\n            $.treeTable.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/html/list.html.vm",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n    <th:block th:include=\"include :: header('${functionName}列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n     <div class=\"container-div\">\r\n        <div class=\"row\">\r\n            <div class=\"col-sm-12 search-collapse\">\r\n                <form id=\"formId\">\r\n                    <div class=\"select-list\">\r\n                        <ul>\r\n#foreach($column in $columns)\r\n#if($column.query)\r\n#set($dictType=$column.dictType)\r\n#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else  \r\n#set($comment=$column.columnComment)\r\n#end  \r\n#if($column.htmlType == \"input\")\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <input type=\"text\" name=\"${column.javaField}\"/>\r\n                            </li>\r\n#elseif(($column.htmlType == \"select\" || $column.htmlType == \"radio\") && \"\" != $dictType)\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <select name=\"${column.javaField}\" th:with=\"type=${@dict.getType('${dictType}')}\">\r\n                                    <option value=\"\">所有</option>\r\n                                    <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n                                </select>\r\n                            </li>\r\n#elseif(($column.htmlType == \"select\" || $column.htmlType == \"radio\") && $dictType)\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <select name=\"${column.javaField}\">\r\n                                    <option value=\"\">所有</option>\r\n                                    <option value=\"-1\">代码生成请选择字典属性</option>\r\n                                </select>\r\n                            </li>\r\n#elseif($column.htmlType == \"datetime\" && $column.queryType != \"BETWEEN\")\r\n                            <li>\r\n                                <label>${comment}：</label>\r\n                                <input type=\"text\" class=\"time-input\" placeholder=\"请选择${comment}\" name=\"${column.javaField}\"/>\r\n                            </li>\r\n#elseif($column.htmlType == \"datetime\" && $column.queryType == \"BETWEEN\")\r\n                            <li class=\"select-time\">\r\n                                <label>${comment}：</label>\r\n                                <input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[begin${AttrName}]\"/>\r\n                                <span>-</span>\r\n                                <input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[end${AttrName}]\"/>\r\n                            </li>\r\n#end\r\n#end\r\n#end\r\n                            <li>\r\n                                <a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n                                <a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n                            </li>\r\n                        </ul>\r\n                    </div>\r\n                </form>\r\n            </div>\r\n\r\n            <div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n                <a class=\"btn btn-success\" onclick=\"$.operate.add()\" shiro:hasPermission=\"${permissionPrefix}:add\">\r\n                    <i class=\"fa fa-plus\"></i> 添加\r\n                </a>\r\n                <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"${permissionPrefix}:edit\">\r\n                    <i class=\"fa fa-edit\"></i> 修改\r\n                </a>\r\n                <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"${permissionPrefix}:remove\">\r\n                    <i class=\"fa fa-remove\"></i> 删除\r\n                </a>\r\n                <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"${permissionPrefix}:export\">\r\n                    <i class=\"fa fa-download\"></i> 导出\r\n                </a>\r\n            </div>\r\n            <div class=\"col-sm-12 select-table table-striped\">\r\n                <table id=\"bootstrap-table\"></table>\r\n            </div>\r\n        </div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <script th:inline=\"javascript\">\r\n        var editFlag = [[${@permission.hasPermi('${permissionPrefix}:edit')}]];\r\n        var removeFlag = [[${@permission.hasPermi('${permissionPrefix}:remove')}]];\r\n#foreach($column in $columns)\r\n#if(${column.dictType} != '')\r\n        var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]];\r\n#end\r\n#end\r\n        var prefix = ctx + \"${moduleName}/${businessName}\";\r\n\r\n        $(function() {\r\n            var options = {\r\n                url: prefix + \"/list\",\r\n                createUrl: prefix + \"/add\",\r\n                updateUrl: prefix + \"/edit/{id}\",\r\n                removeUrl: prefix + \"/remove\",\r\n                exportUrl: prefix + \"/export\",\r\n                modalName: \"${functionName}\",\r\n                columns: [{\r\n                    checkbox: true\r\n                },\r\n#foreach($column in $columns)\r\n#set($dictType=$column.dictType)\r\n#set($javaField=$column.javaField)\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#if($column.pk)\r\n                {\r\n                    field: '${javaField}',\r\n                    title: '${comment}',\r\n                    visible: false\r\n                },\r\n#elseif($column.list && \"\" != $dictType)\r\n                {\r\n                    field: '${javaField}',\r\n                    title: '${comment}',\r\n                    formatter: function(value, row, index) {\r\n                       return $.table.selectDictLabel#if($column.htmlType == \"checkbox\")s#end(${javaField}Datas, value);\r\n                    }\r\n                },\r\n#elseif($column.list && \"\" != $javaField)\r\n                {\r\n                    field: '${javaField}',\r\n                    title: '${comment}'\r\n                },\r\n#end                \r\n#end\r\n                {\r\n                    title: '操作',\r\n                    align: 'center',\r\n                    formatter: function(value, row, index) {\r\n                        var actions = [];\r\n                        actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.edit(\\'' + row.${pkColumn.javaField} + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n                        actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.remove(\\'' + row.${pkColumn.javaField} + '\\')\"><i class=\"fa fa-remove\"></i>删除</a>');\r\n                        return actions.join('');\r\n                    }\r\n                }]\r\n            };\r\n            $.table.init(options);\r\n        });\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/html/tree.html.vm",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n    <th:block th:include=\"include :: header('${functionName}树选择')\" />\r\n    <th:block th:include=\"include :: ztree-css\" />\r\n</head>\r\n<style>\r\n    body{height:auto;font-family: \"Microsoft YaHei\";}\r\n    button{font-family: \"SimSun\",\"Helvetica Neue\",Helvetica,Arial;}\r\n</style>\r\n<body class=\"hold-transition box box-main\">\r\n#set($treeId = \"${className}?.\" + $treeCode)\r\n#set($treeName = \"${className}?.\" + $treeName)\r\n    <input id=\"treeId\"   name=\"treeId\"    type=\"hidden\" th:value=\"${${treeId}}\"/>\r\n    <input id=\"treeName\" name=\"treeName\"  type=\"hidden\" th:value=\"${${treeName}}\"/>\r\n    <div class=\"wrapper\"><div class=\"treeShowHideButton\" onclick=\"$.tree.toggleSearch();\">\r\n        <label id=\"btnShow\" title=\"显示搜索\" style=\"display:none;\">︾</label>\r\n        <label id=\"btnHide\" title=\"隐藏搜索\">︽</label>\r\n    </div>\r\n    <div class=\"treeSearchInput\" id=\"search\">\r\n        <label for=\"keyword\">关键字：</label><input type=\"text\" class=\"empty\" id=\"keyword\" maxlength=\"50\">\r\n        <button class=\"btn\" id=\"btn\" onclick=\"$.tree.searchNode()\"> 搜索 </button>\r\n    </div>\r\n    <div class=\"treeExpandCollapse\">\r\n        <a href=\"javascript:;\" onclick=\"$.tree.expand()\">展开</a> /\r\n        <a href=\"javascript:;\" onclick=\"$.tree.collapse()\">折叠</a>\r\n    </div>\r\n    <div id=\"tree\" class=\"ztree treeselect\"></div>\r\n    </div>\r\n    <th:block th:include=\"include :: footer\" />\r\n    <th:block th:include=\"include :: ztree-js\" />\r\n    <script th:inline=\"javascript\">\r\n        $(function() {\r\n            var url = ctx + \"${moduleName}/${businessName}/treeData\";\r\n            var options = {\r\n                url: url,\r\n                expandLevel: 2,\r\n                onClick : zOnClick\r\n            };\r\n            $.tree.init(options);\r\n        });\r\n\r\n        function zOnClick(event, treeId, treeNode) {\r\n            var treeId = treeNode.id;\r\n            var treeName = treeNode.name;\r\n            $(\"#treeId\").val(treeId);\r\n            $(\"#treeName\").val(treeName);\r\n        }\r\n    </script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/java/controller.java.vm",
    "content": "package ${packageName}.controller;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport ${packageName}.domain.${ClassName};\r\nimport ${packageName}.service.I${ClassName}Service;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\n#if($table.crud || $table.sub)\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\n#elseif($table.tree)\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\n#end\r\n\r\n/**\r\n * ${functionName}Controller\r\n * \r\n * @author ${author}\r\n * @date ${datetime}\r\n */\r\n@Controller\r\n@RequestMapping(\"/${moduleName}/${businessName}\")\r\npublic class ${ClassName}Controller extends BaseController\r\n{\r\n    private String prefix = \"${moduleName}/${businessName}\";\r\n\r\n    @Autowired\r\n    private I${ClassName}Service ${className}Service;\r\n\r\n    @RequiresPermissions(\"${permissionPrefix}:view\")\r\n    @GetMapping()\r\n    public String ${businessName}()\r\n    {\r\n        return prefix + \"/${businessName}\";\r\n    }\r\n\r\n#if($table.crud || $table.sub)\r\n    /**\r\n     * 查询${functionName}列表\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(${ClassName} ${className})\r\n    {\r\n        startPage();\r\n        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});\r\n        return getDataTable(list);\r\n    }\r\n#elseif($table.tree)\r\n    /**\r\n     * 查询${functionName}树列表\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public List<${ClassName}> list(${ClassName} ${className})\r\n    {\r\n        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});\r\n        return list;\r\n    }\r\n#end\r\n\r\n    /**\r\n     * 导出${functionName}列表\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:export\")\r\n    @Log(title = \"${functionName}\", businessType = BusinessType.EXPORT)\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(${ClassName} ${className})\r\n    {\r\n        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});\r\n        ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);\r\n        return util.exportExcel(list, \"${functionName}数据\");\r\n    }\r\n\r\n#if($table.crud || $table.sub)\r\n    /**\r\n     * 新增${functionName}\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:add\")\r\n    @GetMapping(\"/add\")\r\n    public String add()\r\n    {\r\n        return prefix + \"/add\";\r\n    }\r\n#elseif($table.tree)\r\n    /**\r\n     * 新增${functionName}\r\n     */\r\n    @GetMapping(value = { \"/add/{${pkColumn.javaField}}\", \"/add/\" })\r\n    public String add(@PathVariable(value = \"${pkColumn.javaField}\", required = false) Long ${pkColumn.javaField}, ModelMap mmap)\r\n    {\r\n        if (StringUtils.isNotNull(${pkColumn.javaField}))\r\n        {\r\n            mmap.put(\"${className}\", ${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));\r\n        }\r\n        return prefix + \"/add\";\r\n    }\r\n#end\r\n\r\n    /**\r\n     * 新增保存${functionName}\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:add\")\r\n    @Log(title = \"${functionName}\", businessType = BusinessType.INSERT)\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(${ClassName} ${className})\r\n    {\r\n        return toAjax(${className}Service.insert${ClassName}(${className}));\r\n    }\r\n\r\n    /**\r\n     * 修改${functionName}\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:edit\")\r\n    @GetMapping(\"/edit/{${pkColumn.javaField}}\")\r\n    public String edit(@PathVariable(\"${pkColumn.javaField}\") ${pkColumn.javaType} ${pkColumn.javaField}, ModelMap mmap)\r\n    {\r\n        ${ClassName} ${className} = ${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});\r\n        mmap.put(\"${className}\", ${className});\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存${functionName}\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:edit\")\r\n    @Log(title = \"${functionName}\", businessType = BusinessType.UPDATE)\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(${ClassName} ${className})\r\n    {\r\n        return toAjax(${className}Service.update${ClassName}(${className}));\r\n    }\r\n\r\n#if($table.crud || $table.sub)\r\n    /**\r\n     * 删除${functionName}\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:remove\")\r\n    @Log(title = \"${functionName}\", businessType = BusinessType.DELETE)\r\n    @PostMapping( \"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(ids));\r\n    }\r\n#elseif($table.tree)\r\n    /**\r\n     * 删除\r\n     */\r\n    @RequiresPermissions(\"${permissionPrefix}:remove\")\r\n    @Log(title = \"${functionName}\", businessType = BusinessType.DELETE)\r\n    @GetMapping(\"/remove/{${pkColumn.javaField}}\")\r\n    @ResponseBody\r\n    public AjaxResult remove(@PathVariable(\"${pkColumn.javaField}\") ${pkColumn.javaType} ${pkColumn.javaField})\r\n    {\r\n        return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));\r\n    }\r\n#end\r\n#if($table.tree)\r\n\r\n    /**\r\n     * 选择${functionName}树\r\n     */\r\n#set($BusinessName=$businessName.substring(0,1).toUpperCase() + ${businessName.substring(1)})\r\n    @GetMapping(value = { \"/select${BusinessName}Tree/{${pkColumn.javaField}}\", \"/select${BusinessName}Tree/\" })\r\n    public String select${BusinessName}Tree(@PathVariable(value = \"${pkColumn.javaField}\", required = false) Long ${pkColumn.javaField}, ModelMap mmap)\r\n    {\r\n        if (StringUtils.isNotNull(${pkColumn.javaField}))\r\n        {\r\n            mmap.put(\"${className}\", ${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));\r\n        }\r\n        return prefix + \"/tree\";\r\n    }\r\n\r\n    /**\r\n     * 加载${functionName}树列表\r\n     */\r\n    @GetMapping(\"/treeData\")\r\n    @ResponseBody\r\n    public List<Ztree> treeData()\r\n    {\r\n        List<Ztree> ztrees = ${className}Service.select${ClassName}Tree();\r\n        return ztrees;\r\n    }\r\n#end\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/java/domain.java.vm",
    "content": "package ${packageName}.domain;\r\n\r\n#foreach ($import in $importList)\r\nimport ${import};\r\n#end\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\n#if($table.crud || $table.sub)\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n#elseif($table.tree)\r\nimport com.ruoyi.common.core.domain.TreeEntity;\r\n#end\r\n\r\n/**\r\n * ${functionName}对象 ${tableName}\r\n * \r\n * @author ${author}\r\n * @date ${datetime}\r\n */\r\n#if($table.crud || $table.sub)\r\n#set($Entity=\"BaseEntity\")\r\n#elseif($table.tree)\r\n#set($Entity=\"TreeEntity\")\r\n#end\r\npublic class ${ClassName} extends ${Entity}\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n#foreach ($column in $columns)\r\n#if(!$table.isSuperColumn($column.javaField))\r\n    /** $column.columnComment */\r\n#if($column.list)\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#if($parentheseIndex != -1)\r\n    @Excel(name = \"${comment}\", readConverterExp = \"$column.readConverterExp()\")\r\n#elseif($column.javaType == 'Date')\r\n    @JsonFormat(pattern = \"yyyy-MM-dd\", timezone = \"GMT+8\")\r\n    @Excel(name = \"${comment}\", width = 30, dateFormat = \"yyyy-MM-dd\")\r\n#else\r\n    @Excel(name = \"${comment}\")\r\n#end\r\n#end\r\n    private $column.javaType $column.javaField;\r\n\r\n#end\r\n#end\r\n#if($table.sub)\r\n    /** $table.subTable.functionName信息 */\r\n    private List<${subClassName}> ${subclassName}List;\r\n\r\n#end\r\n#foreach ($column in $columns)\r\n#if(!$table.isSuperColumn($column.javaField))\r\n#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches(\"[A-Z]\"))\r\n#set($AttrName=$column.javaField)\r\n#else\r\n#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})\r\n#end\r\n    public void set${AttrName}($column.javaType $column.javaField) \r\n    {\r\n        this.$column.javaField = $column.javaField;\r\n    }\r\n\r\n    public $column.javaType get${AttrName}() \r\n    {\r\n        return $column.javaField;\r\n    }\r\n\r\n#end\r\n#end\r\n#if($table.sub)\r\n    public List<${subClassName}> get${subClassName}List()\r\n    {\r\n        return ${subclassName}List;\r\n    }\r\n\r\n    public void set${subClassName}List(List<${subClassName}> ${subclassName}List)\r\n    {\r\n        this.${subclassName}List = ${subclassName}List;\r\n    }\r\n\r\n#end\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n#foreach ($column in $columns)\r\n#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches(\"[A-Z]\"))\r\n#set($AttrName=$column.javaField)\r\n#else\r\n#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})\r\n#end\r\n            .append(\"${column.javaField}\", get${AttrName}())\r\n#end\r\n#if($table.sub)\r\n            .append(\"${subclassName}List\", get${subClassName}List())\r\n#end\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/java/mapper.java.vm",
    "content": "package ${packageName}.mapper;\r\n\r\nimport java.util.List;\r\nimport ${packageName}.domain.${ClassName};\r\n#if($table.sub)\r\nimport ${packageName}.domain.${subClassName};\r\n#end\r\n\r\n/**\r\n * ${functionName}Mapper接口\r\n * \r\n * @author ${author}\r\n * @date ${datetime}\r\n */\r\npublic interface ${ClassName}Mapper \r\n{\r\n    /**\r\n     * 查询${functionName}\r\n     * \r\n     * @param ${pkColumn.javaField} ${functionName}主键\r\n     * @return ${functionName}\r\n     */\r\n    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});\r\n\r\n    /**\r\n     * 查询${functionName}列表\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return ${functionName}集合\r\n     */\r\n    public List<${ClassName}> select${ClassName}List(${ClassName} ${className});\r\n\r\n    /**\r\n     * 新增${functionName}\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return 结果\r\n     */\r\n    public int insert${ClassName}(${ClassName} ${className});\r\n\r\n    /**\r\n     * 修改${functionName}\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return 结果\r\n     */\r\n    public int update${ClassName}(${ClassName} ${className});\r\n\r\n    /**\r\n     * 删除${functionName}\r\n     * \r\n     * @param ${pkColumn.javaField} ${functionName}主键\r\n     * @return 结果\r\n     */\r\n    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});\r\n\r\n    /**\r\n     * 批量删除${functionName}\r\n     * \r\n     * @param ${pkColumn.javaField}s 需要删除的数据主键集合\r\n     * @return 结果\r\n     */\r\n    public int delete${ClassName}By${pkColumn.capJavaField}s(String[] ${pkColumn.javaField}s);\r\n#if($table.sub)\r\n\r\n    /**\r\n     * 批量删除${subTable.functionName}\r\n     * \r\n     * @param ${pkColumn.javaField}s 需要删除的数据主键集合\r\n     * @return 结果\r\n     */\r\n    public int delete${subClassName}By${subTableFkClassName}s(String[] ${pkColumn.javaField}s);\r\n    \r\n    /**\r\n     * 批量新增${subTable.functionName}\r\n     * \r\n     * @param ${subclassName}List ${subTable.functionName}列表\r\n     * @return 结果\r\n     */\r\n    public int batch${subClassName}(List<${subClassName}> ${subclassName}List);\r\n    \r\n\r\n    /**\r\n     * 通过${functionName}主键删除${subTable.functionName}信息\r\n     * \r\n     * @param ${pkColumn.javaField} ${functionName}ID\r\n     * @return 结果\r\n     */\r\n    public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});\r\n#end\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/java/service.java.vm",
    "content": "package ${packageName}.service;\r\n\r\nimport java.util.List;\r\nimport ${packageName}.domain.${ClassName};\r\n#if($table.tree)\r\nimport com.ruoyi.common.core.domain.Ztree;\r\n#end\r\n\r\n/**\r\n * ${functionName}Service接口\r\n * \r\n * @author ${author}\r\n * @date ${datetime}\r\n */\r\npublic interface I${ClassName}Service \r\n{\r\n    /**\r\n     * 查询${functionName}\r\n     * \r\n     * @param ${pkColumn.javaField} ${functionName}主键\r\n     * @return ${functionName}\r\n     */\r\n    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});\r\n\r\n    /**\r\n     * 查询${functionName}列表\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return ${functionName}集合\r\n     */\r\n    public List<${ClassName}> select${ClassName}List(${ClassName} ${className});\r\n\r\n    /**\r\n     * 新增${functionName}\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return 结果\r\n     */\r\n    public int insert${ClassName}(${ClassName} ${className});\r\n\r\n    /**\r\n     * 修改${functionName}\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return 结果\r\n     */\r\n    public int update${ClassName}(${ClassName} ${className});\r\n\r\n    /**\r\n     * 批量删除${functionName}\r\n     * \r\n     * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合\r\n     * @return 结果\r\n     */\r\n    public int delete${ClassName}By${pkColumn.capJavaField}s(String ${pkColumn.javaField}s);\r\n\r\n    /**\r\n     * 删除${functionName}信息\r\n     * \r\n     * @param ${pkColumn.javaField} ${functionName}主键\r\n     * @return 结果\r\n     */\r\n    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});\r\n#if($table.tree)\r\n\r\n    /**\r\n     * 查询${functionName}树列表\r\n     * \r\n     * @return 所有${functionName}信息\r\n     */\r\n    public List<Ztree> select${ClassName}Tree();\r\n#end\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm",
    "content": "package ${packageName}.service.impl;\r\n\r\nimport java.util.List;\r\n#if($table.tree)\r\nimport java.util.ArrayList;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\n#end\r\n#foreach ($column in $columns)\r\n#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')\r\nimport com.ruoyi.common.utils.DateUtils;\r\n#break\r\n#end\r\n#end\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\n#if($table.sub)\r\nimport java.util.ArrayList;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport org.springframework.transaction.annotation.Transactional;\r\nimport ${packageName}.domain.${subClassName};\r\n#end\r\nimport ${packageName}.mapper.${ClassName}Mapper;\r\nimport ${packageName}.domain.${ClassName};\r\nimport ${packageName}.service.I${ClassName}Service;\r\nimport com.ruoyi.common.core.text.Convert;\r\n\r\n/**\r\n * ${functionName}Service业务层处理\r\n * \r\n * @author ${author}\r\n * @date ${datetime}\r\n */\r\n@Service\r\npublic class ${ClassName}ServiceImpl implements I${ClassName}Service \r\n{\r\n    @Autowired\r\n    private ${ClassName}Mapper ${className}Mapper;\r\n\r\n    /**\r\n     * 查询${functionName}\r\n     * \r\n     * @param ${pkColumn.javaField} ${functionName}主键\r\n     * @return ${functionName}\r\n     */\r\n    @Override\r\n    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})\r\n    {\r\n        return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});\r\n    }\r\n\r\n    /**\r\n     * 查询${functionName}列表\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return ${functionName}\r\n     */\r\n    @Override\r\n    public List<${ClassName}> select${ClassName}List(${ClassName} ${className})\r\n    {\r\n        return ${className}Mapper.select${ClassName}List(${className});\r\n    }\r\n\r\n    /**\r\n     * 新增${functionName}\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return 结果\r\n     */\r\n#if($table.sub)\r\n    @Transactional\r\n#end\r\n    @Override\r\n    public int insert${ClassName}(${ClassName} ${className})\r\n    {\r\n#foreach ($column in $columns)\r\n#if($column.javaField == 'createTime')\r\n        ${className}.setCreateTime(DateUtils.getNowDate());\r\n#end\r\n#end\r\n#if($table.sub)\r\n        int rows = ${className}Mapper.insert${ClassName}(${className});\r\n        insert${subClassName}(${className});\r\n        return rows;\r\n#else\r\n        return ${className}Mapper.insert${ClassName}(${className});\r\n#end\r\n    }\r\n\r\n    /**\r\n     * 修改${functionName}\r\n     * \r\n     * @param ${className} ${functionName}\r\n     * @return 结果\r\n     */\r\n#if($table.sub)\r\n    @Transactional\r\n#end\r\n    @Override\r\n    public int update${ClassName}(${ClassName} ${className})\r\n    {\r\n#foreach ($column in $columns)\r\n#if($column.javaField == 'updateTime')\r\n        ${className}.setUpdateTime(DateUtils.getNowDate());\r\n#end\r\n#end\r\n#if($table.sub)\r\n        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());\r\n        insert${subClassName}(${className});\r\n#end\r\n        return ${className}Mapper.update${ClassName}(${className});\r\n    }\r\n\r\n    /**\r\n     * 批量删除${functionName}\r\n     * \r\n     * @param ${pkColumn.javaField}s 需要删除的${functionName}主键\r\n     * @return 结果\r\n     */\r\n#if($table.sub)\r\n    @Transactional\r\n#end\r\n    @Override\r\n    public int delete${ClassName}By${pkColumn.capJavaField}s(String ${pkColumn.javaField}s)\r\n    {\r\n#if($table.sub)\r\n        ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(Convert.toStrArray(${pkColumn.javaField}s));\r\n#end\r\n        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(Convert.toStrArray(${pkColumn.javaField}s));\r\n    }\r\n\r\n    /**\r\n     * 删除${functionName}信息\r\n     * \r\n     * @param ${pkColumn.javaField} ${functionName}主键\r\n     * @return 结果\r\n     */\r\n#if($table.sub)\r\n    @Transactional\r\n#end\r\n    @Override\r\n    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})\r\n    {\r\n#if($table.sub)\r\n        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});\r\n#end\r\n        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});\r\n    }\r\n#if($table.tree)\r\n\r\n    /**\r\n     * 查询${functionName}树列表\r\n     * \r\n     * @return 所有${functionName}信息\r\n     */\r\n    @Override\r\n    public List<Ztree> select${ClassName}Tree()\r\n    {\r\n        List<${ClassName}> ${className}List = ${className}Mapper.select${ClassName}List(new ${ClassName}());\r\n        List<Ztree> ztrees = new ArrayList<Ztree>();\r\n        for (${ClassName} ${className} : ${className}List)\r\n        {\r\n            Ztree ztree = new Ztree();\r\n#if($treeCode.length() > 2 && $treeCode.substring(1,2).matches(\"[A-Z]\"))\r\n#set($TreeCode=$treeCode)\r\n#else\r\n#set($TreeCode=$treeCode.substring(0,1).toUpperCase() + ${treeCode.substring(1)})\r\n#end\r\n#if($treeParentCode.length() > 2 && $treeParentCode.substring(1,2).matches(\"[A-Z]\"))\r\n#set($TreeParentCode=$treeParentCode)\r\n#else\r\n#set($TreeParentCode=$treeParentCode.substring(0,1).toUpperCase() + ${treeParentCode.substring(1)})\r\n#end\r\n#if($treeName.length() > 2 && $treeName.substring(1,2).matches(\"[A-Z]\"))\r\n#set($TreeName=$treeName)\r\n#else\r\n#set($TreeName=$treeName.substring(0,1).toUpperCase() + ${treeName.substring(1)})\r\n#end\r\n            ztree.setId(${className}.get${TreeCode}());\r\n            ztree.setpId(${className}.get${TreeParentCode}());\r\n            ztree.setName(${className}.get${TreeName}());\r\n            ztree.setTitle(${className}.get${TreeName}());\r\n            ztrees.add(ztree);\r\n        }\r\n        return ztrees;\r\n    }\r\n#end\r\n#if($table.sub)\r\n\r\n    /**\r\n     * 新增${subTable.functionName}信息\r\n     * \r\n     * @param ${className} ${functionName}对象\r\n     */\r\n    public void insert${subClassName}(${ClassName} ${className})\r\n    {\r\n        List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();\r\n        ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();\r\n        if (StringUtils.isNotNull(${subclassName}List))\r\n        {\r\n            List<${subClassName}> list = new ArrayList<${subClassName}>();\r\n            for (${subClassName} ${subclassName} : ${subclassName}List)\r\n            {\r\n                ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});\r\n                list.add(${subclassName});\r\n            }\r\n            if (list.size() > 0)\r\n            {\r\n                ${className}Mapper.batch${subClassName}(list);\r\n            }\r\n        }\r\n    }\r\n#end\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm",
    "content": "package ${packageName}.domain;\r\n\r\n#foreach ($import in $subImportList)\r\nimport ${import};\r\n#end\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * ${subTable.functionName}对象 ${subTableName}\r\n * \r\n * @author ${author}\r\n * @date ${datetime}\r\n */\r\npublic class ${subClassName} extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n#foreach ($column in $subTable.columns)\r\n#if(!$table.isSuperColumn($column.javaField))\r\n    /** $column.columnComment */\r\n#if($column.list)\r\n#set($parentheseIndex=$column.columnComment.indexOf(\"（\"))\r\n#if($parentheseIndex != -1)\r\n#set($comment=$column.columnComment.substring(0, $parentheseIndex))\r\n#else\r\n#set($comment=$column.columnComment)\r\n#end\r\n#if($parentheseIndex != -1)\r\n    @Excel(name = \"${comment}\", readConverterExp = \"$column.readConverterExp()\")\r\n#elseif($column.javaType == 'Date')\r\n    @JsonFormat(pattern = \"yyyy-MM-dd\", timezone = \"GMT+8\")\r\n    @Excel(name = \"${comment}\", width = 30, dateFormat = \"yyyy-MM-dd\")\r\n#else\r\n    @Excel(name = \"${comment}\")\r\n#end\r\n#end\r\n    private $column.javaType $column.javaField;\r\n\r\n#end\r\n#end\r\n#foreach ($column in $subTable.columns)\r\n#if(!$table.isSuperColumn($column.javaField))\r\n#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches(\"[A-Z]\"))\r\n#set($AttrName=$column.javaField)\r\n#else\r\n#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})\r\n#end\r\n    public void set${AttrName}($column.javaType $column.javaField) \r\n    {\r\n        this.$column.javaField = $column.javaField;\r\n    }\r\n\r\n    public $column.javaType get${AttrName}() \r\n    {\r\n        return $column.javaField;\r\n    }\r\n#end\r\n#end\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n#foreach ($column in $subTable.columns)\r\n#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches(\"[A-Z]\"))\r\n#set($AttrName=$column.javaField)\r\n#else\r\n#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})\r\n#end\r\n            .append(\"${column.javaField}\", get${AttrName}())\r\n#end\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/sql/sql.vm",
    "content": "-- 菜单 SQL\r\ninsert into sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)\r\nvalues('${functionName}', '${parentMenuId}', '1', '/${moduleName}/${businessName}', 'C', '0', '${permissionPrefix}:view', '#', 'admin', sysdate(), '', null, '${functionName}菜单');\r\n\r\n-- 按钮父菜单ID\r\nSELECT @parentId := LAST_INSERT_ID();\r\n\r\n-- 按钮 SQL\r\ninsert into sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)\r\nvalues('${functionName}查询', @parentId, '1',  '#',  'F', '0', '${permissionPrefix}:list',         '#', 'admin', sysdate(), '', null, '');\r\n\r\ninsert into sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)\r\nvalues('${functionName}新增', @parentId, '2',  '#',  'F', '0', '${permissionPrefix}:add',          '#', 'admin', sysdate(), '', null, '');\r\n\r\ninsert into sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)\r\nvalues('${functionName}修改', @parentId, '3',  '#',  'F', '0', '${permissionPrefix}:edit',         '#', 'admin', sysdate(), '', null, '');\r\n\r\ninsert into sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)\r\nvalues('${functionName}删除', @parentId, '4',  '#',  'F', '0', '${permissionPrefix}:remove',       '#', 'admin', sysdate(), '', null, '');\r\n\r\ninsert into sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)\r\nvalues('${functionName}导出', @parentId, '5',  '#',  'F', '0', '${permissionPrefix}:export',       '#', 'admin', sysdate(), '', null, '');\r\n"
  },
  {
    "path": "ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"${packageName}.mapper.${ClassName}Mapper\">\r\n    \r\n    <resultMap type=\"${ClassName}\" id=\"${ClassName}Result\">\r\n#foreach ($column in $columns)\r\n        <result property=\"${column.javaField}\"    column=\"${column.columnName}\"    />\r\n#end\r\n#if($table.tree)\r\n        <result property=\"parentName\" column=\"parent_name\" />\r\n#end\r\n    </resultMap>\r\n#if($table.sub)\r\n\r\n    <resultMap id=\"${ClassName}${subClassName}Result\" type=\"${ClassName}\" extends=\"${ClassName}Result\">\r\n        <collection property=\"${subclassName}List\" ofType=\"${subClassName}\" column=\"${pkColumn.columnName}\" select=\"select${subClassName}List\" />\r\n    </resultMap>\r\n\r\n    <resultMap type=\"${subClassName}\" id=\"${subClassName}Result\">\r\n#foreach ($column in $subTable.columns)\r\n        <result property=\"${column.javaField}\"    column=\"${column.columnName}\"    />\r\n#end\r\n    </resultMap>\r\n#end\r\n\r\n    <sql id=\"select${ClassName}Vo\">\r\n        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName}\r\n    </sql>\r\n\r\n    <select id=\"select${ClassName}List\" parameterType=\"${ClassName}\" resultMap=\"${ClassName}Result\">\r\n        <include refid=\"select${ClassName}Vo\"/>\r\n        <where>  \r\n#foreach($column in $columns)\r\n#set($queryType=$column.queryType)\r\n#set($javaField=$column.javaField)\r\n#set($javaType=$column.javaType)\r\n#set($columnName=$column.columnName)\r\n#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})\r\n#if($column.query)\r\n#if($column.queryType == \"EQ\")\r\n            <if test=\"$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end\"> and $columnName = #{$javaField}</if>\r\n#elseif($queryType == \"NE\")\r\n            <if test=\"$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end\"> and $columnName != #{$javaField}</if>\r\n#elseif($queryType == \"GT\")\r\n            <if test=\"$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end\"> and $columnName &gt; #{$javaField}</if>\r\n#elseif($queryType == \"GTE\")\r\n            <if test=\"$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end\"> and $columnName &gt;= #{$javaField}</if>\r\n#elseif($queryType == \"LT\")\r\n            <if test=\"$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end\"> and $columnName &lt; #{$javaField}</if>\r\n#elseif($queryType == \"LTE\")\r\n            <if test=\"$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end\"> and $columnName &lt;= #{$javaField}</if>\r\n#elseif($queryType == \"LIKE\")\r\n            <if test=\"$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end\"> and $columnName like concat('%', #{$javaField}, '%')</if>\r\n#elseif($queryType == \"BETWEEN\")\r\n            <if test=\"params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''\"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if>\r\n#end\r\n#end\r\n#end\r\n        </where>\r\n#if($table.tree)\r\n        order by ${tree_parent_code}\r\n#end\r\n    </select>\r\n    \r\n    <select id=\"select${ClassName}By${pkColumn.capJavaField}\" parameterType=\"${pkColumn.javaType}\" resultMap=\"#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end\">\r\n#if($table.crud)\r\n        <include refid=\"select${ClassName}Vo\"/>\r\n        where ${pkColumn.columnName} = #{${pkColumn.javaField}}\r\n#elseif($table.tree)\r\n        select#foreach($column in $columns) t.$column.columnName,#end p.${tree_name} as parent_name\r\n        from ${tableName} t\r\n        left join ${tableName} p on p.${pkColumn.columnName} = t.${tree_parent_code}\r\n        where t.${pkColumn.columnName} = #{${pkColumn.javaField}}\r\n#elseif($table.sub)\r\n        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end\r\n        from ${tableName}\r\n        where ${pkColumn.columnName} = #{${pkColumn.javaField}}\r\n#end\r\n    </select>\r\n#if($table.sub)\r\n\r\n    <select id=\"select${subClassName}List\" resultMap=\"${subClassName}Result\">\r\n        select#foreach ($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end\r\n        from ${subTableName}\r\n        where ${subTableFkName} = #{${subTableFkName}}\r\n    </select>\r\n#end\r\n\r\n    <insert id=\"insert${ClassName}\" parameterType=\"${ClassName}\"#if($pkColumn.increment) useGeneratedKeys=\"true\" keyProperty=\"$pkColumn.javaField\"#end>\r\n        insert into ${tableName}\r\n        <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\r\n#foreach($column in $columns)\r\n#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)\r\n            <if test=\"$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end\">$column.columnName,</if>\r\n#end\r\n#end\r\n         </trim>\r\n        <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\r\n#foreach($column in $columns)\r\n#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)\r\n            <if test=\"$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end\">#{$column.javaField},</if>\r\n#end\r\n#end\r\n         </trim>\r\n    </insert>\r\n\r\n    <update id=\"update${ClassName}\" parameterType=\"${ClassName}\">\r\n        update ${tableName}\r\n        <trim prefix=\"SET\" suffixOverrides=\",\">\r\n#foreach($column in $columns)\r\n#if($column.columnName != $pkColumn.columnName)\r\n            <if test=\"$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end\">$column.columnName = #{$column.javaField},</if>\r\n#end\r\n#end\r\n        </trim>\r\n        where ${pkColumn.columnName} = #{${pkColumn.javaField}}\r\n    </update>\r\n\r\n    <delete id=\"delete${ClassName}By${pkColumn.capJavaField}\" parameterType=\"${pkColumn.javaType}\">\r\n        delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}}\r\n    </delete>\r\n\r\n    <delete id=\"delete${ClassName}By${pkColumn.capJavaField}s\" parameterType=\"String\">\r\n        delete from ${tableName} where ${pkColumn.columnName} in \r\n        <foreach item=\"${pkColumn.javaField}\" collection=\"array\" open=\"(\" separator=\",\" close=\")\">\r\n            #{${pkColumn.javaField}}\r\n        </foreach>\r\n    </delete>\r\n#if($table.sub)\r\n    \r\n    <delete id=\"delete${subClassName}By${subTableFkClassName}s\" parameterType=\"String\">\r\n        delete from ${subTableName} where ${subTableFkName} in \r\n        <foreach item=\"${subTableFkclassName}\" collection=\"array\" open=\"(\" separator=\",\" close=\")\">\r\n            #{${subTableFkclassName}}\r\n        </foreach>\r\n    </delete>\r\n\r\n    <delete id=\"delete${subClassName}By${subTableFkClassName}\" parameterType=\"${pkColumn.javaType}\">\r\n        delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}\r\n    </delete>\r\n\r\n    <insert id=\"batch${subClassName}\">\r\n        insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values\r\n        <foreach item=\"item\" index=\"index\" collection=\"list\" separator=\",\">\r\n            (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end)\r\n        </foreach>\r\n    </insert>\r\n#end\r\n\r\n</mapper>"
  },
  {
    "path": "ruoyi-quartz/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\r\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\r\n    <parent>\r\n        <artifactId>ruoyi</artifactId>\r\n        <groupId>com.ruoyi</groupId>\r\n        <version>4.8.2</version>\r\n    </parent>\r\n    <modelVersion>4.0.0</modelVersion>\r\n\r\n    <artifactId>ruoyi-quartz</artifactId>\r\n\r\n    <description>\r\n        quartz定时任务\r\n    </description>\r\n\r\n    <dependencies>\r\n\r\n        <!-- 定时任务 -->\r\n        <dependency>\r\n            <groupId>org.springframework.boot</groupId>\r\n            <artifactId>spring-boot-starter-quartz</artifactId>\r\n        </dependency>\r\n\r\n        <!-- 通用工具-->\r\n        <dependency>\r\n            <groupId>com.ruoyi</groupId>\r\n            <artifactId>ruoyi-common</artifactId>\r\n        </dependency>\r\n\r\n    </dependencies>\r\n\r\n</project>"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java",
    "content": "//package com.ruoyi.quartz.config;\r\n//\r\n//import org.springframework.context.annotation.Bean;\r\n//import org.springframework.context.annotation.Configuration;\r\n//import org.springframework.scheduling.quartz.SchedulerFactoryBean;\r\n//import javax.sql.DataSource;\r\n//import java.util.Properties;\r\n//\r\n///**\r\n// * 定时任务配置（单机部署建议默认走内存，如需集群需要创建qrtz数据库表/打开类注释）\r\n// * \r\n// * @author ruoyi\r\n// */\r\n//@Configuration\r\n//public class ScheduleConfig\r\n//{\r\n//    @Bean\r\n//    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)\r\n//    {\r\n//        SchedulerFactoryBean factory = new SchedulerFactoryBean();\r\n//        factory.setDataSource(dataSource);\r\n//\r\n//        // quartz参数\r\n//        Properties prop = new Properties();\r\n//        prop.put(\"org.quartz.scheduler.instanceName\", \"RuoyiScheduler\");\r\n//        prop.put(\"org.quartz.scheduler.instanceId\", \"AUTO\");\r\n//        // 线程池配置\r\n//        prop.put(\"org.quartz.threadPool.class\", \"org.quartz.simpl.SimpleThreadPool\");\r\n//        prop.put(\"org.quartz.threadPool.threadCount\", \"20\");\r\n//        prop.put(\"org.quartz.threadPool.threadPriority\", \"5\");\r\n//        // JobStore配置\r\n//        prop.put(\"org.quartz.jobStore.class\", \"org.springframework.scheduling.quartz.LocalDataSourceJobStore\");\r\n//        // 集群配置\r\n//        prop.put(\"org.quartz.jobStore.isClustered\", \"true\");\r\n//        prop.put(\"org.quartz.jobStore.clusterCheckinInterval\", \"15000\");\r\n//        prop.put(\"org.quartz.jobStore.maxMisfiresToHandleAtATime\", \"10\");\r\n//        prop.put(\"org.quartz.jobStore.txIsolationLevelSerializable\", \"true\");\r\n//\r\n//        // sqlserver 启用\r\n//        // prop.put(\"org.quartz.jobStore.selectWithLockSQL\", \"SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?\");\r\n//        prop.put(\"org.quartz.jobStore.misfireThreshold\", \"12000\");\r\n//        prop.put(\"org.quartz.jobStore.tablePrefix\", \"QRTZ_\");\r\n//        factory.setQuartzProperties(prop);\r\n//\r\n//        factory.setSchedulerName(\"RuoyiScheduler\");\r\n//        // 延时启动\r\n//        factory.setStartupDelay(1);\r\n//        factory.setApplicationContextSchedulerContextKey(\"applicationContextKey\");\r\n//        // 可选，QuartzScheduler\r\n//        // 启动时更新己存在的Job，这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了\r\n//        factory.setOverwriteExistingJobs(true);\r\n//        // 设置自动启动，默认为true\r\n//        factory.setAutoStartup(true);\r\n//\r\n//        return factory;\r\n//    }\r\n//}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java",
    "content": "package com.ruoyi.quartz.controller;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.quartz.SchedulerException;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.validation.annotation.Validated;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.RequestParam;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.exception.job.TaskException;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\nimport com.ruoyi.quartz.service.ISysJobService;\r\nimport com.ruoyi.quartz.util.CronUtils;\r\nimport com.ruoyi.quartz.util.ScheduleUtils;\r\n\r\n/**\r\n * 调度任务信息操作处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/job\")\r\npublic class SysJobController extends BaseController\r\n{\r\n    private String prefix = \"monitor/job\";\r\n\r\n    @Autowired\r\n    private ISysJobService jobService;\r\n\r\n    @RequiresPermissions(\"monitor:job:view\")\r\n    @GetMapping()\r\n    public String job()\r\n    {\r\n        return prefix + \"/job\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:job:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysJob job)\r\n    {\r\n        startPage();\r\n        List<SysJob> list = jobService.selectJobList(job);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"定时任务\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"monitor:job:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysJob job)\r\n    {\r\n        List<SysJob> list = jobService.selectJobList(job);\r\n        ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);\r\n        return util.exportExcel(list, \"定时任务\");\r\n    }\r\n\r\n    @Log(title = \"定时任务\", businessType = BusinessType.DELETE)\r\n    @RequiresPermissions(\"monitor:job:remove\")\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids) throws SchedulerException\r\n    {\r\n        jobService.deleteJobByIds(ids);\r\n        return success();\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:job:detail\")\r\n    @GetMapping(\"/detail/{jobId}\")\r\n    public String detail(@PathVariable(\"jobId\") Long jobId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"name\", \"job\");\r\n        mmap.put(\"job\", jobService.selectJobById(jobId));\r\n        return prefix + \"/detail\";\r\n    }\r\n\r\n    /**\r\n     * 任务调度状态修改\r\n     */\r\n    @Log(title = \"定时任务\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"monitor:job:changeStatus\")\r\n    @PostMapping(\"/changeStatus\")\r\n    @ResponseBody\r\n    public AjaxResult changeStatus(SysJob job) throws SchedulerException\r\n    {\r\n        SysJob newJob = jobService.selectJobById(job.getJobId());\r\n        newJob.setStatus(job.getStatus());\r\n        return toAjax(jobService.changeStatus(newJob));\r\n    }\r\n\r\n    /**\r\n     * 任务调度立即执行一次\r\n     */\r\n    @Log(title = \"定时任务\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"monitor:job:changeStatus\")\r\n    @PostMapping(\"/run\")\r\n    @ResponseBody\r\n    public AjaxResult run(SysJob job) throws SchedulerException\r\n    {\r\n        boolean result = jobService.run(job);\r\n        return result ? success() : error(\"任务不存在或已过期！\");\r\n    }\r\n\r\n    /**\r\n     * 新增调度\r\n     */\r\n    @RequiresPermissions(\"monitor:job:add\")\r\n    @GetMapping(\"/add\")\r\n    public String add()\r\n    {\r\n        return prefix + \"/add\";\r\n    }\r\n\r\n    /**\r\n     * 新增保存调度\r\n     */\r\n    @Log(title = \"定时任务\", businessType = BusinessType.INSERT)\r\n    @RequiresPermissions(\"monitor:job:add\")\r\n    @PostMapping(\"/add\")\r\n    @ResponseBody\r\n    public AjaxResult addSave(@Validated SysJob job) throws SchedulerException, TaskException\r\n    {\r\n        if (!CronUtils.isValid(job.getCronExpression()))\r\n        {\r\n            return error(\"新增任务'\" + job.getJobName() + \"'失败，Cron表达式不正确\");\r\n        }\r\n        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))\r\n        {\r\n            return error(\"新增任务'\" + job.getJobName() + \"'失败，目标字符串不允许'rmi'调用\");\r\n        }\r\n        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))\r\n        {\r\n            return error(\"新增任务'\" + job.getJobName() + \"'失败，目标字符串不允许'ldap(s)'调用\");\r\n        }\r\n        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))\r\n        {\r\n            return error(\"新增任务'\" + job.getJobName() + \"'失败，目标字符串不允许'http(s)'调用\");\r\n        }\r\n        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))\r\n        {\r\n            return error(\"新增任务'\" + job.getJobName() + \"'失败，目标字符串存在违规\");\r\n        }\r\n        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))\r\n        {\r\n            return error(\"新增任务'\" + job.getJobName() + \"'失败，目标字符串不在白名单内\");\r\n        }\r\n        job.setCreateBy(getLoginName());\r\n        return toAjax(jobService.insertJob(job));\r\n    }\r\n\r\n    /**\r\n     * 修改调度\r\n     */\r\n    @RequiresPermissions(\"monitor:job:edit\")\r\n    @GetMapping(\"/edit/{jobId}\")\r\n    public String edit(@PathVariable(\"jobId\") Long jobId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"job\", jobService.selectJobById(jobId));\r\n        return prefix + \"/edit\";\r\n    }\r\n\r\n    /**\r\n     * 修改保存调度\r\n     */\r\n    @Log(title = \"定时任务\", businessType = BusinessType.UPDATE)\r\n    @RequiresPermissions(\"monitor:job:edit\")\r\n    @PostMapping(\"/edit\")\r\n    @ResponseBody\r\n    public AjaxResult editSave(@Validated SysJob job) throws SchedulerException, TaskException\r\n    {\r\n        if (!CronUtils.isValid(job.getCronExpression()))\r\n        {\r\n            return error(\"修改任务'\" + job.getJobName() + \"'失败，Cron表达式不正确\");\r\n        }\r\n        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))\r\n        {\r\n            return error(\"修改任务'\" + job.getJobName() + \"'失败，目标字符串不允许'rmi'调用\");\r\n        }\r\n        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))\r\n        {\r\n            return error(\"修改任务'\" + job.getJobName() + \"'失败，目标字符串不允许'ldap'调用\");\r\n        }\r\n        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))\r\n        {\r\n            return error(\"修改任务'\" + job.getJobName() + \"'失败，目标字符串不允许'http(s)'调用\");\r\n        }\r\n        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))\r\n        {\r\n            return error(\"修改任务'\" + job.getJobName() + \"'失败，目标字符串存在违规\");\r\n        }\r\n        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))\r\n        {\r\n            return error(\"修改任务'\" + job.getJobName() + \"'失败，目标字符串不在白名单内\");\r\n        }\r\n        return toAjax(jobService.updateJob(job));\r\n    }\r\n\r\n    /**\r\n     * 校验cron表达式是否有效\r\n     */\r\n    @PostMapping(\"/checkCronExpressionIsValid\")\r\n    @ResponseBody\r\n    public boolean checkCronExpressionIsValid(SysJob job)\r\n    {\r\n        return jobService.checkCronExpressionIsValid(job.getCronExpression());\r\n    }\r\n\r\n    /**\r\n     * Cron表达式在线生成\r\n     */\r\n    @GetMapping(\"/cron\")\r\n    public String cron()\r\n    {\r\n        return prefix + \"/cron\";\r\n    }\r\n\r\n    /**\r\n     * 查询cron表达式近10次的执行时间\r\n     */\r\n    @GetMapping(\"/queryCronExpression\")\r\n    @ResponseBody\r\n    public AjaxResult queryCronExpression(@RequestParam(value = \"cronExpression\", required = false) String cronExpression)\r\n    {\r\n        if (jobService.checkCronExpressionIsValid(cronExpression))\r\n        {\r\n            List<String> dateList = CronUtils.getRecentTriggerTime(cronExpression);\r\n            return success(dateList);\r\n        }\r\n        else\r\n        {\r\n            return error(\"表达式无效\");\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java",
    "content": "package com.ruoyi.quartz.controller;\r\n\r\nimport java.util.List;\r\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.ModelMap;\r\nimport org.springframework.web.bind.annotation.GetMapping;\r\nimport org.springframework.web.bind.annotation.PathVariable;\r\nimport org.springframework.web.bind.annotation.PostMapping;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.RequestParam;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\nimport com.ruoyi.common.annotation.Log;\r\nimport com.ruoyi.common.core.controller.BaseController;\r\nimport com.ruoyi.common.core.domain.AjaxResult;\r\nimport com.ruoyi.common.core.page.TableDataInfo;\r\nimport com.ruoyi.common.enums.BusinessType;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.poi.ExcelUtil;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\nimport com.ruoyi.quartz.domain.SysJobLog;\r\nimport com.ruoyi.quartz.service.ISysJobLogService;\r\nimport com.ruoyi.quartz.service.ISysJobService;\r\n\r\n/**\r\n * 调度日志操作处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Controller\r\n@RequestMapping(\"/monitor/jobLog\")\r\npublic class SysJobLogController extends BaseController\r\n{\r\n    private String prefix = \"monitor/job\";\r\n\r\n    @Autowired\r\n    private ISysJobService jobService;\r\n\r\n    @Autowired\r\n    private ISysJobLogService jobLogService;\r\n\r\n    @RequiresPermissions(\"monitor:job:view\")\r\n    @GetMapping()\r\n    public String jobLog(@RequestParam(value = \"jobId\", required = false) Long jobId, ModelMap mmap)\r\n    {\r\n        if (StringUtils.isNotNull(jobId))\r\n        {\r\n            SysJob job = jobService.selectJobById(jobId);\r\n            mmap.put(\"job\", job);\r\n        }\r\n        return prefix + \"/jobLog\";\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:job:list\")\r\n    @PostMapping(\"/list\")\r\n    @ResponseBody\r\n    public TableDataInfo list(SysJobLog jobLog)\r\n    {\r\n        startPage();\r\n        List<SysJobLog> list = jobLogService.selectJobLogList(jobLog);\r\n        return getDataTable(list);\r\n    }\r\n\r\n    @Log(title = \"调度日志\", businessType = BusinessType.EXPORT)\r\n    @RequiresPermissions(\"monitor:job:export\")\r\n    @PostMapping(\"/export\")\r\n    @ResponseBody\r\n    public AjaxResult export(SysJobLog jobLog)\r\n    {\r\n        List<SysJobLog> list = jobLogService.selectJobLogList(jobLog);\r\n        ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);\r\n        return util.exportExcel(list, \"调度日志\");\r\n    }\r\n\r\n    @Log(title = \"调度日志\", businessType = BusinessType.DELETE)\r\n    @RequiresPermissions(\"monitor:job:remove\")\r\n    @PostMapping(\"/remove\")\r\n    @ResponseBody\r\n    public AjaxResult remove(String ids)\r\n    {\r\n        return toAjax(jobLogService.deleteJobLogByIds(ids));\r\n    }\r\n\r\n    @RequiresPermissions(\"monitor:job:detail\")\r\n    @GetMapping(\"/detail/{jobLogId}\")\r\n    public String detail(@PathVariable(\"jobLogId\") Long jobLogId, ModelMap mmap)\r\n    {\r\n        mmap.put(\"name\", \"jobLog\");\r\n        mmap.put(\"jobLog\", jobLogService.selectJobLogById(jobLogId));\r\n        return prefix + \"/detail\";\r\n    }\r\n\r\n    @Log(title = \"调度日志\", businessType = BusinessType.CLEAN)\r\n    @RequiresPermissions(\"monitor:job:remove\")\r\n    @PostMapping(\"/clean\")\r\n    @ResponseBody\r\n    public AjaxResult clean()\r\n    {\r\n        jobLogService.cleanJobLog();\r\n        return success();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java",
    "content": "package com.ruoyi.quartz.domain;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.Date;\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.constant.ScheduleConstants;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.quartz.util.CronUtils;\r\n\r\n/**\r\n * 定时任务调度表 sys_job\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysJob extends BaseEntity implements Serializable\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 任务ID */\r\n    @Excel(name = \"任务序号\", cellType = ColumnType.NUMERIC)\r\n    private Long jobId;\r\n\r\n    /** 任务名称 */\r\n    @Excel(name = \"任务名称\")\r\n    private String jobName;\r\n\r\n    /** 任务组名 */\r\n    @Excel(name = \"任务组名\")\r\n    private String jobGroup;\r\n\r\n    /** 调用目标字符串 */\r\n    @Excel(name = \"调用目标字符串\")\r\n    private String invokeTarget;\r\n\r\n    /** cron执行表达式 */\r\n    @Excel(name = \"执行表达式 \")\r\n    private String cronExpression;\r\n\r\n    /** cron计划策略 */\r\n    @Excel(name = \"计划策略 \", readConverterExp = \"0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行\")\r\n    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;\r\n\r\n    /** 是否并发执行（0允许 1禁止） */\r\n    @Excel(name = \"并发执行\", readConverterExp = \"0=允许,1=禁止\")\r\n    private String concurrent;\r\n\r\n    /** 任务状态（0正常 1暂停） */\r\n    @Excel(name = \"任务状态\", readConverterExp = \"0=正常,1=暂停\")\r\n    private String status;\r\n\r\n    public Long getJobId()\r\n    {\r\n        return jobId;\r\n    }\r\n\r\n    public void setJobId(Long jobId)\r\n    {\r\n        this.jobId = jobId;\r\n    }\r\n\r\n    @NotBlank(message = \"任务名称不能为空\")\r\n    @Size(min = 0, max = 64, message = \"任务名称不能超过64个字符\")\r\n    public String getJobName()\r\n    {\r\n        return jobName;\r\n    }\r\n\r\n    public void setJobName(String jobName)\r\n    {\r\n        this.jobName = jobName;\r\n    }\r\n\r\n    public String getJobGroup()\r\n    {\r\n        return jobGroup;\r\n    }\r\n\r\n    public void setJobGroup(String jobGroup)\r\n    {\r\n        this.jobGroup = jobGroup;\r\n    }\r\n\r\n    @NotBlank(message = \"调用目标字符串不能为空\")\r\n    @Size(min = 0, max = 1000, message = \"调用目标字符串长度不能超过500个字符\")\r\n    public String getInvokeTarget()\r\n    {\r\n        return invokeTarget;\r\n    }\r\n\r\n    public void setInvokeTarget(String invokeTarget)\r\n    {\r\n        this.invokeTarget = invokeTarget;\r\n    }\r\n\r\n    @NotBlank(message = \"Cron执行表达式不能为空\")\r\n    @Size(min = 0, max = 255, message = \"Cron执行表达式不能超过255个字符\")\r\n    public String getCronExpression()\r\n    {\r\n        return cronExpression;\r\n    }\r\n\r\n    public void setCronExpression(String cronExpression)\r\n    {\r\n        this.cronExpression = cronExpression;\r\n    }\r\n\r\n    public Date getNextValidTime()\r\n    {\r\n        if (StringUtils.isNotEmpty(cronExpression))\r\n        {\r\n            return CronUtils.getNextExecution(cronExpression);\r\n        }\r\n        return null;\r\n    }\r\n\r\n    public String getMisfirePolicy()\r\n    {\r\n        return misfirePolicy;\r\n    }\r\n\r\n    public void setMisfirePolicy(String misfirePolicy)\r\n    {\r\n        this.misfirePolicy = misfirePolicy;\r\n    }\r\n\r\n    public String getConcurrent()\r\n    {\r\n        return concurrent;\r\n    }\r\n\r\n    public void setConcurrent(String concurrent)\r\n    {\r\n        this.concurrent = concurrent;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"jobId\", getJobId())\r\n            .append(\"jobName\", getJobName())\r\n            .append(\"jobGroup\", getJobGroup())\r\n            .append(\"cronExpression\", getCronExpression())\r\n            .append(\"nextValidTime\", getNextValidTime())\r\n            .append(\"misfirePolicy\", getMisfirePolicy())\r\n            .append(\"concurrent\", getConcurrent())\r\n            .append(\"status\", getStatus())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java",
    "content": "package com.ruoyi.quartz.domain;\r\n\r\nimport java.util.Date;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 定时任务调度日志表 sys_job_log\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysJobLog extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** ID */\r\n    @Excel(name = \"日志序号\")\r\n    private Long jobLogId;\r\n\r\n    /** 任务名称 */\r\n    @Excel(name = \"任务名称\")\r\n    private String jobName;\r\n\r\n    /** 任务组名 */\r\n    @Excel(name = \"任务组名\")\r\n    private String jobGroup;\r\n\r\n    /** 调用目标字符串 */\r\n    @Excel(name = \"调用目标字符串\")\r\n    private String invokeTarget;\r\n\r\n    /** 日志信息 */\r\n    @Excel(name = \"日志信息\")\r\n    private String jobMessage;\r\n\r\n    /** 执行状态（0正常 1失败） */\r\n    @Excel(name = \"执行状态\", readConverterExp = \"0=正常,1=失败\")\r\n    private String status;\r\n\r\n    /** 异常信息 */\r\n    @Excel(name = \"异常信息\")\r\n    private String exceptionInfo;\r\n\r\n    /** 开始时间 */\r\n    private Date startTime;\r\n\r\n    /** 结束时间 */\r\n    private Date endTime;\r\n\r\n    public Long getJobLogId()\r\n    {\r\n        return jobLogId;\r\n    }\r\n\r\n    public void setJobLogId(Long jobLogId)\r\n    {\r\n        this.jobLogId = jobLogId;\r\n    }\r\n\r\n    public String getJobName()\r\n    {\r\n        return jobName;\r\n    }\r\n\r\n    public void setJobName(String jobName)\r\n    {\r\n        this.jobName = jobName;\r\n    }\r\n\r\n    public String getJobGroup()\r\n    {\r\n        return jobGroup;\r\n    }\r\n\r\n    public void setJobGroup(String jobGroup)\r\n    {\r\n        this.jobGroup = jobGroup;\r\n    }\r\n\r\n    public String getInvokeTarget()\r\n    {\r\n        return invokeTarget;\r\n    }\r\n\r\n    public void setInvokeTarget(String invokeTarget)\r\n    {\r\n        this.invokeTarget = invokeTarget;\r\n    }\r\n\r\n    public String getJobMessage()\r\n    {\r\n        return jobMessage;\r\n    }\r\n\r\n    public void setJobMessage(String jobMessage)\r\n    {\r\n        this.jobMessage = jobMessage;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public String getExceptionInfo()\r\n    {\r\n        return exceptionInfo;\r\n    }\r\n\r\n    public void setExceptionInfo(String exceptionInfo)\r\n    {\r\n        this.exceptionInfo = exceptionInfo;\r\n    }\r\n\r\n    public Date getStartTime()\r\n    {\r\n        return startTime;\r\n    }\r\n\r\n    public void setStartTime(Date startTime)\r\n    {\r\n        this.startTime = startTime;\r\n    }\r\n\r\n    public Date getEndTime()\r\n    {\r\n        return endTime;\r\n    }\r\n\r\n    public void setEndTime(Date endTime)\r\n    {\r\n        this.endTime = endTime;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"jobLogId\", getJobLogId())\r\n            .append(\"jobName\", getJobName())\r\n            .append(\"jobGroup\", getJobGroup())\r\n            .append(\"jobMessage\", getJobMessage())\r\n            .append(\"status\", getStatus())\r\n            .append(\"exceptionInfo\", getExceptionInfo())\r\n            .append(\"startTime\", getStartTime())\r\n            .append(\"endTime\", getEndTime())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java",
    "content": "package com.ruoyi.quartz.mapper;\r\n\r\nimport com.ruoyi.quartz.domain.SysJobLog;\r\nimport java.util.List;\r\n\r\n/**\r\n * 调度任务日志信息 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysJobLogMapper\r\n{\r\n    /**\r\n     * 获取quartz调度器日志的计划任务\r\n     * \r\n     * @param jobLog 调度日志信息\r\n     * @return 调度任务日志集合\r\n     */\r\n    public List<SysJobLog> selectJobLogList(SysJobLog jobLog);\r\n\r\n    /**\r\n     * 查询所有调度任务日志\r\n     *\r\n     * @return 调度任务日志列表\r\n     */\r\n    public List<SysJobLog> selectJobLogAll();\r\n\r\n    /**\r\n     * 通过调度任务日志ID查询调度信息\r\n     * \r\n     * @param jobLogId 调度任务日志ID\r\n     * @return 调度任务日志对象信息\r\n     */\r\n    public SysJobLog selectJobLogById(Long jobLogId);\r\n\r\n    /**\r\n     * 新增任务日志\r\n     * \r\n     * @param jobLog 调度日志信息\r\n     * @return 结果\r\n     */\r\n    public int insertJobLog(SysJobLog jobLog);\r\n\r\n    /**\r\n     * 批量删除调度日志信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteJobLogByIds(String[] ids);\r\n\r\n    /**\r\n     * 删除任务日志\r\n     * \r\n     * @param jobId 调度日志ID\r\n     * @return 结果\r\n     */\r\n    public int deleteJobLogById(Long jobId);\r\n\r\n    /**\r\n     * 清空任务日志\r\n     */\r\n    public void cleanJobLog();\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java",
    "content": "package com.ruoyi.quartz.mapper;\r\n\r\nimport com.ruoyi.quartz.domain.SysJob;\r\nimport java.util.List;\r\n\r\n/**\r\n * 调度任务信息 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysJobMapper\r\n{\r\n    /**\r\n     * 查询调度任务日志集合\r\n     * \r\n     * @param job 调度信息\r\n     * @return 操作日志集合\r\n     */\r\n    public List<SysJob> selectJobList(SysJob job);\r\n\r\n    /**\r\n     * 查询所有调度任务\r\n     * \r\n     * @return 调度任务列表\r\n     */\r\n    public List<SysJob> selectJobAll();\r\n\r\n    /**\r\n     * 通过调度ID查询调度任务信息\r\n     * \r\n     * @param jobId 调度ID\r\n     * @return 角色对象信息\r\n     */\r\n    public SysJob selectJobById(Long jobId);\r\n\r\n    /**\r\n     * 通过调度ID删除调度任务信息\r\n     * \r\n     * @param jobId 调度ID\r\n     * @return 结果\r\n     */\r\n    public int deleteJobById(Long jobId);\r\n\r\n    /**\r\n     * 批量删除调度任务信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteJobByIds(Long[] ids);\r\n\r\n    /**\r\n     * 修改调度任务信息\r\n     * \r\n     * @param job 调度任务信息\r\n     * @return 结果\r\n     */\r\n    public int updateJob(SysJob job);\r\n\r\n    /**\r\n     * 新增调度任务信息\r\n     * \r\n     * @param job 调度任务信息\r\n     * @return 结果\r\n     */\r\n    public int insertJob(SysJob job);\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java",
    "content": "package com.ruoyi.quartz.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.quartz.domain.SysJobLog;\r\n\r\n/**\r\n * 定时任务调度日志信息信息 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysJobLogService\r\n{\r\n    /**\r\n     * 获取quartz调度器日志的计划任务\r\n     * \r\n     * @param jobLog 调度日志信息\r\n     * @return 调度任务日志集合\r\n     */\r\n    public List<SysJobLog> selectJobLogList(SysJobLog jobLog);\r\n\r\n    /**\r\n     * 通过调度任务日志ID查询调度信息\r\n     * \r\n     * @param jobLogId 调度任务日志ID\r\n     * @return 调度任务日志对象信息\r\n     */\r\n    public SysJobLog selectJobLogById(Long jobLogId);\r\n\r\n    /**\r\n     * 新增任务日志\r\n     * \r\n     * @param jobLog 调度日志信息\r\n     */\r\n    public void addJobLog(SysJobLog jobLog);\r\n\r\n    /**\r\n     * 批量删除调度日志信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteJobLogByIds(String ids);\r\n\r\n    /**\r\n     * 删除任务日志\r\n     * \r\n     * @param jobId 调度日志ID\r\n     * @return 结果\r\n     */\r\n    public int deleteJobLogById(Long jobId);\r\n    \r\n    /**\r\n     * 清空任务日志\r\n     */\r\n    public void cleanJobLog();\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java",
    "content": "package com.ruoyi.quartz.service;\r\n\r\nimport java.util.List;\r\nimport org.quartz.SchedulerException;\r\nimport com.ruoyi.common.exception.job.TaskException;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\n\r\n/**\r\n * 定时任务调度信息信息 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysJobService\r\n{\r\n    /**\r\n     * 获取quartz调度器的计划任务\r\n     * \r\n     * @param job 调度信息\r\n     * @return 调度任务集合\r\n     */\r\n    public List<SysJob> selectJobList(SysJob job);\r\n\r\n    /**\r\n     * 通过调度任务ID查询调度信息\r\n     * \r\n     * @param jobId 调度任务ID\r\n     * @return 调度任务对象信息\r\n     */\r\n    public SysJob selectJobById(Long jobId);\r\n\r\n    /**\r\n     * 暂停任务\r\n     * \r\n     * @param job 调度信息\r\n     * @return 结果\r\n     */\r\n    public int pauseJob(SysJob job) throws SchedulerException;\r\n\r\n    /**\r\n     * 恢复任务\r\n     * \r\n     * @param job 调度信息\r\n     * @return 结果\r\n     */\r\n    public int resumeJob(SysJob job) throws SchedulerException;\r\n\r\n    /**\r\n     * 删除任务后，所对应的trigger也将被删除\r\n     * \r\n     * @param job 调度信息\r\n     * @return 结果\r\n     */\r\n    public int deleteJob(SysJob job) throws SchedulerException;\r\n\r\n    /**\r\n     * 批量删除调度信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public void deleteJobByIds(String ids) throws SchedulerException;\r\n\r\n    /**\r\n     * 任务调度状态修改\r\n     * \r\n     * @param job 调度信息\r\n     * @return 结果\r\n     */\r\n    public int changeStatus(SysJob job) throws SchedulerException;\r\n\r\n    /**\r\n     * 立即运行任务\r\n     * \r\n     * @param job 调度信息\r\n     * @return 结果\r\n     */\r\n    public boolean run(SysJob job) throws SchedulerException;\r\n\r\n    /**\r\n     * 新增任务\r\n     * \r\n     * @param job 调度信息\r\n     * @return 结果\r\n     */\r\n    public int insertJob(SysJob job) throws SchedulerException, TaskException;\r\n\r\n    /**\r\n     * 更新任务\r\n     * \r\n     * @param job 调度信息\r\n     * @return 结果\r\n     */\r\n    public int updateJob(SysJob job) throws SchedulerException, TaskException;\r\n\r\n    /**\r\n     * 校验cron表达式是否有效\r\n     * \r\n     * @param cronExpression 表达式\r\n     * @return 结果\r\n     */\r\n    public boolean checkCronExpressionIsValid(String cronExpression);\r\n}"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java",
    "content": "package com.ruoyi.quartz.service.impl;\n\nimport java.util.List;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.quartz.domain.SysJobLog;\nimport com.ruoyi.quartz.mapper.SysJobLogMapper;\nimport com.ruoyi.quartz.service.ISysJobLogService;\n\n/**\n * 定时任务调度日志信息 服务层\n * \n * @author ruoyi\n */\n@Service\npublic class SysJobLogServiceImpl implements ISysJobLogService\n{\n    @Autowired\n    private SysJobLogMapper jobLogMapper;\n\n    /**\n     * 获取quartz调度器日志的计划任务\n     * \n     * @param jobLog 调度日志信息\n     * @return 调度任务日志集合\n     */\n    @Override\n    public List<SysJobLog> selectJobLogList(SysJobLog jobLog)\n    {\n        return jobLogMapper.selectJobLogList(jobLog);\n    }\n\n    /**\n     * 通过调度任务日志ID查询调度信息\n     * \n     * @param jobLogId 调度任务日志ID\n     * @return 调度任务日志对象信息\n     */\n    @Override\n    public SysJobLog selectJobLogById(Long jobLogId)\n    {\n        return jobLogMapper.selectJobLogById(jobLogId);\n    }\n\n    /**\n     * 新增任务日志\n     * \n     * @param jobLog 调度日志信息\n     */\n    @Override\n    public void addJobLog(SysJobLog jobLog)\n    {\n        jobLogMapper.insertJobLog(jobLog);\n    }\n\n    /**\n     * 批量删除调度日志信息\n     * \n     * @param ids 需要删除的数据ID\n     * @return 结果\n     */\n    @Override\n    public int deleteJobLogByIds(String ids)\n    {\n        return jobLogMapper.deleteJobLogByIds(Convert.toStrArray(ids));\n    }\n\n    /**\n     * 删除任务日志\n     * \n     * @param jobId 调度日志ID\n     */\n    @Override\n    public int deleteJobLogById(Long jobId)\n    {\n        return jobLogMapper.deleteJobLogById(jobId);\n    }\n\n    /**\n     * 清空任务日志\n     */\n    @Override\n    public void cleanJobLog()\n    {\n        jobLogMapper.cleanJobLog();\n    }\n}\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java",
    "content": "package com.ruoyi.quartz.service.impl;\r\n\r\nimport java.util.List;\r\nimport jakarta.annotation.PostConstruct;\r\nimport org.quartz.JobDataMap;\r\nimport org.quartz.JobKey;\r\nimport org.quartz.Scheduler;\r\nimport org.quartz.SchedulerException;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport org.springframework.transaction.annotation.Transactional;\r\nimport com.ruoyi.common.constant.ScheduleConstants;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.job.TaskException;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\nimport com.ruoyi.quartz.mapper.SysJobMapper;\r\nimport com.ruoyi.quartz.service.ISysJobService;\r\nimport com.ruoyi.quartz.util.CronUtils;\r\nimport com.ruoyi.quartz.util.ScheduleUtils;\r\n\r\n/**\r\n * 定时任务调度信息 服务层\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysJobServiceImpl implements ISysJobService\r\n{\r\n    @Autowired\r\n    private Scheduler scheduler;\r\n\r\n    @Autowired\r\n    private SysJobMapper jobMapper;\r\n\r\n    /**\r\n     * 项目启动时，初始化定时器 \r\n     * 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）\r\n     */\r\n    @PostConstruct\r\n    public void init() throws SchedulerException, TaskException\r\n    {\r\n        scheduler.clear();\r\n        List<SysJob> jobList = jobMapper.selectJobAll();\r\n        for (SysJob job : jobList)\r\n        {\r\n            ScheduleUtils.createScheduleJob(scheduler, job);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取quartz调度器的计划任务列表\r\n     * \r\n     * @param job 调度信息\r\n     * @return\r\n     */\r\n    @Override\r\n    public List<SysJob> selectJobList(SysJob job)\r\n    {\r\n        return jobMapper.selectJobList(job);\r\n    }\r\n\r\n    /**\r\n     * 通过调度任务ID查询调度信息\r\n     * \r\n     * @param jobId 调度任务ID\r\n     * @return 调度任务对象信息\r\n     */\r\n    @Override\r\n    public SysJob selectJobById(Long jobId)\r\n    {\r\n        return jobMapper.selectJobById(jobId);\r\n    }\r\n\r\n    /**\r\n     * 暂停任务\r\n     * \r\n     * @param job 调度信息\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public int pauseJob(SysJob job) throws SchedulerException\r\n    {\r\n        Long jobId = job.getJobId();\r\n        String jobGroup = job.getJobGroup();\r\n        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());\r\n        int rows = jobMapper.updateJob(job);\r\n        if (rows > 0)\r\n        {\r\n            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 恢复任务\r\n     * \r\n     * @param job 调度信息\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public int resumeJob(SysJob job) throws SchedulerException\r\n    {\r\n        Long jobId = job.getJobId();\r\n        String jobGroup = job.getJobGroup();\r\n        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());\r\n        int rows = jobMapper.updateJob(job);\r\n        if (rows > 0)\r\n        {\r\n            scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 删除任务后，所对应的trigger也将被删除\r\n     * \r\n     * @param job 调度信息\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public int deleteJob(SysJob job) throws SchedulerException\r\n    {\r\n        Long jobId = job.getJobId();\r\n        String jobGroup = job.getJobGroup();\r\n        int rows = jobMapper.deleteJobById(jobId);\r\n        if (rows > 0)\r\n        {\r\n            scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 批量删除调度信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public void deleteJobByIds(String ids) throws SchedulerException\r\n    {\r\n        Long[] jobIds = Convert.toLongArray(ids);\r\n        for (Long jobId : jobIds)\r\n        {\r\n            SysJob job = jobMapper.selectJobById(jobId);\r\n            deleteJob(job);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 任务调度状态修改\r\n     * \r\n     * @param job 调度信息\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public int changeStatus(SysJob job) throws SchedulerException\r\n    {\r\n        int rows = 0;\r\n        String status = job.getStatus();\r\n        if (ScheduleConstants.Status.NORMAL.getValue().equals(status))\r\n        {\r\n            rows = resumeJob(job);\r\n        }\r\n        else if (ScheduleConstants.Status.PAUSE.getValue().equals(status))\r\n        {\r\n            rows = pauseJob(job);\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 立即运行任务\r\n     * \r\n     * @param job 调度信息\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public boolean run(SysJob job) throws SchedulerException\r\n    {\r\n        boolean result = false;\r\n        Long jobId = job.getJobId();\r\n        SysJob tmpObj = selectJobById(job.getJobId());\r\n        // 参数\r\n        JobDataMap dataMap = new JobDataMap();\r\n        dataMap.put(ScheduleConstants.TASK_PROPERTIES, tmpObj);\r\n        JobKey jobKey = ScheduleUtils.getJobKey(jobId, tmpObj.getJobGroup());\r\n        if (scheduler.checkExists(jobKey))\r\n        {\r\n            result = true;\r\n            scheduler.triggerJob(jobKey, dataMap);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * 新增任务\r\n     * \r\n     * @param job 调度信息 调度信息\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public int insertJob(SysJob job) throws SchedulerException, TaskException\r\n    {\r\n        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());\r\n        int rows = jobMapper.insertJob(job);\r\n        if (rows > 0)\r\n        {\r\n            ScheduleUtils.createScheduleJob(scheduler, job);\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 更新任务的时间表达式\r\n     * \r\n     * @param job 调度信息\r\n     */\r\n    @Override\r\n    @Transactional(rollbackFor = Exception.class)\r\n    public int updateJob(SysJob job) throws SchedulerException, TaskException\r\n    {\r\n        SysJob properties = selectJobById(job.getJobId());\r\n        int rows = jobMapper.updateJob(job);\r\n        if (rows > 0)\r\n        {\r\n            updateSchedulerJob(job, properties.getJobGroup());\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 更新任务\r\n     * \r\n     * @param job 任务对象\r\n     * @param jobGroup 任务组名\r\n     */\r\n    public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException\r\n    {\r\n        Long jobId = job.getJobId();\r\n        // 判断是否存在\r\n        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);\r\n        if (scheduler.checkExists(jobKey))\r\n        {\r\n            // 防止创建时存在数据问题 先移除，然后在执行创建操作\r\n            scheduler.deleteJob(jobKey);\r\n        }\r\n        ScheduleUtils.createScheduleJob(scheduler, job);\r\n    }\r\n\r\n    /**\r\n     * 校验cron表达式是否有效\r\n     * \r\n     * @param cronExpression 表达式\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkCronExpressionIsValid(String cronExpression)\r\n    {\r\n        return CronUtils.isValid(cronExpression);\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java",
    "content": "package com.ruoyi.quartz.task;\r\n\r\nimport org.springframework.stereotype.Component;\r\nimport com.ruoyi.common.utils.StringUtils;\r\n\r\n/**\r\n * 定时任务调度测试\r\n * \r\n * @author ruoyi\r\n */\r\n@Component(\"ryTask\")\r\npublic class RyTask\r\n{\r\n    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)\r\n    {\r\n        System.out.println(StringUtils.format(\"执行多参方法： 字符串类型{}，布尔类型{}，长整型{}，浮点型{}，整形{}\", s, b, l, d, i));\r\n    }\r\n\r\n    public void ryParams(String params)\r\n    {\r\n        System.out.println(\"执行有参方法：\" + params);\r\n    }\r\n\r\n    public void ryNoParams()\r\n    {\r\n        System.out.println(\"执行无参方法\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java",
    "content": "package com.ruoyi.quartz.util;\r\n\r\nimport java.util.Date;\r\nimport org.quartz.Job;\r\nimport org.quartz.JobExecutionContext;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.constant.ScheduleConstants;\r\nimport com.ruoyi.common.utils.ExceptionUtil;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.bean.BeanUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\nimport com.ruoyi.quartz.domain.SysJobLog;\r\nimport com.ruoyi.quartz.service.ISysJobLogService;\r\n\r\n/**\r\n * 抽象quartz调用\r\n *\r\n * @author ruoyi\r\n */\r\npublic abstract class AbstractQuartzJob implements Job\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);\r\n\r\n    /**\r\n     * 线程本地变量\r\n     */\r\n    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();\r\n\r\n    @Override\r\n    public void execute(JobExecutionContext context)\r\n    {\r\n        SysJob sysJob = new SysJob();\r\n        BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));\r\n        try\r\n        {\r\n            before(context, sysJob);\r\n            if (sysJob != null)\r\n            {\r\n                doExecute(context, sysJob);\r\n            }\r\n            after(context, sysJob, null);\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            log.error(\"任务执行异常  - ：\", e);\r\n            after(context, sysJob, e);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 执行前\r\n     *\r\n     * @param context 工作执行上下文对象\r\n     * @param sysJob 系统计划任务\r\n     */\r\n    protected void before(JobExecutionContext context, SysJob sysJob)\r\n    {\r\n        threadLocal.set(new Date());\r\n    }\r\n\r\n    /**\r\n     * 执行后\r\n     *\r\n     * @param context 工作执行上下文对象\r\n     * @param sysJob 系统计划任务\r\n     */\r\n    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)\r\n    {\r\n        Date startTime = threadLocal.get();\r\n        threadLocal.remove();\r\n\r\n        final SysJobLog sysJobLog = new SysJobLog();\r\n        sysJobLog.setJobName(sysJob.getJobName());\r\n        sysJobLog.setJobGroup(sysJob.getJobGroup());\r\n        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());\r\n        sysJobLog.setStartTime(startTime);\r\n        sysJobLog.setEndTime(new Date());\r\n        long runMs = sysJobLog.getEndTime().getTime() - sysJobLog.getStartTime().getTime();\r\n        sysJobLog.setJobMessage(sysJobLog.getJobName() + \" 总共耗时：\" + runMs + \"毫秒\");\r\n        if (e != null)\r\n        {\r\n            sysJobLog.setStatus(Constants.FAIL);\r\n            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);\r\n            sysJobLog.setExceptionInfo(errorMsg);\r\n        }\r\n        else\r\n        {\r\n            sysJobLog.setStatus(Constants.SUCCESS);\r\n        }\r\n\r\n        // 写入数据库当中\r\n        SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);\r\n    }\r\n\r\n    /**\r\n     * 执行方法，由子类重载\r\n     *\r\n     * @param context 工作执行上下文对象\r\n     * @param sysJob 系统计划任务\r\n     * @throws Exception 执行过程中的异常\r\n     */\r\n    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java",
    "content": "package com.ruoyi.quartz.util;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport org.quartz.CronExpression;\nimport org.quartz.TriggerUtils;\nimport org.quartz.impl.triggers.CronTriggerImpl;\nimport com.ruoyi.common.utils.DateUtils;\n\n/**\n * cron表达式工具类\n * \n * @author ruoyi\n *\n */\npublic class CronUtils\n{\n    /**\n     * 返回一个布尔值代表一个给定的Cron表达式的有效性\n     *\n     * @param cronExpression Cron表达式\n     * @return boolean 表达式是否有效\n     */\n    public static boolean isValid(String cronExpression)\n    {\n        return CronExpression.isValidExpression(cronExpression);\n    }\n\n    /**\n     * 返回一个字符串值,表示该消息无效Cron表达式给出有效性\n     *\n     * @param cronExpression Cron表达式\n     * @return String 无效时返回表达式错误描述,如果有效返回null\n     */\n    public static String getInvalidMessage(String cronExpression)\n    {\n        try\n        {\n            new CronExpression(cronExpression);\n            return null;\n        }\n        catch (ParseException pe)\n        {\n            return pe.getMessage();\n        }\n    }\n\n    /**\n     * 返回下一个执行时间根据给定的Cron表达式\n     *\n     * @param cronExpression Cron表达式\n     * @return Date 下次Cron表达式执行时间\n     */\n    public static Date getNextExecution(String cronExpression)\n    {\n        try\n        {\n            CronExpression cron = new CronExpression(cronExpression);\n            return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));\n        }\n        catch (ParseException e)\n        {\n            throw new IllegalArgumentException(e.getMessage());\n        }\n    }\n\n    /**\n     * 通过表达式获取近10次的执行时间\n     * \n     * @param cron 表达式\n     * @return 时间列表\n     */\n    public static List<String> getRecentTriggerTime(String cron)\n    {\n        List<String> list = new ArrayList<String>();\n        try\n        {\n            CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();\n            cronTriggerImpl.setCronExpression(cron);\n            List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 10);\n            for (Date date : dates)\n            {\n                list.add(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, date));\n            }\n        }\n        catch (ParseException e)\n        {\n            return null;\n        }\n        return list;\n    }\n}\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java",
    "content": "package com.ruoyi.quartz.util;\r\n\r\nimport java.lang.reflect.InvocationTargetException;\r\nimport java.lang.reflect.Method;\r\nimport java.util.LinkedList;\r\nimport java.util.List;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\n\r\n/**\r\n * 任务执行工具\r\n *\r\n * @author ruoyi\r\n */\r\npublic class JobInvokeUtil\r\n{\r\n    /**\r\n     * 执行方法\r\n     *\r\n     * @param sysJob 系统任务\r\n     */\r\n    public static void invokeMethod(SysJob sysJob) throws Exception\r\n    {\r\n        String invokeTarget = sysJob.getInvokeTarget();\r\n        String beanName = getBeanName(invokeTarget);\r\n        String methodName = getMethodName(invokeTarget);\r\n        List<Object[]> methodParams = getMethodParams(invokeTarget);\r\n\r\n        if (!isValidClassName(beanName))\r\n        {\r\n            Object bean = SpringUtils.getBean(beanName);\r\n            invokeMethod(bean, methodName, methodParams);\r\n        }\r\n        else\r\n        {\r\n            Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();\r\n            invokeMethod(bean, methodName, methodParams);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 调用任务方法\r\n     *\r\n     * @param bean 目标对象\r\n     * @param methodName 方法名称\r\n     * @param methodParams 方法参数\r\n     */\r\n    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)\r\n            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,\r\n            InvocationTargetException\r\n    {\r\n        if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0)\r\n        {\r\n            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));\r\n            method.invoke(bean, getMethodParamsValue(methodParams));\r\n        }\r\n        else\r\n        {\r\n            Method method = bean.getClass().getMethod(methodName);\r\n            method.invoke(bean);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 校验是否为为class包名\r\n     * \r\n     * @param invokeTarget 名称\r\n     * @return true是 false否\r\n     */\r\n    public static boolean isValidClassName(String invokeTarget)\r\n    {\r\n        return StringUtils.countMatches(invokeTarget, \".\") > 1;\r\n    }\r\n\r\n    /**\r\n     * 获取bean名称\r\n     * \r\n     * @param invokeTarget 目标字符串\r\n     * @return bean名称\r\n     */\r\n    public static String getBeanName(String invokeTarget)\r\n    {\r\n        String beanName = StringUtils.substringBefore(invokeTarget, \"(\");\r\n        return StringUtils.substringBeforeLast(beanName, \".\");\r\n    }\r\n\r\n    /**\r\n     * 获取bean方法\r\n     * \r\n     * @param invokeTarget 目标字符串\r\n     * @return method方法\r\n     */\r\n    public static String getMethodName(String invokeTarget)\r\n    {\r\n        String methodName = StringUtils.substringBefore(invokeTarget, \"(\");\r\n        return StringUtils.substringAfterLast(methodName, \".\");\r\n    }\r\n\r\n    /**\r\n     * 获取method方法参数相关列表\r\n     * \r\n     * @param invokeTarget 目标字符串\r\n     * @return method方法相关参数列表\r\n     */\r\n    public static List<Object[]> getMethodParams(String invokeTarget)\r\n    {\r\n        String methodStr = StringUtils.substringBetweenLast(invokeTarget, \"(\", \")\");\r\n        if (StringUtils.isEmpty(methodStr))\r\n        {\r\n            return null;\r\n        }\r\n        String[] methodParams = methodStr.split(\",(?=([^\\\"']*[\\\"'][^\\\"']*[\\\"'])*[^\\\"']*$)\");\r\n        List<Object[]> classs = new LinkedList<>();\r\n        for (int i = 0; i < methodParams.length; i++)\r\n        {\r\n            String str = StringUtils.trimToEmpty(methodParams[i]);\r\n            // String字符串类型，以'或\"开头\r\n            if (StringUtils.startsWithAny(str, \"'\", \"\\\"\"))\r\n            {\r\n                classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class });\r\n            }\r\n            // boolean布尔类型，等于true或者false\r\n            else if (\"true\".equalsIgnoreCase(str) || \"false\".equalsIgnoreCase(str))\r\n            {\r\n                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });\r\n            }\r\n            // long长整形，以L结尾\r\n            else if (StringUtils.endsWith(str, \"L\"))\r\n            {\r\n                classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });\r\n            }\r\n            // double浮点类型，以D结尾\r\n            else if (StringUtils.endsWith(str, \"D\"))\r\n            {\r\n                classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class });\r\n            }\r\n            // 其他类型归类为整形\r\n            else\r\n            {\r\n                classs.add(new Object[] { Integer.valueOf(str), Integer.class });\r\n            }\r\n        }\r\n        return classs;\r\n    }\r\n\r\n    /**\r\n     * 获取参数类型\r\n     * \r\n     * @param methodParams 参数相关列表\r\n     * @return 参数类型列表\r\n     */\r\n    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams)\r\n    {\r\n        Class<?>[] classs = new Class<?>[methodParams.size()];\r\n        int index = 0;\r\n        for (Object[] os : methodParams)\r\n        {\r\n            classs[index] = (Class<?>) os[1];\r\n            index++;\r\n        }\r\n        return classs;\r\n    }\r\n\r\n    /**\r\n     * 获取参数值\r\n     * \r\n     * @param methodParams 参数相关列表\r\n     * @return 参数值列表\r\n     */\r\n    public static Object[] getMethodParamsValue(List<Object[]> methodParams)\r\n    {\r\n        Object[] classs = new Object[methodParams.size()];\r\n        int index = 0;\r\n        for (Object[] os : methodParams)\r\n        {\r\n            classs[index] = (Object) os[0];\r\n            index++;\r\n        }\r\n        return classs;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java",
    "content": "package com.ruoyi.quartz.util;\r\n\r\nimport org.quartz.DisallowConcurrentExecution;\r\nimport org.quartz.JobExecutionContext;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\n\r\n/**\r\n * 定时任务处理（禁止并发执行）\r\n * \r\n * @author ruoyi\r\n *\r\n */\r\n@DisallowConcurrentExecution\r\npublic class QuartzDisallowConcurrentExecution extends AbstractQuartzJob\r\n{\r\n    @Override\r\n    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception\r\n    {\r\n        JobInvokeUtil.invokeMethod(sysJob);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java",
    "content": "package com.ruoyi.quartz.util;\r\n\r\nimport org.quartz.JobExecutionContext;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\n\r\n/**\r\n * 定时任务处理（允许并发执行）\r\n * \r\n * @author ruoyi\r\n *\r\n */\r\npublic class QuartzJobExecution extends AbstractQuartzJob\r\n{\r\n    @Override\r\n    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception\r\n    {\r\n        JobInvokeUtil.invokeMethod(sysJob);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java",
    "content": "package com.ruoyi.quartz.util;\r\n\r\nimport org.quartz.CronScheduleBuilder;\r\nimport org.quartz.CronTrigger;\r\nimport org.quartz.Job;\r\nimport org.quartz.JobBuilder;\r\nimport org.quartz.JobDetail;\r\nimport org.quartz.JobKey;\r\nimport org.quartz.Scheduler;\r\nimport org.quartz.SchedulerException;\r\nimport org.quartz.TriggerBuilder;\r\nimport org.quartz.TriggerKey;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.constant.ScheduleConstants;\r\nimport com.ruoyi.common.exception.job.TaskException;\r\nimport com.ruoyi.common.exception.job.TaskException.Code;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.quartz.domain.SysJob;\r\n\r\n/**\r\n * 定时任务工具类\r\n * \r\n * @author ruoyi\r\n *\r\n */\r\npublic class ScheduleUtils\r\n{\r\n    /**\r\n     * 得到quartz任务类\r\n     *\r\n     * @param sysJob 执行计划\r\n     * @return 具体执行任务类\r\n     */\r\n    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob)\r\n    {\r\n        boolean isConcurrent = \"0\".equals(sysJob.getConcurrent());\r\n        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;\r\n    }\r\n\r\n    /**\r\n     * 构建任务触发对象\r\n     */\r\n    public static TriggerKey getTriggerKey(Long jobId, String jobGroup)\r\n    {\r\n        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);\r\n    }\r\n\r\n    /**\r\n     * 构建任务键对象\r\n     */\r\n    public static JobKey getJobKey(Long jobId, String jobGroup)\r\n    {\r\n        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);\r\n    }\r\n\r\n    /**\r\n     * 创建定时任务\r\n     */\r\n    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException\r\n    {\r\n        Class<? extends Job> jobClass = getQuartzJobClass(job);\r\n        // 构建job信息\r\n        Long jobId = job.getJobId();\r\n        String jobGroup = job.getJobGroup();\r\n        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();\r\n\r\n        // 表达式调度构建器\r\n        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());\r\n        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);\r\n\r\n        // 按新的cronExpression表达式构建一个新的trigger\r\n        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))\r\n                .withSchedule(cronScheduleBuilder).build();\r\n\r\n        // 放入参数，运行时的方法可以获取\r\n        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);\r\n\r\n        // 判断是否存在\r\n        if (scheduler.checkExists(getJobKey(jobId, jobGroup)))\r\n        {\r\n            // 防止创建时存在数据问题 先移除，然后在执行创建操作\r\n            scheduler.deleteJob(getJobKey(jobId, jobGroup));\r\n        }\r\n\r\n        // 判断任务是否过期\r\n        if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression())))\r\n        {\r\n            // 执行调度任务\r\n            scheduler.scheduleJob(jobDetail, trigger);\r\n        }\r\n\r\n        // 暂停任务\r\n        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))\r\n        {\r\n            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 设置定时任务策略\r\n     */\r\n    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)\r\n            throws TaskException\r\n    {\r\n        switch (job.getMisfirePolicy())\r\n        {\r\n            case ScheduleConstants.MISFIRE_DEFAULT:\r\n                return cb;\r\n            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:\r\n                return cb.withMisfireHandlingInstructionIgnoreMisfires();\r\n            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:\r\n                return cb.withMisfireHandlingInstructionFireAndProceed();\r\n            case ScheduleConstants.MISFIRE_DO_NOTHING:\r\n                return cb.withMisfireHandlingInstructionDoNothing();\r\n            default:\r\n                throw new TaskException(\"The task misfire policy '\" + job.getMisfirePolicy()\r\n                        + \"' cannot be used in cron schedule tasks\", Code.CONFIG_ERROR);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 检查包名是否为白名单配置\r\n     * \r\n     * @param invokeTarget 目标字符串\r\n     * @return 结果\r\n     */\r\n    public static boolean whiteList(String invokeTarget)\r\n    {\r\n        String packageName = StringUtils.substringBefore(invokeTarget, \"(\");\r\n        int count = StringUtils.countMatches(packageName, \".\");\r\n        if (count > 1)\r\n        {\r\n            return StringUtils.startsWithAny(invokeTarget, Constants.JOB_WHITELIST_STR);\r\n        }\r\n        Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, \".\")[0]);\r\n        String beanPackageName = obj.getClass().getPackage().getName();\r\n        return StringUtils.startsWithAny(beanPackageName, Constants.JOB_WHITELIST_STR)\r\n                && !StringUtils.startsWithAny(beanPackageName, Constants.JOB_ERROR_STR);\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.quartz.mapper.SysJobLogMapper\">\r\n\r\n\t<resultMap type=\"SysJobLog\" id=\"SysJobLogResult\">\r\n\t\t<id     property=\"jobLogId\"       column=\"job_log_id\"      />\r\n\t\t<result property=\"jobName\"        column=\"job_name\"        />\r\n\t\t<result property=\"jobGroup\"       column=\"job_group\"       />\r\n\t\t<result property=\"invokeTarget\"   column=\"invoke_target\"   />\r\n\t\t<result property=\"jobMessage\"     column=\"job_message\"     />\r\n\t\t<result property=\"status\"         column=\"status\"          />\r\n\t\t<result property=\"exceptionInfo\"  column=\"exception_info\"  />\r\n\t\t<result property=\"startTime\"      column=\"start_time\"      />\r\n\t\t<result property=\"endTime\"        column=\"end_time\"        />\r\n\t\t<result property=\"createTime\"     column=\"create_time\"     />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectJobLogVo\">\r\n        select job_log_id, job_name, job_group, invoke_target, job_message, status, exception_info, start_time, end_time, create_time\r\n\t\tfrom sys_job_log\r\n    </sql>\r\n\t\r\n\t<select id=\"selectJobLogList\" parameterType=\"SysJobLog\" resultMap=\"SysJobLogResult\">\r\n\t\t<include refid=\"selectJobLogVo\"/>\r\n\t\t<where>\r\n\t\t\t<if test=\"jobName != null and jobName != ''\">\r\n\t\t\t\tAND job_name like concat('%', #{jobName}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"jobGroup != null and jobGroup != ''\">\r\n\t\t\t\tAND job_group = #{jobGroup}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"status != null and status != ''\">\r\n\t\t\t\tAND status = #{status}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"invokeTarget != null and invokeTarget != ''\">\r\n\t\t\t\tAND invoke_target like concat('%', #{invokeTarget}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.beginTime != null and params.beginTime != ''\"><!-- 开始时间检索 -->\r\n\t\t\t\tand date_format(create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.endTime != null and params.endTime != ''\"><!-- 结束时间检索 -->\r\n\t\t\t\tand date_format(create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t\torder by create_time desc\r\n\t</select>\r\n\t\r\n\t<select id=\"selectJobLogAll\" resultMap=\"SysJobLogResult\">\r\n\t\t<include refid=\"selectJobLogVo\"/>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectJobLogById\" parameterType=\"Long\" resultMap=\"SysJobLogResult\">\r\n\t\t<include refid=\"selectJobLogVo\"/>\r\n\t\twhere job_log_id = #{jobLogId}\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteJobLogById\" parameterType=\"Long\">\r\n \t\tdelete from sys_job_log where job_log_id = #{jobLogId}\r\n \t</delete>\r\n \t\r\n \t<delete id=\"deleteJobLogByIds\" parameterType=\"String\">\r\n \t\tdelete from sys_job_log where job_log_id in\r\n \t\t<foreach collection=\"array\" item=\"jobLogId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{jobLogId}\r\n        </foreach> \r\n \t</delete>\r\n \t\r\n \t<update id=\"cleanJobLog\">\r\n        truncate table sys_job_log\r\n    </update>\r\n \t\r\n \t<insert id=\"insertJobLog\" parameterType=\"SysJobLog\">\r\n \t\tinsert into sys_job_log(\r\n \t\t\t<if test=\"jobLogId != null and jobLogId != 0\">job_log_id,</if>\r\n \t\t\t<if test=\"jobName != null and jobName != ''\">job_name,</if>\r\n \t\t\t<if test=\"jobGroup != null and jobGroup != ''\">job_group,</if>\r\n \t\t\t<if test=\"invokeTarget != null and invokeTarget != ''\">invoke_target,</if>\r\n \t\t\t<if test=\"jobMessage != null and jobMessage != ''\">job_message,</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status,</if>\r\n \t\t\t<if test=\"exceptionInfo != null and exceptionInfo != ''\">exception_info,</if>\r\n \t\t\t<if test=\"startTime != null\">start_time,</if>\r\n \t\t\t<if test=\"endTime != null\">end_time,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t\t<if test=\"jobLogId != null and jobLogId != 0\">#{jobLogId},</if>\r\n \t\t\t<if test=\"jobName != null and jobName != ''\">#{jobName},</if>\r\n \t\t\t<if test=\"jobGroup != null and jobGroup != ''\">#{jobGroup},</if>\r\n \t\t\t<if test=\"invokeTarget != null and invokeTarget != ''\">#{invokeTarget},</if>\r\n \t\t\t<if test=\"jobMessage != null and jobMessage != ''\">#{jobMessage},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">#{status},</if>\r\n \t\t\t<if test=\"exceptionInfo != null and exceptionInfo != ''\">#{exceptionInfo},</if>\r\n \t\t\t<if test=\"startTime != null\">#{startTime},</if>\r\n \t\t\t<if test=\"endTime != null\">#{endTime},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\r\n</mapper> "
  },
  {
    "path": "ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.quartz.mapper.SysJobMapper\">\r\n\r\n\t<resultMap type=\"SysJob\" id=\"SysJobResult\">\r\n\t\t<id     property=\"jobId\"          column=\"job_id\"          />\r\n\t\t<result property=\"jobName\"        column=\"job_name\"        />\r\n\t\t<result property=\"jobGroup\"       column=\"job_group\"       />\r\n\t\t<result property=\"invokeTarget\"   column=\"invoke_target\"   />\r\n\t\t<result property=\"cronExpression\" column=\"cron_expression\" />\r\n\t\t<result property=\"misfirePolicy\"  column=\"misfire_policy\"  />\r\n\t\t<result property=\"concurrent\"     column=\"concurrent\"      />\r\n\t\t<result property=\"status\"         column=\"status\"          />\r\n\t\t<result property=\"createBy\"       column=\"create_by\"       />\r\n\t\t<result property=\"createTime\"     column=\"create_time\"     />\r\n\t\t<result property=\"updateBy\"       column=\"update_by\"       />\r\n\t\t<result property=\"updateTime\"     column=\"update_time\"     />\r\n\t\t<result property=\"remark\"         column=\"remark\"          />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectJobVo\">\r\n        select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, update_by, update_time, remark \r\n\t\tfrom sys_job\r\n    </sql>\r\n\t\r\n\t<select id=\"selectJobList\" parameterType=\"SysJob\" resultMap=\"SysJobResult\">\r\n\t\t<include refid=\"selectJobVo\"/>\r\n\t\t<where>\r\n\t\t\t<if test=\"jobName != null and jobName != ''\">\r\n\t\t\t\tAND job_name like concat('%', #{jobName}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"jobGroup != null and jobGroup != ''\">\r\n\t\t\t\tAND job_group = #{jobGroup}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"status != null and status != ''\">\r\n\t\t\t\tAND status = #{status}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"invokeTarget != null and invokeTarget != ''\">\r\n\t\t\t\tAND invoke_target like concat('%', #{invokeTarget}, '%')\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectJobAll\" resultMap=\"SysJobResult\">\r\n\t\t<include refid=\"selectJobVo\"/>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectJobById\" parameterType=\"Long\" resultMap=\"SysJobResult\">\r\n\t\t<include refid=\"selectJobVo\"/>\r\n\t\twhere job_id = #{jobId}\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteJobById\" parameterType=\"Long\">\r\n \t\tdelete from sys_job where job_id = #{jobId}\r\n \t</delete>\r\n \t\r\n \t<delete id=\"deleteJobByIds\" parameterType=\"Long\">\r\n \t\tdelete from sys_job where job_id in\r\n \t\t<foreach collection=\"array\" item=\"jobId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{jobId}\r\n        </foreach> \r\n \t</delete>\r\n \t\r\n \t<update id=\"updateJob\" parameterType=\"SysJob\">\r\n \t\tupdate sys_job\r\n \t\t<set>\r\n \t\t\t<if test=\"jobName != null and jobName != ''\">job_name = #{jobName},</if>\r\n \t\t\t<if test=\"jobGroup != null and jobGroup != ''\">job_group = #{jobGroup},</if>\r\n \t\t\t<if test=\"invokeTarget != null and invokeTarget != ''\">invoke_target = #{invokeTarget},</if>\r\n \t\t\t<if test=\"cronExpression != null and cronExpression != ''\">cron_expression = #{cronExpression},</if>\r\n \t\t\t<if test=\"misfirePolicy != null and misfirePolicy != ''\">misfire_policy = #{misfirePolicy},</if>\r\n \t\t\t<if test=\"concurrent != null and concurrent != ''\">concurrent = #{concurrent},</if>\r\n \t\t\t<if test=\"status !=null\">status = #{status},</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">remark = #{remark},</if>\r\n \t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\tupdate_time = sysdate()\r\n \t\t</set>\r\n \t\twhere job_id = #{jobId}\r\n\t</update>\r\n \t\r\n \t<insert id=\"insertJob\" parameterType=\"SysJob\" useGeneratedKeys=\"true\" keyProperty=\"jobId\">\r\n \t\tinsert into sys_job(\r\n \t\t\t<if test=\"jobId != null and jobId != 0\">job_id,</if>\r\n \t\t\t<if test=\"jobName != null and jobName != ''\">job_name,</if>\r\n \t\t\t<if test=\"jobGroup != null and jobGroup != ''\">job_group,</if>\r\n \t\t\t<if test=\"invokeTarget != null and invokeTarget != ''\">invoke_target,</if>\r\n \t\t\t<if test=\"cronExpression != null and cronExpression != ''\">cron_expression,</if>\r\n \t\t\t<if test=\"misfirePolicy != null and misfirePolicy != ''\">misfire_policy,</if>\r\n \t\t\t<if test=\"concurrent != null and concurrent != ''\">concurrent,</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status,</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t\t<if test=\"jobId != null and jobId != 0\">#{jobId},</if>\r\n \t\t\t<if test=\"jobName != null and jobName != ''\">#{jobName},</if>\r\n \t\t\t<if test=\"jobGroup != null and jobGroup != ''\">#{jobGroup},</if>\r\n \t\t\t<if test=\"invokeTarget != null and invokeTarget != ''\">#{invokeTarget},</if>\r\n \t\t\t<if test=\"cronExpression != null and cronExpression != ''\">#{cronExpression},</if>\r\n \t\t\t<if test=\"misfirePolicy != null and misfirePolicy != ''\">#{misfirePolicy},</if>\r\n \t\t\t<if test=\"concurrent != null and concurrent != ''\">#{concurrent},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">#{status},</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\r\n</mapper> "
  },
  {
    "path": "ruoyi-quartz/src/main/resources/templates/monitor/job/add.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('新增定时任务')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-job-add\">\r\n\t\t    <input type=\"hidden\" name=\"createBy\" th:value=\"${@permission.getPrincipalProperty('loginName')}\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">任务名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"jobName\" id=\"jobName\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">任务分组：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<select name=\"jobGroup\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_job_group')}\">\r\n\t\t                <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t            </select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">调用目标字符串：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"invokeTarget\" id=\"invokeTarget\" required>\r\n\t\t\t\t    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> Bean调用示例：ryTask.ryParams('ry')</span>\r\n\t\t\t\t    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> Class类调用示例：com.ruoyi.quartz.task.RyTask.ryParams('ry')</span>\r\n\t\t\t\t    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 参数说明：支持字符串，布尔类型，长整型，浮点型，整型</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">cron表达式：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"cronExpression\" id=\"cronExpression\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">执行策略：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"misfirePolicy\" value=\"1\" th:checked=\"true\"/> 立即执行 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"misfirePolicy\" value=\"2\" /> 执行一次 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"misfirePolicy\" value=\"3\" /> 放弃执行 </label>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">并发执行：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"concurrent\" value=\"0\"/> 允许 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" name=\"concurrent\" value=\"1\" th:checked=\"true\"/> 禁止 </label> \r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\"></textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"monitor/job\";\r\n\t\r\n\t\t$(\"#form-job-add\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tcronExpression:{\r\n\t\t\t\t\tremote: {\r\n\t                    url: prefix + \"/checkCronExpressionIsValid\",\r\n\t                    type: \"post\",\r\n\t                    dataType: \"json\",\r\n\t                    data: {\r\n\t                        \"cronExpression\": function() {\r\n\t                            return $.common.trim($(\"#cronExpression\").val());\r\n\t                        }\r\n\t                    },\r\n\t                    dataFilter: function(data, type) {\r\n\t                    \treturn data;\r\n\t                    }\r\n\t                }\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t            \"cronExpression\": {\r\n\t                remote: \"表达式不正确\"\r\n\t            }\r\n\t        },\r\n\t        focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/add\", $('#form-job-add').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/resources/templates/monitor/job/cron.html",
    "content": "<!DOCTYPE html>\r\n<html  lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>Cron表达式在线生成</title>\r\n    <link th:href=\"@{/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\r\n    <link th:href=\"@{/css/zen-checkbox.css}\" rel=\"stylesheet\"/>\r\n</head>\r\n<body class=\"load-indicator\">\r\n    <div class=\"container t-small-margin\">\r\n      <div class=\"t-big-margin\">\r\n        <ul class=\"nav nav-tabs\">\r\n            <li class=\"active\"><a data-toggle=\"tab\" href=\"#tabSecond\">秒</a></li>\r\n            <li><a data-toggle=\"tab\" href=\"#tabMinute\">分</a></li>\r\n            <li><a data-toggle=\"tab\" href=\"#tabHour\">时</a></li>\r\n            <li><a data-toggle=\"tab\" href=\"#tabDay\">日</a></li>\r\n            <li><a data-toggle=\"tab\" href=\"#tabMonth\">月</a></li>\r\n            <li><a data-toggle=\"tab\" href=\"#tabWeek\">周</a></li>\r\n            <li><a data-toggle=\"tab\" href=\"#tabYear\">年</a></li>\r\n        </ul>\r\n        <div class=\"tab-content tab-cron\">\r\n            <div class=\"tab-pane active\" id=\"tabSecond\">\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"sec_all\" name=\"rdoSecond\"> 每秒 允许的通配符[, - * /]\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" id=\"sec_circle\" name=\"rdoSecond\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">周期从</span>\r\n                            <input type=\"number\" id=\"sec_circle1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">-</span>\r\n                            <input type=\"number\" id=\"sec_circle2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">秒</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  \">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" id=\"sec_per\" name=\"rdoSecond\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">从</span>\r\n                            <input type=\"number\" id=\"sec_per1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">秒开始，每</span>\r\n                            <input type=\"number\" id=\"sec_per2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">秒执行一次</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  tabsecondchk\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"sec_assign\" name=\"rdoSecond\">指定\r\n                        <div class=\"checkbox\">\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond0\" name=\"zd_second\" value=\"0\">\r\n                                <label for=\"zdSecond0\">0</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond1\" name=\"zd_second\" value=\"1\">\r\n                                <label for=\"zdSecond1\">1</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond2\" name=\"zd_second\" value=\"2\">\r\n                                <label for=\"zdSecond2\">2</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond3\" name=\"zd_second\" value=\"3\">\r\n                                <label for=\"zdSecond3\">3</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond4\" name=\"zd_second\" value=\"4\">\r\n                                <label for=\"zdSecond4\">4</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond5\" name=\"zd_second\" value=\"5\">\r\n                                <label for=\"zdSecond5\">5</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond6\" name=\"zd_second\" value=\"6\">\r\n                                <label for=\"zdSecond6\">6</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond7\" name=\"zd_second\" value=\"7\">\r\n                                <label for=\"zdSecond7\">7</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond8\" name=\"zd_second\" value=\"8\">\r\n                                <label for=\"zdSecond8\">8</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond9\" name=\"zd_second\" value=\"9\">\r\n                                <label for=\"zdSecond9\">9</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond10\" name=\"zd_second\" value=\"10\">\r\n                                <label for=\"zdSecond10\">10</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond11\" name=\"zd_second\" value=\"11\">\r\n                                <label for=\"zdSecond11\">11</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond12\" name=\"zd_second\" value=\"12\">\r\n                                <label for=\"zdSecond12\">12</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond13\" name=\"zd_second\" value=\"13\">\r\n                                <label for=\"zdSecond13\">13</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond14\" name=\"zd_second\" value=\"14\">\r\n                                <label for=\"zdSecond14\">14</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond15\" name=\"zd_second\" value=\"15\">\r\n                                <label for=\"zdSecond15\">15</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond16\" name=\"zd_second\" value=\"16\">\r\n                                <label for=\"zdSecond16\">16</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond17\" name=\"zd_second\" value=\"17\">\r\n                                <label for=\"zdSecond17\">17</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond18\" name=\"zd_second\" value=\"18\">\r\n                                <label for=\"zdSecond18\">18</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond19\" name=\"zd_second\" value=\"19\">\r\n                                <label for=\"zdSecond19\">19</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond20\" name=\"zd_second\" value=\"20\">\r\n                                <label for=\"zdSecond20\">20</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond21\" name=\"zd_second\" value=\"21\">\r\n                                <label for=\"zdSecond21\">21</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond22\" name=\"zd_second\" value=\"22\">\r\n                                <label for=\"zdSecond22\">22</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond23\" name=\"zd_second\" value=\"23\">\r\n                                <label for=\"zdSecond23\">23</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond24\" name=\"zd_second\" value=\"24\">\r\n                                <label for=\"zdSecond24\">24</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond25\" name=\"zd_second\" value=\"25\">\r\n                                <label for=\"zdSecond25\">25</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond26\" name=\"zd_second\" value=\"26\">\r\n                                <label for=\"zdSecond26\">26</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond27\" name=\"zd_second\" value=\"27\">\r\n                                <label for=\"zdSecond27\">27</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond28\" name=\"zd_second\" value=\"28\">\r\n                                <label for=\"zdSecond28\">28</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond29\" name=\"zd_second\" value=\"29\">\r\n                                <label for=\"zdSecond29\">29</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond30\" name=\"zd_second\" value=\"30\">\r\n                                <label for=\"zdSecond30\">30</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond31\" name=\"zd_second\" value=\"31\">\r\n                                <label for=\"zdSecond31\">31</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond32\" name=\"zd_second\" value=\"32\">\r\n                                <label for=\"zdSecond32\">32</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond33\" name=\"zd_second\" value=\"33\">\r\n                                <label for=\"zdSecond33\">33</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond34\" name=\"zd_second\" value=\"34\">\r\n                                <label for=\"zdSecond34\">34</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond35\" name=\"zd_second\" value=\"35\">\r\n                                <label for=\"zdSecond35\">35</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond36\" name=\"zd_second\" value=\"36\">\r\n                                <label for=\"zdSecond36\">36</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond37\" name=\"zd_second\" value=\"37\">\r\n                                <label for=\"zdSecond37\">37</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond38\" name=\"zd_second\" value=\"38\">\r\n                                <label for=\"zdSecond38\">38</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond39\" name=\"zd_second\" value=\"39\">\r\n                                <label for=\"zdSecond39\">39</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond40\" name=\"zd_second\" value=\"40\">\r\n                                <label for=\"zdSecond40\">40</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond41\" name=\"zd_second\" value=\"41\">\r\n                                <label for=\"zdSecond41\">41</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond42\" name=\"zd_second\" value=\"42\">\r\n                                <label for=\"zdSecond42\">42</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond43\" name=\"zd_second\" value=\"43\">\r\n                                <label for=\"zdSecond43\">43</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond44\" name=\"zd_second\" value=\"44\">\r\n                                <label for=\"zdSecond44\">44</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond45\" name=\"zd_second\" value=\"45\">\r\n                                <label for=\"zdSecond45\">45</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond46\" name=\"zd_second\" value=\"46\">\r\n                                <label for=\"zdSecond46\">46</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond47\" name=\"zd_second\" value=\"47\">\r\n                                <label for=\"zdSecond47\">47</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond48\" name=\"zd_second\" value=\"48\">\r\n                                <label for=\"zdSecond48\">48</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond49\" name=\"zd_second\" value=\"49\">\r\n                                <label for=\"zdSecond49\">49</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond50\" name=\"zd_second\" value=\"50\">\r\n                                <label for=\"zdSecond50\">50</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond51\" name=\"zd_second\" value=\"51\">\r\n                                <label for=\"zdSecond51\">51</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond52\" name=\"zd_second\" value=\"52\">\r\n                                <label for=\"zdSecond52\">52</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond53\" name=\"zd_second\" value=\"53\">\r\n                                <label for=\"zdSecond53\">53</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond54\" name=\"zd_second\" value=\"54\">\r\n                                <label for=\"zdSecond54\">54</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond55\" name=\"zd_second\" value=\"55\">\r\n                                <label for=\"zdSecond55\">55</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond56\" name=\"zd_second\" value=\"56\">\r\n                                <label for=\"zdSecond56\">56</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond57\" name=\"zd_second\" value=\"57\">\r\n                                <label for=\"zdSecond57\">57</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond58\" name=\"zd_second\" value=\"58\">\r\n                                <label for=\"zdSecond58\">58</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdSecond59\" name=\"zd_second\" value=\"59\">\r\n                                <label for=\"zdSecond59\">59</label>\r\n                            </div>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n            </div>\r\n            <div class=\"tab-pane\" id=\"tabMinute\">\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"min_all\" name=\"rdoMinute\"> 每分 允许的通配符[, - * /]\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  \">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" id=\"min_circle\" name=\"rdoMinute\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">周期从</span>\r\n                            <input type=\"number\" id=\"min_circle1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">-</span>\r\n                            <input id=\"min_circle2\" type=\"number\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">分</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  \">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoMinute\" id=\"min_per\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">从</span>\r\n                            <input type=\"number\" id=\"min_per1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">分开始，每</span>\r\n                            <input type=\"number\" id=\"min_per2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">分执行一次</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  tabsecondchk\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"min_assign\" name=\"rdoMinute\">指定\r\n                        <div class=\"checkbox\">\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute0\" name=\"zd_minute\" value=\"0\">\r\n                                <label for=\"zdMinute0\">0</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute1\" name=\"zd_minute\" value=\"1\">\r\n                                <label for=\"zdMinute1\">1</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute2\" name=\"zd_minute\" value=\"2\">\r\n                                <label for=\"zdMinute2\">2</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute3\" name=\"zd_minute\" value=\"3\">\r\n                                <label for=\"zdMinute3\">3</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute4\" name=\"zd_minute\" value=\"4\">\r\n                                <label for=\"zdMinute4\">4</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute5\" name=\"zd_minute\" value=\"5\">\r\n                                <label for=\"zdMinute5\">5</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute6\" name=\"zd_minute\" value=\"6\">\r\n                                <label for=\"zdMinute6\">6</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute7\" name=\"zd_minute\" value=\"7\">\r\n                                <label for=\"zdMinute7\">7</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute8\" name=\"zd_minute\" value=\"8\">\r\n                                <label for=\"zdMinute8\">8</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute9\" name=\"zd_minute\" value=\"9\">\r\n                                <label for=\"zdMinute9\">9</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute10\" name=\"zd_minute\" value=\"10\">\r\n                                <label for=\"zdMinute10\">10</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute11\" name=\"zd_minute\" value=\"11\">\r\n                                <label for=\"zdMinute11\">11</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute12\" name=\"zd_minute\" value=\"12\">\r\n                                <label for=\"zdMinute12\">12</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute13\" name=\"zd_minute\" value=\"13\">\r\n                                <label for=\"zdMinute13\">13</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute14\" name=\"zd_minute\" value=\"14\">\r\n                                <label for=\"zdMinute14\">14</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute15\" name=\"zd_minute\" value=\"15\">\r\n                                <label for=\"zdMinute15\">15</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute16\" name=\"zd_minute\" value=\"16\">\r\n                                <label for=\"zdMinute16\">16</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute17\" name=\"zd_minute\" value=\"17\">\r\n                                <label for=\"zdMinute17\">17</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute18\" name=\"zd_minute\" value=\"18\">\r\n                                <label for=\"zdMinute18\">18</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute19\" name=\"zd_minute\" value=\"19\">\r\n                                <label for=\"zdMinute19\">19</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute20\" name=\"zd_minute\" value=\"20\">\r\n                                <label for=\"zdMinute20\">20</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute21\" name=\"zd_minute\" value=\"21\">\r\n                                <label for=\"zdMinute21\">21</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute22\" name=\"zd_minute\" value=\"22\">\r\n                                <label for=\"zdMinute22\">22</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute23\" name=\"zd_minute\" value=\"23\">\r\n                                <label for=\"zdMinute23\">23</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute24\" name=\"zd_minute\" value=\"24\">\r\n                                <label for=\"zdMinute24\">24</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute25\" name=\"zd_minute\" value=\"25\">\r\n                                <label for=\"zdMinute25\">25</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute26\" name=\"zd_minute\" value=\"26\">\r\n                                <label for=\"zdMinute26\">26</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute27\" name=\"zd_minute\" value=\"27\">\r\n                                <label for=\"zdMinute27\">27</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute28\" name=\"zd_minute\" value=\"28\">\r\n                                <label for=\"zdMinute28\">28</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute29\" name=\"zd_minute\" value=\"29\">\r\n                                <label for=\"zdMinute29\">29</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute30\" name=\"zd_minute\" value=\"30\">\r\n                                <label for=\"zdMinute30\">30</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute31\" name=\"zd_minute\" value=\"31\">\r\n                                <label for=\"zdMinute31\">31</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute32\" name=\"zd_minute\" value=\"32\">\r\n                                <label for=\"zdMinute32\">32</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute33\" name=\"zd_minute\" value=\"33\">\r\n                                <label for=\"zdMinute33\">33</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute34\" name=\"zd_minute\" value=\"34\">\r\n                                <label for=\"zdMinute34\">34</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute35\" name=\"zd_minute\" value=\"35\">\r\n                                <label for=\"zdMinute35\">35</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute36\" name=\"zd_minute\" value=\"36\">\r\n                                <label for=\"zdMinute36\">36</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute37\" name=\"zd_minute\" value=\"37\">\r\n                                <label for=\"zdMinute37\">37</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute38\" name=\"zd_minute\" value=\"38\">\r\n                                <label for=\"zdMinute38\">38</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute39\" name=\"zd_minute\" value=\"39\">\r\n                                <label for=\"zdMinute39\">39</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute40\" name=\"zd_minute\" value=\"40\">\r\n                                <label for=\"zdMinute40\">40</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute41\" name=\"zd_minute\" value=\"41\">\r\n                                <label for=\"zdMinute41\">41</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute42\" name=\"zd_minute\" value=\"42\">\r\n                                <label for=\"zdMinute42\">42</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute43\" name=\"zd_minute\" value=\"43\">\r\n                                <label for=\"zdMinute43\">43</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute44\" name=\"zd_minute\" value=\"44\">\r\n                                <label for=\"zdMinute44\">44</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute45\" name=\"zd_minute\" value=\"45\">\r\n                                <label for=\"zdMinute45\">45</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute46\" name=\"zd_minute\" value=\"46\">\r\n                                <label for=\"zdMinute46\">46</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute47\" name=\"zd_minute\" value=\"47\">\r\n                                <label for=\"zdMinute47\">47</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute48\" name=\"zd_minute\" value=\"48\">\r\n                                <label for=\"zdMinute48\">48</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute49\" name=\"zd_minute\" value=\"49\">\r\n                                <label for=\"zdMinute49\">49</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute50\" name=\"zd_minute\" value=\"50\">\r\n                                <label for=\"zdMinute50\">50</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute51\" name=\"zd_minute\" value=\"51\">\r\n                                <label for=\"zdMinute51\">51</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute52\" name=\"zd_minute\" value=\"52\">\r\n                                <label for=\"zdMinute52\">52</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute53\" name=\"zd_minute\" value=\"53\">\r\n                                <label for=\"zdMinute53\">53</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute54\" name=\"zd_minute\" value=\"54\">\r\n                                <label for=\"zdMinute54\">54</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute55\" name=\"zd_minute\" value=\"55\">\r\n                                <label for=\"zdMinute55\">55</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute56\" name=\"zd_minute\" value=\"56\">\r\n                                <label for=\"zdMinute56\">56</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute57\" name=\"zd_minute\" value=\"57\">\r\n                                <label for=\"zdMinute57\">57</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute58\" name=\"zd_minute\" value=\"58\">\r\n                                <label for=\"zdMinute58\">58</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMinute59\" name=\"zd_minute\" value=\"59\">\r\n                                <label for=\"zdMinute59\">59</label>\r\n                            </div>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n            </div>\r\n            <div class=\"tab-pane\" id=\"tabHour\">\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"hour_all\" name=\"rdoMinute\"> 每小时 允许的通配符[, - * /]\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" id=\"hour_circle\" name=\"rdoMinute\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">周期从</span>\r\n                            <input type=\"number\" id=\"hour_circle1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">-</span>\r\n                            <input type=\"number\" id=\"hour_circle2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">小时</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoMinute\" id=\"hour_per\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">从</span>\r\n                            <input type=\"number\" id=\"hour_per1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">小时开始，每</span>\r\n                            <input type=\"number\" id=\"hour_per2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">小时执行一次</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  tabsecondchk\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"hour_assign\" name=\"rdoMinute\">指定\r\n                        <div class=\"checkbox\">\r\n                            <label>AM:</label>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour0\" name=\"zd_hour\" value=\"0\">\r\n                                <label for=\"zdHour0\">0</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour1\" name=\"zd_hour\" value=\"1\">\r\n                                <label for=\"zdHour1\">1</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour2\" name=\"zd_hour\" value=\"2\">\r\n                                <label for=\"zdHour2\">2</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour3\" name=\"zd_hour\" value=\"3\">\r\n                                <label for=\"zdHour3\">3</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour4\" name=\"zd_hour\" value=\"4\">\r\n                                <label for=\"zdHour4\">4</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour5\" name=\"zd_hour\" value=\"5\">\r\n                                <label for=\"zdHour5\">5</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour6\" name=\"zd_hour\" value=\"6\">\r\n                                <label for=\"zdHour6\">6</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour7\" name=\"zd_hour\" value=\"7\">\r\n                                <label for=\"zdHour7\">7</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour8\" name=\"zd_hour\" value=\"8\">\r\n                                <label for=\"zdHour8\">8</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour9\" name=\"zd_hour\" value=\"9\">\r\n                                <label for=\"zdHour9\">9</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour10\" name=\"zd_hour\" value=\"10\">\r\n                                <label for=\"zdHour10\">10</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour11\" name=\"zd_hour\" value=\"11\">\r\n                                <label for=\"zdHour11\">11</label>\r\n                            </div>\r\n                            <br>\r\n                            <label>PM:</label>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour12\" name=\"zd_hour\" value=\"12\">\r\n                                <label for=\"zdHour12\">12</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour13\" name=\"zd_hour\" value=\"13\">\r\n                                <label for=\"zdHour13\">13</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour14\" name=\"zd_hour\" value=\"14\">\r\n                                <label for=\"zdHour14\">14</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour15\" name=\"zd_hour\" value=\"15\">\r\n                                <label for=\"zdHour15\">15</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour16\" name=\"zd_hour\" value=\"16\">\r\n                                <label for=\"zdHour16\">16</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour17\" name=\"zd_hour\" value=\"17\">\r\n                                <label for=\"zdHour17\">17</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour18\" name=\"zd_hour\" value=\"18\">\r\n                                <label for=\"zdHour18\">18</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour19\" name=\"zd_hour\" value=\"19\">\r\n                                <label for=\"zdHour19\">19</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour20\" name=\"zd_hour\" value=\"20\">\r\n                                <label for=\"zdHour20\">20</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour21\" name=\"zd_hour\" value=\"21\">\r\n                                <label for=\"zdHour21\">21</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour22\" name=\"zd_hour\" value=\"22\">\r\n                                <label for=\"zdHour22\">22</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdHour23\" name=\"zd_hour\" value=\"23\">\r\n                                <label for=\"zdHour23\">23</label>\r\n                            </div>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n            </div>\r\n            <div class=\"tab-pane\" id=\"tabDay\">\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" name=\"rdoDay\" id=\"day_all\"> 每日 允许的通配符[, - * /]\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" name=\"rdoDay\" id=\"day_no\"> 不指定\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoDay\" id=\"day_circle\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">周期从</span>\r\n                            <input type=\"number\" id=\"day_circle1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">-</span>\r\n                            <input type=\"number\" id=\"day_circle2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">日</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoDay\" id=\"day_per\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">从</span>\r\n                            <input type=\"number\" id=\"day_per1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">日开始，每</span>\r\n                            <input type=\"number\" id=\"day_per2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">日执行一次</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoDay\" id=\"day_work\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">每月</span>\r\n                            <input type=\"number\" id=\"day_work1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">号最近的那个工作日</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" name=\"rdoDay\" id=\"day_last\"> 本月最后一日\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  tabsecondchk\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"day_assign\" name=\"rdoDay\">指定\r\n                        <div class=\"checkbox\">\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay1\" name=\"zd_day\" value=\"1\">\r\n                                <label for=\"zdDay1\">1</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay2\" name=\"zd_day\" value=\"2\">\r\n                                <label for=\"zdDay2\">2</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay3\" name=\"zd_day\" value=\"3\">\r\n                                <label for=\"zdDay3\">3</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay4\" name=\"zd_day\" value=\"4\">\r\n                                <label for=\"zdDay4\">4</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay5\" name=\"zd_day\" value=\"5\">\r\n                                <label for=\"zdDay5\">5</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay6\" name=\"zd_day\" value=\"6\">\r\n                                <label for=\"zdDay6\">6</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay7\" name=\"zd_day\" value=\"7\">\r\n                                <label for=\"zdDay7\">7</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay8\" name=\"zd_day\" value=\"8\">\r\n                                <label for=\"zdDay8\">8</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay9\" name=\"zd_day\" value=\"9\">\r\n                                <label for=\"zdDay9\">9</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay10\" name=\"zd_day\" value=\"10\">\r\n                                <label for=\"zdDay10\">10</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay11\" name=\"zd_day\" value=\"11\">\r\n                                <label for=\"zdDay11\">11</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay12\" name=\"zd_day\" value=\"12\">\r\n                                <label for=\"zdDay12\">12</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay13\" name=\"zd_day\" value=\"13\">\r\n                                <label for=\"zdDay13\">13</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay14\" name=\"zd_day\" value=\"14\">\r\n                                <label for=\"zdDay14\">14</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay15\" name=\"zd_day\" value=\"15\">\r\n                                <label for=\"zdDay15\">15</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay16\" name=\"zd_day\" value=\"16\">\r\n                                <label for=\"zdDay16\">16</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay17\" name=\"zd_day\" value=\"17\">\r\n                                <label for=\"zdDay17\">17</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay18\" name=\"zd_day\" value=\"18\">\r\n                                <label for=\"zdDay18\">18</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay19\" name=\"zd_day\" value=\"19\">\r\n                                <label for=\"zdDay19\">19</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay20\" name=\"zd_day\" value=\"20\">\r\n                                <label for=\"zdDay20\">20</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay21\" name=\"zd_day\" value=\"21\">\r\n                                <label for=\"zdDay21\">21</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay22\" name=\"zd_day\" value=\"22\">\r\n                                <label for=\"zdDay22\">22</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay23\" name=\"zd_day\" value=\"23\">\r\n                                <label for=\"zdDay23\">23</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay24\" name=\"zd_day\" value=\"24\">\r\n                                <label for=\"zdDay24\">24</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay25\" name=\"zd_day\" value=\"25\">\r\n                                <label for=\"zdDay25\">25</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay26\" name=\"zd_day\" value=\"26\">\r\n                                <label for=\"zdDay26\">26</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay27\" name=\"zd_day\" value=\"27\">\r\n                                <label for=\"zdDay27\">27</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay28\" name=\"zd_day\" value=\"28\">\r\n                                <label for=\"zdDay28\">28</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay29\" name=\"zd_day\" value=\"29\">\r\n                                <label for=\"zdDay29\">29</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay30\" name=\"zd_day\" value=\"30\">\r\n                                <label for=\"zdDay30\">30</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdDay31\" name=\"zd_day\" value=\"31\">\r\n                                <label for=\"zdDay31\">31</label>\r\n                            </div>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n            </div>\r\n            <div class=\"tab-pane\" id=\"tabMonth\">\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" name=\"rdoMonth\" id=\"month_all\"> 每月 允许的通配符[, - * /]\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" name=\"rdoMonth\" id=\"month_no\"> 不指定\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoMonth\" id=\"month_circle\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">周期从</span>\r\n                            <input type=\"number\" id=\"month_circle1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">-</span>\r\n                            <input type=\"number\" id=\"month_circle2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">月</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoMonth\" id=\"month_per\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">从</span>\r\n                            <input type=\"number\" id=\"month_per1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">月开始，每</span>\r\n                            <input type=\"number\" id=\"month_per2\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">月执行一次</span>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  tabsecondchk\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"month_assign\" name=\"rdoMonth\">指定\r\n                        <div class=\"checkbox\">\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth1\" name=\"zd_month\" value=\"1\">\r\n                                <label for=\"zdMonth1\">1</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth2\" name=\"zd_month\" value=\"2\">\r\n                                <label for=\"zdMonth2\">2</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth3\" name=\"zd_month\" value=\"3\">\r\n                                <label for=\"zdMonth3\">3</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth4\" name=\"zd_month\" value=\"4\">\r\n                                <label for=\"zdMonth4\">4</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth5\" name=\"zd_month\" value=\"5\">\r\n                                <label for=\"zdMonth5\">5</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth6\" name=\"zd_month\" value=\"6\">\r\n                                <label for=\"zdMonth6\">6</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth7\" name=\"zd_month\" value=\"7\">\r\n                                <label for=\"zdMonth7\">7</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth8\" name=\"zd_month\" value=\"8\">\r\n                                <label for=\"zdMonth8\">8</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth9\" name=\"zd_month\" value=\"9\">\r\n                                <label for=\"zdMonth9\">9</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth10\" name=\"zd_month\" value=\"10\">\r\n                                <label for=\"zdMonth10\">10</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth11\" name=\"zd_month\" value=\"11\">\r\n                                <label for=\"zdMonth11\">11</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdMonth12\" name=\"zd_month\" value=\"12\">\r\n                                <label for=\"zdMonth12\">12</label>\r\n                            </div>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n            </div>\r\n            <div class=\"tab-pane\" id=\"tabWeek\">\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"week_all\" name=\"rdoWeek\"> 周 允许的通配符[, - * /]\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"week_no\" name=\"rdoWeek\"> 不指定\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoWeek\" id=\"week_circle\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">周期从</span>\r\n                            <input type=\"number\" id=\"week_circle1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">-</span>\r\n                            <input type=\"number\" id=\"week_circle2\" class=\"form-control\">\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoWeek\" id=\"week_num\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">第</span>\r\n                            <input type=\"number\" id=\"week_num1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">星期的星期</span>\r\n                            <input type=\"number\" id=\"week_num2\" class=\"form-control\">\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" name=\"rdoWeek\" id=\"week_last\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">本月最后一个星期</span>\r\n                            <input type=\"number\" id=\"week_last1\" class=\"form-control\">\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio  tabsecondchk\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"week_assign\" name=\"rdoWeek\">指定\r\n                        <div class=\"checkbox\">\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdWeek1\" name=\"zd_week\" value=\"1\">\r\n                                <label for=\"zdWeek1\">1</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdWeek2\" name=\"zd_week\" value=\"2\">\r\n                                <label for=\"zdWeek2\">2</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdWeek3\" name=\"zd_week\" value=\"3\">\r\n                                <label for=\"zdWeek3\">3</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdWeek4\" name=\"zd_week\" value=\"4\">\r\n                                <label for=\"zdWeek4\">4</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdWeek5\" name=\"zd_week\" value=\"5\">\r\n                                <label for=\"zdWeek5\">5</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdWeek6\" name=\"zd_week\" value=\"6\">\r\n                                <label for=\"zdWeek6\">6</label>\r\n                            </div>\r\n                            <div class=\"checkbox-primary\">\r\n                                <input type=\"checkbox\" id=\"zdWeek7\" name=\"zd_week\" value=\"7\">\r\n                                <label for=\"zdWeek7\">7</label>\r\n                            </div>\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n            </div>\r\n            <div class=\"tab-pane\" id=\"tabYear\">\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"year_no\" name=\"rdoWeek\"> 不指定 允许的通配符[, - * /] 非必填\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label>\r\n                        <input type=\"radio\" id=\"year_all\" name=\"rdoWeek\"> 每年\r\n                    </label>\r\n                </div>\r\n                <div class=\"radio\">\r\n                    <label class=\"custom-radio\">\r\n                        <input type=\"radio\" name=\"rdoWeek\" id=\"year_circle\">\r\n                        <div class=\"input-group\">\r\n                            <span class=\"input-group-addon\">周期从</span>\r\n                            <input type=\"number\" id=\"year_circle1\" class=\"form-control\">\r\n                            <span class=\"input-group-addon\">-</span>\r\n                            <input type=\"number\" id=\"year_circle2\" class=\"form-control\">\r\n                        </div>\r\n                    </label>\r\n                </div>\r\n            </div>\r\n        </div>\r\n        <div class=\"t-big-margin\">\r\n            <h4>表达式</h4>\r\n        </div>\r\n        <table class=\"table table-hover cron_table table-bordered\">\r\n            <tbody>\r\n            <tr>\r\n                <td></td>\r\n                <td align=\"center\">秒</td>\r\n                <td align=\"center\">分钟</td>\r\n                <td align=\"center\">小时</td>\r\n                <td align=\"center\">日</td>\r\n                <td align=\"center\">月</td>\r\n                <td align=\"center\">星期</td>\r\n                <td align=\"center\">年</td>\r\n            </tr>\r\n            <tr>\r\n                <td>表达式字段</td>\r\n                <td><input type=\"text\" class=\"form-control\" id=\"v_second\" value=\"*\" readonly=\"\"></td>\r\n                <td><input type=\"text\" class=\"form-control\" id=\"v_min\" value=\"*\" readonly=\"\"></td>\r\n                <td><input type=\"text\" class=\"form-control\" id=\"v_hour\" value=\"*\" readonly=\"\"></td>\r\n                <td><input type=\"text\" class=\"form-control\" id=\"v_day\" value=\"*\" readonly=\"\"></td>\r\n                <td><input type=\"text\" class=\"form-control\" id=\"v_month\" value=\"*\" readonly=\"\"></td>\r\n                <td><input type=\"text\" class=\"form-control\" id=\"v_week\" value=\"?\" readonly=\"\"></td>\r\n                <td><input type=\"text\" class=\"form-control\" id=\"v_year\" readonly=\"\"></td>\r\n            </tr>\r\n            <tr>\r\n                <td>Cron 表达式</td>\r\n                <td colspan=\"7\"><input type=\"text\" class=\"form-control\" id=\"cron\" value=\"* * * * * ?\"></td>\r\n            </tr>\r\n            </tbody>\r\n        </table>\r\n        <div class=\"text-center\">\r\n            <button type=\"button\" class=\"btn btn-primary\" id=\"runBtn\">查询最近10次运行时间</button>\r\n            <button type=\"button\" class=\"btn btn-info\" id=\"unrunBtn\">Cron表达式转成字段</button>\r\n            <button type=\"button\" class=\"btn btn-warning\" id=\"checkCron\">Cron表达式验证</button>\r\n        </div>\r\n        <br/>\r\n      </div>\r\n    </div>\r\n</div>\r\n<script th:src=\"@{/js/jquery.min.js}\"></script>\r\n<script th:src=\"@{/js/bootstrap.min.js}\"></script>\r\n<script th:src=\"@{/ajax/libs/layer/layer.min.js}\"></script>\r\n<script th:src=\"@{/ruoyi/js/ry-ui.js?v=4.8.2}\"></script>\r\n<script th:src=\"@{/js/cron.js}\"></script>\r\n<script th:inline=\"javascript\">\r\nvar prefix = [[@{/}]] + \"monitor/job\";\r\n\r\n// 查询最近10次运行时间\r\n$('#runBtn').click(function() {\r\n    var cronExpression = $(\"#cron\").val();\r\n    $.get(prefix + \"/queryCronExpression\", { \"cronExpression\": cronExpression }, function(result) {\r\n    \tif (result.code == web_status.SUCCESS) {\r\n    \t\tif (result.data.length > 0) {\r\n        \t\tvar time = \"表达式<font color='red'>[\" + cronExpression + \"]</font>最近10次运行时间<br/>\";\r\n                for (var i = 0; i < result.data.length; i++) {\r\n                \ttime += i + 1 +\"、\" + result.data[i] + \"<br/>\"\r\n                }\r\n                $.modal.alertSuccess(time);\r\n        \t} else {\r\n                $.modal.alertError(\"表达式有误，未查询出结果\");\r\n            }\r\n        } else {\r\n            $.modal.alertError(result.msg);\r\n        }\r\n    });\r\n});\r\n\r\n// Cron表达式验证\r\n$('#checkCron').click(function() {\r\n    var cronExpression = $(\"#cron\").val();\r\n    $.post(prefix + \"/checkCronExpressionIsValid\", { \"cronExpression\": cronExpression }, function(result) {\r\n        if (result) {\r\n            $.modal.msgSuccess(\"恭喜你，格式正确\");\r\n        } else {\r\n            $.modal.msgError(\"很遗憾，格式错误\");\r\n        }\r\n    });\r\n});\r\n</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/resources/templates/monitor/job/detail.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('定时任务详细')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\r\n\t<form class=\"form-horizontal m-t\" id=\"jobLogForm\" th:if=\"${name == 'jobLog'}\">\r\n\t    <div class=\"ibox\">\r\n\t        <div class=\"ibox-title\">\r\n\t            <h5><i class=\"fa fa-tasks\"></i> 定时任务执行日志详情</h5>\r\n\t        </div>\r\n\t        <div class=\"ibox-content\">\r\n\t            <div class=\"row\">\r\n\t                <div class=\"col-sm-6\">\r\n\t                    <h4><i class=\"fa fa-info-circle text-info\"></i> 基础信息</h4>\r\n\t                    <hr/>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-hashtag\"></i> 日志序号：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${jobLog.jobLogId}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-font\"></i> 任务名称：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${jobLog.jobName}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-object-group\"></i> 任务分组：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${@dict.getLabel('sys_job_group', jobLog.jobGroup)}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-flag\"></i> 执行状态：</label>\r\n\t                        <div class=\"col-sm-8\">\r\n\t                            <span th:if=\"${jobLog.status == '0'}\" class=\"label label-primary\"><i class=\"fa fa-check\"></i> 正常</span>\r\n\t                            <span th:if=\"${jobLog.status == '1'}\" class=\"label label-danger\"><i class=\"fa fa-close\"></i> 失败</span>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                </div>\r\n\t\r\n\t                <div class=\"col-sm-6\">\r\n\t                    <h4><i class=\"fa fa-clock-o text-success\"></i> 执行时间线</h4>\r\n\t                    <hr/>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-play-circle\"></i> 开始时间：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${#dates.format(jobLog.startTime, 'yyyy-MM-dd HH:mm:ss')}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-stop-circle\"></i> 结束时间：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${#dates.format(jobLog.endTime, 'yyyy-MM-dd HH:mm:ss')}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-calendar-plus-o\"></i> 记录时间：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${#dates.format(jobLog.createTime, 'yyyy-MM-dd HH:mm:ss')}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\" th:if=\"${jobLog.status == '0'}\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-rocket\"></i> 执行耗时：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\">\r\n\t                            <span th:text=\"${(jobLog.endTime.time - jobLog.startTime.time)} + ' 毫秒'\" class=\"text-info\"></span>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                </div>\r\n\t            </div>\r\n\t            \r\n \r\n\t            <div class=\"row\">\r\n\t                <div class=\"col-sm-12\">\r\n\t                    <h4><i class=\"fa fa-code text-warning\"></i> 执行方法</h4>\r\n\t                    <hr/>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-2 control-label\"><i class=\"fa fa-code\"></i> 调用目标：</label>\r\n\t                        <div class=\"col-sm-10\">\r\n\t                            <div class=\"well well-sm\" style=\"margin-bottom: 0;\" th:text=\"${jobLog.invokeTarget}\"></div>\r\n\t                        </div>\r\n\t                    </div>\r\n\t\r\n\t                    <div class=\"form-group\" th:if=\"${jobLog.status == '1'}\">\r\n\t                        <label class=\"col-sm-2 control-label\"><i class=\"fa fa-exclamation-triangle text-danger\"></i> 异常信息：</label>\r\n\t                        <div class=\"col-sm-10\">\r\n\t                            <pre class=\"alert alert-danger\" style=\"border: none; margin-bottom: 0; white-space: pre-wrap; word-break: break-all;\" th:text=\"${jobLog.exceptionInfo}\"></pre>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                </div>\r\n\t\t\t\t\t\r\n\t                <div class=\"col-sm-12\">\r\n\t                    <h4><i class=\"fa fa-file-text-o text-warning\"></i> 日志详情</h4>\r\n\t                    <hr/>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-2 control-label\"><i class=\"fa fa-commenting\"></i> 日志信息：</label>\r\n\t                        <div class=\"col-sm-10\">\r\n\t                            <div class=\"well well-sm\" style=\"margin-bottom: 0;\" th:text=\"${jobLog.jobMessage}\">\r\n\t                            </div>\r\n\t                        </div>\r\n\t                    </div>\r\n\t\r\n\t                    <div class=\"form-group\" th:if=\"${jobLog.status == '1'}\">\r\n\t                        <label class=\"col-sm-2 control-label\"><i class=\"fa fa-exclamation-triangle text-danger\"></i> 异常信息：</label>\r\n\t                        <div class=\"col-sm-10\">\r\n\t                            <pre class=\"alert alert-danger\" style=\"border: none; margin-bottom: 0; white-space: pre-wrap; word-break: break-all;\" th:text=\"${jobLog.exceptionInfo}\"></pre>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                </div>\r\n\t            </div>\r\n\t        </div>\r\n\t    </div>\r\n\t</form>\r\n\t\r\n\t<form class=\"form-horizontal m-t\" id=\"jobForm\" th:if=\"${name == 'job'}\">\r\n\t    <div class=\"ibox\">\r\n\t        <div class=\"ibox-title\">\r\n\t            <h5><i class=\"fa fa-clock-o\"></i> 定时任务详情</h5>\r\n\t        </div>\r\n\t        <div class=\"ibox-content\">\r\n\t            <div class=\"row\">\r\n\t                <div class=\"col-sm-6\">\r\n\t                    <h4><i class=\"fa fa-cogs text-info\"></i> 任务配置</h4>\r\n\t                    <hr/>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-hashtag\"></i> 任务序号：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${job.jobId}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-font\"></i> 任务名称：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${job.jobName}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-object-group\"></i> 任务分组：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${@dict.getLabel('sys_job_group', job.jobGroup)}\"></div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-flag\"></i> 执行状态：</label>\r\n\t                        <div class=\"col-sm-8\">\r\n\t                            <span th:if=\"${job.status == '0'}\" class=\"label label-primary\"><i class=\"fa fa-play\"></i> 正常</span>\r\n\t                            <span th:if=\"${job.status == '1'}\" class=\"label label-default\"><i class=\"fa fa-pause\"></i> 暂停</span>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                </div>\r\n\r\n\t                <div class=\"col-sm-6\">\r\n\t                    <h4><i class=\"fa fa-calendar-check-o text-success\"></i> 调度信息</h4>\r\n\t                    <hr/>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\">cron表达式：</label>\r\n\t                        <div class=\"col-sm-8\">\r\n\t                            <code class=\"form-control-static\" th:text=\"${job.cronExpression}\" style=\"background-color: #f7f7f9; padding: 2px 5px; border-radius: 3px;\"></code>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-history\"></i> 执行策略：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\">\r\n\t                            <span th:if=\"${job.misfirePolicy == '0'}\" class=\"label label-default\">默认策略</span>\r\n\t                            <span th:if=\"${job.misfirePolicy == '1'}\" class=\"label label-warning\">立即执行</span>\r\n\t                            <span th:if=\"${job.misfirePolicy == '2'}\" class=\"label label-info\">执行一次</span>\r\n\t                            <span th:if=\"${job.misfirePolicy == '3'}\" class=\"label label-danger\">放弃执行</span>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-bolt\"></i> 并发执行：</label>\r\n\t                        <div class=\"col-sm-8\">\r\n\t                            <span th:if=\"${job.concurrent == '0'}\" class=\"label label-success\"><i class=\"fa fa-check\"></i> 允许</span>\r\n\t                            <span th:if=\"${job.concurrent == '1'}\" class=\"label label-danger\"><i class=\"fa fa-close\"></i> 禁止</span>\r\n\t                        </div>\r\n\t                    </div>\r\n\t                    <div class=\"form-group\">\r\n\t                        <label class=\"col-sm-4 control-label\"><i class=\"fa fa-calendar-plus-o\"></i> 下次执行：</label>\r\n\t                        <div class=\"col-sm-8 form-control-static\" th:text=\"${job.nextValidTime != null} ? ${#dates.format(job.nextValidTime, 'yyyy-MM-dd HH:mm:ss')} : '未计算'\"></div>\r\n\t                    </div>\r\n\t                </div>\r\n\t            </div>\r\n\t\r\n\t\t\t\t<div class=\"row\" style=\"margin-top: 20px;\">\r\n\t\t\t\t    <div class=\"col-sm-12\">\r\n\t\t\t\t        <h4><i class=\"fa fa-info-circle text-warning\"></i> 执行方法</h4>\r\n\t\t\t\t        <hr/>\r\n\t\t\t\t        <div class=\"form-group\">\r\n\t\t\t\t            <label class=\"col-sm-2 control-label\"><i class=\"fa fa-code\"></i> 调用目标：</label>\r\n\t\t\t\t            <div class=\"col-sm-10\">\r\n\t\t\t\t                <div class=\"well well-sm\" style=\"margin-bottom: 0; font-family: monospace; font-size: 0.9em;\" th:text=\"${job.invokeTarget}\"></div>\r\n\t\t\t\t            </div>\r\n\t\t\t\t        </div>\r\n\t\t\t\t    </div>\r\n\t\t\t\t    <div class=\"col-sm-12\">\r\n\t\t\t\t        <h4><i class=\"fa fa-info-circle text-warning\"></i> 元信息</h4>\r\n\t\t\t\t        <hr/>\r\n\t\t\t\t        <div class=\"row\">\r\n\t\t\t\t            <div class=\"col-sm-6\">\r\n\t\t\t\t                <div class=\"form-group\">\r\n\t\t\t\t                    <label class=\"col-sm-4 control-label\"><i class=\"fa fa-user-plus\"></i> 创建人：</label>\r\n\t\t\t\t                    <div class=\"col-sm-8 form-control-static\" th:text=\"*{#strings.defaultString(job.createBy,'-')}\"></div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t                <div class=\"form-group\">\r\n\t\t\t\t                    <label class=\"col-sm-4 control-label\"><i class=\"fa fa-calendar-plus-o\"></i> 创建时间：</label>\r\n\t\t\t\t                    <div class=\"col-sm-8 form-control-static\" th:text=\"${#dates.format(job.createTime, 'yyyy-MM-dd HH:mm:ss')}\"></div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t            </div>\r\n\t\t\t\t            <div class=\"col-sm-6\">\r\n\t\t\t\t                <div class=\"form-group\">\r\n\t\t\t\t                    <label class=\"col-sm-4 control-label\"><i class=\"fa fa-user-edit\"></i> 更新人：</label>\r\n\t\t\t\t                    <div class=\"col-sm-8 form-control-static\" th:text=\"*{#strings.defaultString(job.updateBy,'-')}\"></div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t                <div class=\"form-group\">\r\n\t\t\t\t                    <label class=\"col-sm-4 control-label\"><i class=\"fa fa-calendar-minus-o\"></i> 更新时间：</label>\r\n\t\t\t\t                    <div class=\"col-sm-8 form-control-static\" th:text=\"${#dates.format(job.updateTime, 'yyyy-MM-dd HH:mm:ss')}\"></div>\r\n\t\t\t\t                </div>\r\n\t\t\t\t            </div>\r\n\t\t\t\t        </div>\r\n\t\t\t\t        <div class=\"form-group\" th:if=\"${job.remark != null and job.remark != ''}\">\r\n\t\t\t\t            <label class=\"col-sm-2 control-label\"><i class=\"fa fa-comment\"></i> 备注：</label>\r\n\t\t\t\t            <div class=\"col-sm-10\">\r\n\t\t\t\t                <div class=\"well well-sm\" style=\"margin-bottom: 0; min-height: 60px;\" th:text=\"${job.remark}\"></div>\r\n\t\t\t\t            </div>\r\n\t\t\t\t        </div>\r\n\t\t\t\t    </div>\r\n\t\t\t\t</div>\r\n\t        </div>\r\n\t    </div>\r\n\t</form>\r\n\t\r\n    </div>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-quartz/src/main/resources/templates/monitor/job/edit.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" >\r\n<head>\r\n\t<th:block th:include=\"include :: header('修改定时任务')\" />\r\n</head>\r\n<body class=\"white-bg\">\r\n\t<div class=\"wrapper wrapper-content animated fadeInRight ibox-content\">\r\n\t\t<form class=\"form-horizontal m\" id=\"form-job-edit\" th:object=\"${job}\">\r\n\t\t\t<input id=\"jobId\" name=\"jobId\" type=\"hidden\" th:field=\"*{jobId}\"/>\r\n\t\t\t<input type=\"hidden\" name=\"updateBy\" th:value=\"${@permission.getPrincipalProperty('loginName')}\">\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">任务名称：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"jobName\" id=\"jobName\" th:field=\"*{jobName}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">任务分组：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<select name=\"jobGroup\" class=\"form-control m-b\" th:with=\"type=${@dict.getType('sys_job_group')}\">\r\n\t\t                <option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\" th:field=\"*{jobGroup}\"></option>\r\n\t\t            </select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">调用目标字符串：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"invokeTarget\" id=\"invokeTarget\" th:field=\"*{invokeTarget}\" required>\r\n\t\t\t\t    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> Bean调用示例：ryTask.ryParams('ry')</span>\r\n\t\t\t\t    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> Class类调用示例：com.ruoyi.quartz.task.RyTask.ryParams('ry')</span>\r\n\t\t\t\t    <span class=\"help-block m-b-none\"><i class=\"fa fa-info-circle\"></i> 参数说明：支持字符串，布尔类型，长整型，浮点型，整型</span>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label is-required\">cron表达式：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<input class=\"form-control\" type=\"text\" name=\"cronExpression\" id=\"cronExpression\" th:field=\"*{cronExpression}\" required>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">执行策略：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{misfirePolicy}\" name=\"misfirePolicy\" value=\"1\" /> 立即执行 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{misfirePolicy}\" name=\"misfirePolicy\" value=\"2\" /> 执行一次 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{misfirePolicy}\" name=\"misfirePolicy\" value=\"3\" /> 放弃执行 </label>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">并发执行：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{concurrent}\" name=\"concurrent\" value=\"0\"/> 允许 </label> \r\n\t\t\t\t\t<label class=\"radio-box\"> <input type=\"radio\" th:field=\"*{concurrent}\" name=\"concurrent\" value=\"1\"/> 禁止 </label> \r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">状态：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<div class=\"radio-box\" th:each=\"dict : ${@dict.getType('sys_job_status')}\">\r\n\t\t\t\t\t\t<input type=\"radio\" th:id=\"${dict.dictCode}\" name=\"status\" th:value=\"${dict.dictValue}\" th:field=\"*{status}\">\r\n\t\t\t\t\t\t<label th:for=\"${dict.dictCode}\" th:text=\"${dict.dictLabel}\"></label>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"form-group\">\r\n\t\t\t\t<label class=\"col-sm-3 control-label\">备注：</label>\r\n\t\t\t\t<div class=\"col-sm-8\">\r\n\t\t\t\t\t<textarea id=\"remark\" name=\"remark\" class=\"form-control\">[[*{remark}]]</textarea>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</form>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script type=\"text/javascript\">\r\n\t\tvar prefix = ctx + \"monitor/job\";\r\n\t\r\n\t\t$(\"#form-job-edit\").validate({\r\n\t\t\tonkeyup: false,\r\n\t\t\trules:{\r\n\t\t\t\tcronExpression:{\r\n\t\t\t\t\trequired:true,\r\n\t\t\t\t\tremote: {\r\n\t                    url: prefix + \"/checkCronExpressionIsValid\",\r\n\t                    type: \"post\",\r\n\t                    dataType: \"json\",\r\n\t                    data: {\r\n\t                        \"cronExpression\": function() {\r\n\t                            return $.common.trim($(\"#cronExpression\").val());\r\n\t                        }\r\n\t                    },\r\n\t                    dataFilter: function(data, type) {\r\n\t                    \treturn data;\r\n\t                    }\r\n\t                }\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\tmessages: {\r\n\t            \"cronExpression\": {\r\n\t                remote: \"表达式不正确\"\r\n\t            }\r\n\t        },\r\n\t        focusCleanup: true\r\n\t\t});\r\n\t\t\r\n\t\tfunction submitHandler() {\r\n\t        if ($.validate.form()) {\r\n\t        \t$.operate.save(prefix + \"/edit\", $('#form-job-edit').serialize());\r\n\t        }\r\n\t    }\r\n\t</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "ruoyi-quartz/src/main/resources/templates/monitor/job/job.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('定时任务列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"job-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t任务名称：<input type=\"text\" name=\"jobName\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t任务分组：<select name=\"jobGroup\" th:with=\"type=${@dict.getType('sys_job_group')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t任务状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_job_status')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t\t\t<a class=\"btn btn-success\" onclick=\"$.operate.add()\" shiro:hasPermission=\"monitor:job:add\">\r\n\t                <i class=\"fa fa-plus\"></i> 新增\r\n\t            </a>\r\n\t            <a class=\"btn btn-primary single disabled\" onclick=\"$.operate.edit()\" shiro:hasPermission=\"monitor:job:edit\">\r\n\t\t            <i class=\"fa fa-edit\"></i> 修改\r\n\t\t        </a>\r\n\t\t\t\t<a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"monitor:job:remove\">\r\n\t\t            <i class=\"fa fa-remove\"></i> 删除\r\n\t\t        </a>\r\n\t\t         <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"monitor:job:export\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-primary\" onclick=\"javascript:cron()\">\r\n\t\t            <i class=\"fa fa-code\"></i> 生成表达式\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-info\" onclick=\"javascript:jobLog()\" shiro:hasPermission=\"monitor:job:detail\">\r\n\t\t            <i class=\"fa fa-list\"></i> 日志\r\n\t\t        </a>\r\n\t        </div>\r\n        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n        var detailFlag = [[${@permission.hasPermi('monitor:job:detail')}]];\r\n\t\tvar editFlag = [[${@permission.hasPermi('monitor:job:edit')}]];\r\n\t\tvar removeFlag = [[${@permission.hasPermi('monitor:job:remove')}]];\r\n\t\tvar statusFlag = [[${@permission.hasPermi('monitor:job:changeStatus')}]];\r\n\t\tvar datas = [[${@dict.getType('sys_job_group')}]];\r\n\t\tvar prefix = ctx + \"monitor/job\";\r\n\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        detailUrl: prefix + \"/detail/{id}\",\r\n\t\t        createUrl: prefix + \"/add\",\r\n\t\t        updateUrl: prefix + \"/edit/{id}\",\r\n\t\t        removeUrl: prefix + \"/remove\",\r\n\t\t        exportUrl: prefix + \"/export\",\r\n\t\t        sortName: \"createTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        modalName: \"任务\",\r\n\t\t        columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'jobId',\r\n\t\t            title: '任务编号'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'jobName',\r\n\t\t            title: '任务名称',\r\n\t\t            sortable: true,\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                return '<a href=\"javascript:void(0)\" onclick=\"$.operate.detail(\\'' + row.jobId + '\\')\">' + value + '</a>';\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'jobGroup',\r\n\t\t            title: '任务分组',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \treturn $.table.selectDictLabel(datas, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'invokeTarget',\r\n\t\t            title: '调用目标字符串',\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'cronExpression',\r\n\t\t            title: '执行表达式'\r\n\t\t        },\r\n\t\t        {\r\n\t\t        \tvisible: statusFlag == 'hidden' ? false : true,\r\n\t\t        \ttitle: '任务状态',\r\n\t\t        \talign: 'center',\r\n\t\t        \tformatter: function (value, row, index) {\r\n\t\t        \t\treturn statusTools(row);\r\n\t\t        \t}\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                var actions = [];\r\n\t\t                actions.push('<a class=\"btn btn-success btn-xs ' + editFlag + '\" href=\"javascript:;\" onclick=\"$.operate.edit(\\'' + row.jobId + '\\')\"><i class=\"fa fa-edit\"></i>编辑</a> ');\r\n\t\t                actions.push('<a class=\"btn btn-danger btn-xs ' + removeFlag + '\" href=\"javascript:;\" onclick=\"$.operate.remove(\\'' + row.jobId + '\\')\"><i class=\"fa fa-remove\"></i>删除</a> ');\r\n\t\t                var more = [];\r\n\t\t                more.push(\"<a class='btn btn-default btn-xs \" + statusFlag + \"' href='javascript:void(0)' onclick='run(\" + row.jobId + \")'><i class='fa fa-play-circle-o'></i> 执行一次</a> \");\r\n\t\t                more.push(\"<a class='btn btn-default btn-xs \" + detailFlag + \"' href='javascript:void(0)' onclick='jobLog(\" + row.jobId + \")'><i class='fa fa-list'></i>调度日志</a>\");\r\n\t\t                actions.push('<a class=\"btn btn-info btn-xs\" role=\"button\" data-container=\"body\" data-placement=\"left\" data-toggle=\"popover\" data-html=\"true\" data-trigger=\"hover\" data-content=\"' + more.join('') + '\"><i class=\"fa fa-chevron-circle-right\"></i>更多操作</a>');\r\n\t\t                return actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n        \r\n\t\t/* 调度任务状态显示 */\r\n\t\tfunction statusTools(row) {\r\n\t\t    if (row.status == 1) {\r\n    \t\t\treturn '<i class=\\\"fa fa-toggle-off text-info fa-2x\\\" onclick=\"start(\\'' + row.jobId + '\\', \\'' + row.jobGroup + '\\')\"></i> ';\r\n    \t\t} else {\r\n    \t\t\treturn '<i class=\\\"fa fa-toggle-on text-info fa-2x\\\" onclick=\"stop(\\'' + row.jobId + '\\', \\'' + row.jobGroup + '\\')\"></i> ';\r\n    \t\t}\r\n\t\t}\r\n\t\t\r\n\t\t/* 立即执行一次 */\r\n\t\tfunction run(jobId) {\r\n\t\t\t$.modal.confirm(\"确认要立即执行一次任务吗？\", function() {\r\n\t\t\t\t$.operate.post(prefix + \"/run\", { \"jobId\": jobId});\r\n\t\t    })\r\n\t\t}\r\n\r\n\t\t/* 调度任务-停用 */\r\n\t\tfunction stop(jobId, jobGroup) {\r\n\t\t\t$.modal.confirm(\"确认要停用任务吗？\", function() {\r\n\t\t\t\t$.operate.post(prefix + \"/changeStatus\", { \"jobId\": jobId, \"jobGroup\": jobGroup, \"status\": 1 });\r\n\t\t    })\r\n\t\t}\r\n\r\n\t\t/* 调度任务-启用 */\r\n\t\tfunction start(jobId, jobGroup) {\r\n\t\t\t$.modal.confirm(\"确认要启用任务吗？\", function() {\r\n\t\t\t\t$.operate.post(prefix + \"/changeStatus\", { \"jobId\": jobId, \"jobGroup\": jobGroup, \"status\": 0 });\r\n\t\t    })\r\n\t\t}\r\n\r\n\t\t/* 调度日志查询 */\r\n\t\tfunction jobLog(jobId) {\r\n\t\t    var url = ctx + 'monitor/jobLog';\r\n\t\t    if ($.common.isNotEmpty(jobId)) {\r\n\t\t        url += '?jobId=' + jobId;\r\n\t\t    }\r\n\t\t    $.modal.openTab(\"调度日志\", url);\r\n\t\t}\r\n\t\t\r\n\t\t/* cron表达式生成 */\r\n\t\tfunction cron() {\r\n\t\t    var url = prefix + '/cron';\r\n            var height = $(window).height() - 50;\r\n            top.layer.open({\r\n                maxmin: true,\r\n                title: \"Cron表达式生成器\",\r\n                type: 2,\r\n                area: ['800px', height + \"px\" ], //宽高\r\n                shadeClose: true,\r\n                content: url\r\n            });\r\n\t\t}\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-quartz/src/main/resources/templates/monitor/job/jobLog.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\r\n<head>\r\n\t<th:block th:include=\"include :: header('定时任务日志列表')\" />\r\n</head>\r\n<body class=\"gray-bg\">\r\n\r\n\t<div class=\"container-div\">\r\n\t\t<div class=\"row\">\r\n\t\t\t<div class=\"col-sm-12 search-collapse\">\r\n\t\t\t\t<form id=\"jobLog-form\">\r\n\t\t\t\t\t<div class=\"select-list\">\r\n\t\t\t\t\t\t<ul>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t任务名称：<input type=\"text\" name=\"jobName\" th:value=\"${job!=null?job.jobName:''}\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t任务分组：<select name=\"jobGroup\" th:with=\"type=${@dict.getType('sys_job_group')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<th:block th:if=\"${job==null}\"><option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option></th:block>\r\n\t\t\t\t\t\t\t\t\t<th:block th:if=\"${job!=null}\"><option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\" th:field=\"*{job.jobGroup}\"></option></th:block>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t执行状态：<select name=\"status\" th:with=\"type=${@dict.getType('sys_common_status')}\">\r\n\t\t\t\t\t\t\t\t\t<option value=\"\">所有</option>\r\n\t\t\t\t\t\t\t\t\t<option th:each=\"dict : ${type}\" th:text=\"${dict.dictLabel}\" th:value=\"${dict.dictValue}\"></option>\r\n\t\t\t\t\t\t\t\t</select>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li class=\"select-time\">\r\n\t\t\t\t\t\t\t\t<label>执行时间： </label>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"startTime\" placeholder=\"开始时间\" name=\"params[beginTime]\"/>\r\n\t\t\t\t\t\t\t\t<span>-</span>\r\n\t\t\t\t\t\t\t\t<input type=\"text\" class=\"time-input\" id=\"endTime\" placeholder=\"结束时间\" name=\"params[endTime]\"/>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t\t<li>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-primary btn-rounded btn-sm\" onclick=\"$.table.search()\"><i class=\"fa fa-search\"></i>&nbsp;搜索</a>\r\n\t\t\t\t\t\t\t\t<a class=\"btn btn-warning btn-rounded btn-sm\" onclick=\"$.form.reset()\"><i class=\"fa fa-refresh\"></i>&nbsp;重置</a>\r\n\t\t\t\t\t\t\t</li>\r\n\t\t\t\t\t\t</ul>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</form>\r\n\t\t\t</div>\r\n\t\t\t\r\n\t\t\t<div class=\"btn-group-sm\" id=\"toolbar\" role=\"group\">\r\n\t\t\t\t <a class=\"btn btn-danger multiple disabled\" onclick=\"$.operate.removeAll()\" shiro:hasPermission=\"monitor:job:remove\">\r\n\t                <i class=\"fa fa-remove\"></i> 删除\r\n\t            </a>\r\n\t            <a class=\"btn btn-danger\" onclick=\"$.operate.clean()\" shiro:hasPermission=\"monitor:job:remove\">\r\n\t                <i class=\"fa fa-trash\"></i> 清空\r\n\t            </a>\r\n\t            <a class=\"btn btn-warning\" onclick=\"$.table.exportExcel()\" shiro:hasPermission=\"monitor:job:export\">\r\n\t\t            <i class=\"fa fa-download\"></i> 导出\r\n\t\t        </a>\r\n\t\t        <a class=\"btn btn-danger\" onclick=\"closeItem()\">\r\n\t\t            <i class=\"fa fa-reply-all\"></i> 关闭\r\n\t\t        </a>\r\n\t        </div>\r\n\t        \r\n\t        <div class=\"col-sm-12 select-table table-striped\">\r\n\t\t\t    <table id=\"bootstrap-table\"></table>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n\t<th:block th:include=\"include :: footer\" />\r\n\t<script th:inline=\"javascript\">\r\n\t\tvar detailFlag = [[${@permission.hasPermi('monitor:job:detail')}]];\r\n\t\tvar statusDatas = [[${@dict.getType('sys_common_status')}]];\r\n\t\tvar groupDatas = [[${@dict.getType('sys_job_group')}]];\r\n\t\tvar prefix = ctx + \"monitor/jobLog\";\r\n\r\n\t\t$(function() {\r\n\t\t    var options = {\r\n\t\t        url: prefix + \"/list\",\r\n\t\t        cleanUrl: prefix + \"/clean\",\r\n\t\t        detailUrl: prefix + \"/detail/{id}\",\r\n\t\t        removeUrl: prefix + \"/remove\",\r\n\t\t        exportUrl: prefix + \"/export\",\r\n\t\t        sortName: \"createTime\",\r\n\t\t        sortOrder: \"desc\",\r\n\t\t        modalName: \"调度日志\",\r\n\t\t        columns: [{\r\n\t\t            checkbox: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'jobLogId',\r\n\t\t            title: '日志编号'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'jobName',\r\n\t\t            title: '任务名称'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'jobGroup',\r\n\t\t            title: '任务分组',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \treturn $.table.selectDictLabel(groupDatas, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'invokeTarget',\r\n\t\t            title: '调用目标字符串',\r\n\t\t            formatter: function(value, row, index) {\r\n                    \treturn $.table.tooltip(value);\r\n                    }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'jobMessage',\r\n\t\t            title: '日志信息'\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'status',\r\n\t\t            title: '状态',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t            \treturn $.table.selectDictLabel(statusDatas, value);\r\n\t\t            }\r\n\t\t        },\r\n\t\t        {\r\n\t\t            field: 'createTime',\r\n\t\t            title: '创建时间',\r\n\t\t            sortable: true\r\n\t\t        },\r\n\t\t        {\r\n\t\t            title: '操作',\r\n\t\t            align: 'center',\r\n\t\t            formatter: function(value, row, index) {\r\n\t\t                var actions = [];\r\n\t\t                actions.push('<a class=\"btn btn-warning btn-xs ' + detailFlag + '\" href=\"javascript:void(0)\" onclick=\"$.operate.detail(\\'' + row.jobLogId + '\\')\"><i class=\"fa fa-search\"></i>详细</a>');\r\n\t\t                return actions.join('');\r\n\t\t            }\r\n\t\t        }]\r\n\t\t    };\r\n\t\t    $.table.init(options);\r\n\t\t});\r\n\t</script>\r\n</body>\r\n</html>"
  },
  {
    "path": "ruoyi-system/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\r\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\r\n    <parent>\r\n        <artifactId>ruoyi</artifactId>\r\n        <groupId>com.ruoyi</groupId>\r\n        <version>4.8.2</version>\r\n    </parent>\r\n    <modelVersion>4.0.0</modelVersion>\r\n\r\n    <artifactId>ruoyi-system</artifactId>\r\n\r\n    <description>\r\n        system系统模块\r\n    </description>\r\n\r\n    <dependencies>\r\n\r\n        <!-- 通用工具-->\r\n        <dependency>\r\n            <groupId>com.ruoyi</groupId>\r\n            <artifactId>ruoyi-common</artifactId>\r\n        </dependency>\r\n\r\n    </dependencies>\r\n\r\n</project>"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 参数配置表 sys_config\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysConfig extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 参数主键 */\r\n    @Excel(name = \"参数主键\", cellType = ColumnType.NUMERIC)\r\n    private Long configId;\r\n\r\n    /** 参数名称 */\r\n    @Excel(name = \"参数名称\")\r\n    private String configName;\r\n\r\n    /** 参数键名 */\r\n    @Excel(name = \"参数键名\")\r\n    private String configKey;\r\n\r\n    /** 参数键值 */\r\n    @Excel(name = \"参数键值\")\r\n    private String configValue;\r\n\r\n    /** 系统内置（Y是 N否） */\r\n    @Excel(name = \"系统内置\", readConverterExp = \"Y=是,N=否\")\r\n    private String configType;\r\n\r\n    public Long getConfigId()\r\n    {\r\n        return configId;\r\n    }\r\n\r\n    public void setConfigId(Long configId)\r\n    {\r\n        this.configId = configId;\r\n    }\r\n\r\n    @NotBlank(message = \"参数名称不能为空\")\r\n    @Size(min = 0, max = 100, message = \"参数名称不能超过100个字符\")\r\n    public String getConfigName()\r\n    {\r\n        return configName;\r\n    }\r\n\r\n    public void setConfigName(String configName)\r\n    {\r\n        this.configName = configName;\r\n    }\r\n\r\n    @NotBlank(message = \"参数键名长度不能为空\")\r\n    @Size(min = 0, max = 100, message = \"参数键名长度不能超过100个字符\")\r\n    public String getConfigKey()\r\n    {\r\n        return configKey;\r\n    }\r\n\r\n    public void setConfigKey(String configKey)\r\n    {\r\n        this.configKey = configKey;\r\n    }\r\n\r\n    @NotBlank(message = \"参数键值不能为空\")\r\n    @Size(min = 0, max = 500, message = \"参数键值长度不能超过500个字符\")\r\n    public String getConfigValue()\r\n    {\r\n        return configValue;\r\n    }\r\n\r\n    public void setConfigValue(String configValue)\r\n    {\r\n        this.configValue = configValue;\r\n    }\r\n\r\n    public String getConfigType()\r\n    {\r\n        return configType;\r\n    }\r\n\r\n    public void setConfigType(String configType)\r\n    {\r\n        this.configType = configType;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"configId\", getConfigId())\r\n            .append(\"configName\", getConfigName())\r\n            .append(\"configKey\", getConfigKey())\r\n            .append(\"configValue\", getConfigValue())\r\n            .append(\"configType\", getConfigType())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport java.util.Date;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 系统访问记录表 sys_logininfor\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysLogininfor extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** ID */\r\n    @Excel(name = \"序号\", cellType = ColumnType.NUMERIC)\r\n    private Long infoId;\r\n\r\n    /** 用户账号 */\r\n    @Excel(name = \"用户账号\")\r\n    private String loginName;\r\n\r\n    /** 登录状态 0成功 1失败 */\r\n    @Excel(name = \"登录状态\", readConverterExp = \"0=成功,1=失败\")\r\n    private String status;\r\n\r\n    /** 登录IP地址 */\r\n    @Excel(name = \"登录地址\")\r\n    private String ipaddr;\r\n\r\n    /** 登录地点 */\r\n    @Excel(name = \"登录地点\")\r\n    private String loginLocation;\r\n\r\n    /** 浏览器类型 */\r\n    @Excel(name = \"浏览器\")\r\n    private String browser;\r\n\r\n    /** 操作系统 */\r\n    @Excel(name = \"操作系统\")\r\n    private String os;\r\n\r\n    /** 提示消息 */\r\n    @Excel(name = \"提示消息\")\r\n    private String msg;\r\n\r\n    /** 访问时间 */\r\n    @Excel(name = \"访问时间\", width = 30, dateFormat = \"yyyy-MM-dd HH:mm:ss\")\r\n    private Date loginTime;\r\n\r\n    public Long getInfoId()\r\n    {\r\n        return infoId;\r\n    }\r\n\r\n    public void setInfoId(Long infoId)\r\n    {\r\n        this.infoId = infoId;\r\n    }\r\n\r\n    public String getLoginName()\r\n    {\r\n        return loginName;\r\n    }\r\n\r\n    public void setLoginName(String loginName)\r\n    {\r\n        this.loginName = loginName;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public String getIpaddr()\r\n    {\r\n        return ipaddr;\r\n    }\r\n\r\n    public void setIpaddr(String ipaddr)\r\n    {\r\n        this.ipaddr = ipaddr;\r\n    }\r\n\r\n    public String getLoginLocation()\r\n    {\r\n        return loginLocation;\r\n    }\r\n\r\n    public void setLoginLocation(String loginLocation)\r\n    {\r\n        this.loginLocation = loginLocation;\r\n    }\r\n\r\n    public String getBrowser()\r\n    {\r\n        return browser;\r\n    }\r\n\r\n    public void setBrowser(String browser)\r\n    {\r\n        this.browser = browser;\r\n    }\r\n\r\n    public String getOs()\r\n    {\r\n        return os;\r\n    }\r\n\r\n    public void setOs(String os)\r\n    {\r\n        this.os = os;\r\n    }\r\n\r\n    public String getMsg()\r\n    {\r\n        return msg;\r\n    }\r\n\r\n    public void setMsg(String msg)\r\n    {\r\n        this.msg = msg;\r\n    }\r\n\r\n    public Date getLoginTime()\r\n    {\r\n        return loginTime;\r\n    }\r\n\r\n    public void setLoginTime(Date loginTime)\r\n    {\r\n        this.loginTime = loginTime;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"infoId\", getInfoId())\r\n            .append(\"loginName\", getLoginName())\r\n            .append(\"ipaddr\", getIpaddr())\r\n            .append(\"loginLocation\", getLoginLocation())\r\n            .append(\"browser\", getBrowser())\r\n            .append(\"os\", getOs())\r\n            .append(\"status\", getStatus())\r\n            .append(\"msg\", getMsg())\r\n            .append(\"loginTime\", getLoginTime())\r\n            .toString();\r\n    }\r\n}"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport jakarta.validation.constraints.NotBlank;\r\nimport jakarta.validation.constraints.Size;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.fasterxml.jackson.annotation.JsonProperty;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.xss.Xss;\r\n\r\n/**\r\n * 通知公告表 sys_notice\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysNotice extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 公告ID */\r\n    private Long noticeId;\r\n\r\n    /** 公告标题 */\r\n    private String noticeTitle;\r\n\r\n    /** 公告类型（1通知 2公告） */\r\n    private String noticeType;\r\n\r\n    /** 公告内容 */\r\n    private String noticeContent;\r\n\r\n    /** 公告状态（0正常 1关闭） */\r\n    private String status;\r\n\r\n    /** 是否已读 */\r\n    @JsonProperty(\"isRead\")\r\n    private boolean isRead;\r\n\r\n    public Long getNoticeId()\r\n    {\r\n        return noticeId;\r\n    }\r\n\r\n    public void setNoticeId(Long noticeId)\r\n    {\r\n        this.noticeId = noticeId;\r\n    }\r\n\r\n    public void setNoticeTitle(String noticeTitle)\r\n    {\r\n        this.noticeTitle = noticeTitle;\r\n    }\r\n\r\n    @Xss(message = \"公告标题不能包含脚本字符\")\r\n    @NotBlank(message = \"公告标题不能为空\")\r\n    @Size(min = 0, max = 50, message = \"公告标题不能超过50个字符\")\r\n    public String getNoticeTitle()\r\n    {\r\n        return noticeTitle;\r\n    }\r\n\r\n    public void setNoticeType(String noticeType)\r\n    {\r\n        this.noticeType = noticeType;\r\n    }\r\n\r\n    public String getNoticeType()\r\n    {\r\n        return noticeType;\r\n    }\r\n\r\n    public void setNoticeContent(String noticeContent)\r\n    {\r\n        this.noticeContent = noticeContent;\r\n    }\r\n\r\n    public String getNoticeContent()\r\n    {\r\n        return noticeContent;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public boolean getIsRead()\r\n    {\r\n        return isRead;\r\n    }\r\n\r\n    public void setIsRead(boolean isRead)\r\n    {\r\n        this.isRead = isRead;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"noticeId\", getNoticeId())\r\n            .append(\"noticeTitle\", getNoticeTitle())\r\n            .append(\"noticeType\", getNoticeType())\r\n            .append(\"noticeContent\", getNoticeContent())\r\n            .append(\"status\", getStatus())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNoticeRead.java",
    "content": "package com.ruoyi.system.domain;\n\nimport java.util.Date;\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.lang3.builder.ToStringStyle;\n\n/**\n * 公告已读记录表 sys_notice_read\n *\n * @author ruoyi\n */\npublic class SysNoticeRead\n{\n    /** 主键 */\n    private Long readId;\n\n    /** 公告ID */\n    private Long noticeId;\n\n    /** 用户ID */\n    private Long userId;\n\n    /** 阅读时间 */\n    private Date readTime;\n\n    public Long getReadId()\n    {\n        return readId;\n    }\n\n    public void setReadId(Long readId)\n    {\n        this.readId = readId;\n    }\n\n    public Long getNoticeId()\n    {\n        return noticeId;\n    }\n\n    public void setNoticeId(Long noticeId)\n    {\n        this.noticeId = noticeId;\n    }\n\n    public Long getUserId()\n    {\n        return userId;\n    }\n\n    public void setUserId(Long userId)\n    {\n        this.userId = userId;\n    }\n\n    public Date getReadTime()\n    {\n        return readTime;\n    }\n\n    public void setReadTime(Date readTime)\n    {\n        this.readTime = readTime;\n    }\n\n    @Override\n    public String toString()\n    {\n        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)\n            .append(\"readId\", getReadId())\n            .append(\"noticeId\", getNoticeId())\n            .append(\"userId\", getUserId())\n            .append(\"readTime\", getReadTime())\n            .toString();\n    }\n}\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport java.util.Date;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 操作日志记录表 oper_log\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysOperLog extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 日志主键 */\r\n    @Excel(name = \"操作序号\", cellType = ColumnType.NUMERIC)\r\n    private Long operId;\r\n\r\n    /** 操作模块 */\r\n    @Excel(name = \"操作模块\")\r\n    private String title;\r\n\r\n    /** 业务类型（0其它 1新增 2修改 3删除） */\r\n    @Excel(name = \"业务类型\", readConverterExp = \"0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据\")\r\n    private Integer businessType;\r\n\r\n    /** 业务类型数组 */\r\n    private Integer[] businessTypes;\r\n\r\n    /** 请求方法 */\r\n    @Excel(name = \"请求方法\")\r\n    private String method;\r\n\r\n    /** 请求方式 */\r\n    @Excel(name = \"请求方式\")\r\n    private String requestMethod;\r\n\r\n    /** 操作类别（0其它 1后台用户 2手机端用户） */\r\n    @Excel(name = \"操作类别\", readConverterExp = \"0=其它,1=后台用户,2=手机端用户\")\r\n    private Integer operatorType;\r\n\r\n    /** 操作人员 */\r\n    @Excel(name = \"操作人员\")\r\n    private String operName;\r\n\r\n    /** 部门名称 */\r\n    @Excel(name = \"部门名称\")\r\n    private String deptName;\r\n\r\n    /** 请求url */\r\n    @Excel(name = \"请求地址\")\r\n    private String operUrl;\r\n\r\n    /** 操作地址 */\r\n    @Excel(name = \"操作地址\")\r\n    private String operIp;\r\n\r\n    /** 操作地点 */\r\n    @Excel(name = \"操作地点\")\r\n    private String operLocation;\r\n\r\n    /** 请求参数 */\r\n    @Excel(name = \"请求参数\")\r\n    private String operParam;\r\n\r\n    /** 返回参数 */\r\n    @Excel(name = \"返回参数\")\r\n    private String jsonResult;\r\n\r\n    /** 操作状态（0正常 1异常） */\r\n    @Excel(name = \"状态\", readConverterExp = \"0=正常,1=异常\")\r\n    private Integer status;\r\n\r\n    /** 错误消息 */\r\n    @Excel(name = \"错误消息\")\r\n    private String errorMsg;\r\n\r\n    /** 操作时间 */\r\n    @Excel(name = \"操作时间\", width = 30, dateFormat = \"yyyy-MM-dd HH:mm:ss\")\r\n    private Date operTime;\r\n\r\n    /** 消耗时间 */\r\n    @Excel(name = \"消耗时间\", suffix = \"毫秒\")\r\n    private Long costTime;\r\n\r\n    public Long getOperId()\r\n    {\r\n        return operId;\r\n    }\r\n\r\n    public void setOperId(Long operId)\r\n    {\r\n        this.operId = operId;\r\n    }\r\n\r\n    public String getTitle()\r\n    {\r\n        return title;\r\n    }\r\n\r\n    public void setTitle(String title)\r\n    {\r\n        this.title = title;\r\n    }\r\n\r\n    public Integer getBusinessType()\r\n    {\r\n        return businessType;\r\n    }\r\n\r\n    public void setBusinessType(Integer businessType)\r\n    {\r\n        this.businessType = businessType;\r\n    }\r\n\r\n    public Integer[] getBusinessTypes()\r\n    {\r\n        return businessTypes;\r\n    }\r\n\r\n    public void setBusinessTypes(Integer[] businessTypes)\r\n    {\r\n        this.businessTypes = businessTypes;\r\n    }\r\n\r\n    public String getMethod()\r\n    {\r\n        return method;\r\n    }\r\n\r\n    public void setMethod(String method)\r\n    {\r\n        this.method = method;\r\n    }\r\n\r\n    public String getRequestMethod()\r\n    {\r\n        return requestMethod;\r\n    }\r\n\r\n    public void setRequestMethod(String requestMethod)\r\n    {\r\n        this.requestMethod = requestMethod;\r\n    }\r\n\r\n    public Integer getOperatorType()\r\n    {\r\n        return operatorType;\r\n    }\r\n\r\n    public void setOperatorType(Integer operatorType)\r\n    {\r\n        this.operatorType = operatorType;\r\n    }\r\n\r\n    public String getOperName()\r\n    {\r\n        return operName;\r\n    }\r\n\r\n    public void setOperName(String operName)\r\n    {\r\n        this.operName = operName;\r\n    }\r\n\r\n    public String getDeptName()\r\n    {\r\n        return deptName;\r\n    }\r\n\r\n    public void setDeptName(String deptName)\r\n    {\r\n        this.deptName = deptName;\r\n    }\r\n\r\n    public String getOperUrl()\r\n    {\r\n        return operUrl;\r\n    }\r\n\r\n    public void setOperUrl(String operUrl)\r\n    {\r\n        this.operUrl = operUrl;\r\n    }\r\n\r\n    public String getOperIp()\r\n    {\r\n        return operIp;\r\n    }\r\n\r\n    public void setOperIp(String operIp)\r\n    {\r\n        this.operIp = operIp;\r\n    }\r\n\r\n    public String getOperLocation()\r\n    {\r\n        return operLocation;\r\n    }\r\n\r\n    public void setOperLocation(String operLocation)\r\n    {\r\n        this.operLocation = operLocation;\r\n    }\r\n\r\n    public String getOperParam()\r\n    {\r\n        return operParam;\r\n    }\r\n\r\n    public void setOperParam(String operParam)\r\n    {\r\n        this.operParam = operParam;\r\n    }\r\n\r\n    public String getJsonResult()\r\n    {\r\n        return jsonResult;\r\n    }\r\n\r\n    public void setJsonResult(String jsonResult)\r\n    {\r\n        this.jsonResult = jsonResult;\r\n    }\r\n\r\n    public Integer getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(Integer status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public String getErrorMsg()\r\n    {\r\n        return errorMsg;\r\n    }\r\n\r\n    public void setErrorMsg(String errorMsg)\r\n    {\r\n        this.errorMsg = errorMsg;\r\n    }\r\n\r\n    public Date getOperTime()\r\n    {\r\n        return operTime;\r\n    }\r\n\r\n    public void setOperTime(Date operTime)\r\n    {\r\n        this.operTime = operTime;\r\n    }\r\n\r\n    public Long getCostTime()\r\n    {\r\n        return costTime;\r\n    }\r\n\r\n    public void setCostTime(Long costTime)\r\n    {\r\n        this.costTime = costTime;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"operId\", getOperId())\r\n            .append(\"title\", getTitle())\r\n            .append(\"businessType\", getBusinessType())\r\n            .append(\"businessTypes\", getBusinessTypes())\r\n            .append(\"method\", getMethod())\r\n            .append(\"requestMethod\", getRequestMethod())\r\n            .append(\"operatorType\", getOperatorType())\r\n            .append(\"operName\", getOperName())\r\n            .append(\"deptName\", getDeptName())\r\n            .append(\"operUrl\", getOperUrl())\r\n            .append(\"operIp\", getOperIp())\r\n            .append(\"operLocation\", getOperLocation())\r\n            .append(\"operParam\", getOperParam())\r\n            .append(\"status\", getStatus())\r\n            .append(\"errorMsg\", getErrorMsg())\r\n            .append(\"operTime\", getOperTime())\r\n            .append(\"costTime\", getCostTime())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport jakarta.validation.constraints.*;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.annotation.Excel;\r\nimport com.ruoyi.common.annotation.Excel.ColumnType;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\n\r\n/**\r\n * 岗位表 sys_post\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysPost extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n\r\n    /** 岗位序号 */\r\n    @Excel(name = \"岗位序号\", cellType = ColumnType.NUMERIC)\r\n    private Long postId;\r\n\r\n    /** 岗位编码 */\r\n    @Excel(name = \"岗位编码\")\r\n    private String postCode;\r\n\r\n    /** 岗位名称 */\r\n    @Excel(name = \"岗位名称\")\r\n    private String postName;\r\n\r\n    /** 岗位排序 */\r\n    @Excel(name = \"岗位排序\", cellType = ColumnType.NUMERIC)\r\n    private String postSort;\r\n\r\n    /** 状态（0正常 1停用） */\r\n    @Excel(name = \"状态\", readConverterExp = \"0=正常,1=停用\")\r\n    private String status;\r\n\r\n    /** 用户是否存在此岗位标识 默认不存在 */\r\n    private boolean flag = false;\r\n\r\n    public Long getPostId()\r\n    {\r\n        return postId;\r\n    }\r\n\r\n    public void setPostId(Long postId)\r\n    {\r\n        this.postId = postId;\r\n    }\r\n\r\n    @NotBlank(message = \"岗位编码不能为空\")\r\n    @Size(min = 0, max = 64, message = \"岗位编码长度不能超过64个字符\")\r\n    public String getPostCode()\r\n    {\r\n        return postCode;\r\n    }\r\n\r\n    public void setPostCode(String postCode)\r\n    {\r\n        this.postCode = postCode;\r\n    }\r\n\r\n    @NotBlank(message = \"岗位名称不能为空\")\r\n    @Size(min = 0, max = 50, message = \"岗位名称长度不能超过50个字符\")\r\n    public String getPostName()\r\n    {\r\n        return postName;\r\n    }\r\n\r\n    public void setPostName(String postName)\r\n    {\r\n        this.postName = postName;\r\n    }\r\n\r\n    @NotBlank(message = \"显示顺序不能为空\")\r\n    public String getPostSort()\r\n    {\r\n        return postSort;\r\n    }\r\n\r\n    public void setPostSort(String postSort)\r\n    {\r\n        this.postSort = postSort;\r\n    }\r\n\r\n    public String getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(String status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public boolean isFlag()\r\n    {\r\n        return flag;\r\n    }\r\n\r\n    public void setFlag(boolean flag)\r\n    {\r\n        this.flag = flag;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"postId\", getPostId())\r\n            .append(\"postCode\", getPostCode())\r\n            .append(\"postName\", getPostName())\r\n            .append(\"postSort\", getPostSort())\r\n            .append(\"status\", getStatus())\r\n            .append(\"createBy\", getCreateBy())\r\n            .append(\"createTime\", getCreateTime())\r\n            .append(\"updateBy\", getUpdateBy())\r\n            .append(\"updateTime\", getUpdateTime())\r\n            .append(\"remark\", getRemark())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\n\r\n/**\r\n * 角色和部门关联 sys_role_dept\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysRoleDept\r\n{\r\n    /** 角色ID */\r\n    private Long roleId;\r\n    \r\n    /** 部门ID */\r\n    private Long deptId;\r\n\r\n    public Long getRoleId()\r\n    {\r\n        return roleId;\r\n    }\r\n\r\n    public void setRoleId(Long roleId)\r\n    {\r\n        this.roleId = roleId;\r\n    }\r\n\r\n    public Long getDeptId()\r\n    {\r\n        return deptId;\r\n    }\r\n\r\n    public void setDeptId(Long deptId)\r\n    {\r\n        this.deptId = deptId;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"roleId\", getRoleId())\r\n            .append(\"deptId\", getDeptId())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\n\r\n/**\r\n * 角色和菜单关联 sys_role_menu\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysRoleMenu\r\n{\r\n    /** 角色ID */\r\n    private Long roleId;\r\n    \r\n    /** 菜单ID */\r\n    private Long menuId;\r\n\r\n    public Long getRoleId()\r\n    {\r\n        return roleId;\r\n    }\r\n\r\n    public void setRoleId(Long roleId)\r\n    {\r\n        this.roleId = roleId;\r\n    }\r\n\r\n    public Long getMenuId()\r\n    {\r\n        return menuId;\r\n    }\r\n\r\n    public void setMenuId(Long menuId)\r\n    {\r\n        this.menuId = menuId;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"roleId\", getRoleId())\r\n            .append(\"menuId\", getMenuId())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport java.util.Date;\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport com.ruoyi.common.core.domain.BaseEntity;\r\nimport com.ruoyi.common.core.session.OnlineSession;\r\nimport com.ruoyi.common.enums.OnlineStatus;\r\n\r\n/**\r\n * 当前在线会话 sys_user_online\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysUserOnline extends BaseEntity\r\n{\r\n    private static final long serialVersionUID = 1L;\r\n    \r\n    /** 用户会话id */\r\n    private String sessionId;\r\n\r\n    /** 部门名称 */\r\n    private String deptName;\r\n\r\n    /** 登录名称 */\r\n    private String loginName;\r\n\r\n    /** 登录IP地址 */\r\n    private String ipaddr;\r\n\r\n    /** 登录地址 */\r\n    private String loginLocation;\r\n\r\n    /** 浏览器类型 */\r\n    private String browser;\r\n\r\n    /** 操作系统 */\r\n    private String os;\r\n\r\n    /** session创建时间 */\r\n    private Date startTimestamp;\r\n\r\n    /** session最后访问时间 */\r\n    private Date lastAccessTime;\r\n\r\n    /** 超时时间，单位为毫秒 */\r\n    private Long expireTime;\r\n\r\n    /** 在线状态 */\r\n    private OnlineStatus status = OnlineStatus.on_line;\r\n\r\n    /** 备份的当前用户会话 */\r\n    private OnlineSession session;\r\n\r\n    /** 序列化的Session数据\\uff0c用于服务重吏后恢复会话 */\r\n    private byte[] sessionData;\r\n\r\n    public String getSessionId()\r\n    {\r\n        return sessionId;\r\n    }\r\n\r\n    public void setSessionId(String sessionId)\r\n    {\r\n        this.sessionId = sessionId;\r\n    }\r\n\r\n    public String getDeptName()\r\n    {\r\n        return deptName;\r\n    }\r\n\r\n    public void setDeptName(String deptName)\r\n    {\r\n        this.deptName = deptName;\r\n    }\r\n\r\n    public String getLoginName()\r\n    {\r\n        return loginName;\r\n    }\r\n\r\n    public void setLoginName(String loginName)\r\n    {\r\n        this.loginName = loginName;\r\n    }\r\n\r\n    public String getIpaddr()\r\n    {\r\n        return ipaddr;\r\n    }\r\n\r\n    public void setIpaddr(String ipaddr)\r\n    {\r\n        this.ipaddr = ipaddr;\r\n    }\r\n\r\n    public String getLoginLocation()\r\n    {\r\n        return loginLocation;\r\n    }\r\n\r\n    public void setLoginLocation(String loginLocation)\r\n    {\r\n        this.loginLocation = loginLocation;\r\n    }\r\n\r\n    public String getBrowser()\r\n    {\r\n        return browser;\r\n    }\r\n\r\n    public void setBrowser(String browser)\r\n    {\r\n        this.browser = browser;\r\n    }\r\n\r\n    public String getOs()\r\n    {\r\n        return os;\r\n    }\r\n\r\n    public void setOs(String os)\r\n    {\r\n        this.os = os;\r\n    }\r\n\r\n    public Date getStartTimestamp()\r\n    {\r\n        return startTimestamp;\r\n    }\r\n\r\n    public void setStartTimestamp(Date startTimestamp)\r\n    {\r\n        this.startTimestamp = startTimestamp;\r\n    }\r\n\r\n    public Date getLastAccessTime()\r\n    {\r\n        return lastAccessTime;\r\n    }\r\n\r\n    public void setLastAccessTime(Date lastAccessTime)\r\n    {\r\n        this.lastAccessTime = lastAccessTime;\r\n    }\r\n\r\n    public Long getExpireTime()\r\n    {\r\n        return expireTime;\r\n    }\r\n\r\n    public void setExpireTime(Long expireTime)\r\n    {\r\n        this.expireTime = expireTime;\r\n    }\r\n\r\n    public OnlineStatus getStatus()\r\n    {\r\n        return status;\r\n    }\r\n\r\n    public void setStatus(OnlineStatus status)\r\n    {\r\n        this.status = status;\r\n    }\r\n\r\n    public OnlineSession getSession()\r\n    {\r\n        return session;\r\n    }\r\n\r\n    public void setSession(OnlineSession session)\r\n    {\r\n        this.session = session;\r\n    }\r\n\r\n    public byte[] getSessionData()\r\n    {\r\n        return sessionData;\r\n    }\r\n\r\n    public void setSessionData(byte[] sessionData)\r\n    {\r\n        this.sessionData = sessionData;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"sessionId\", getSessionId())\r\n            .append(\"loginName\", getLoginName())\r\n            .append(\"deptName\", getDeptName())\r\n            .append(\"ipaddr\", getIpaddr())\r\n            .append(\"loginLocation\", getLoginLocation())\r\n            .append(\"browser\", getBrowser())\r\n            .append(\"os\", getOs())\r\n            .append(\"status\", getStatus())\r\n            .append(\"startTimestamp\", getStartTimestamp())\r\n            .append(\"lastAccessTime\", getLastAccessTime())\r\n            .append(\"expireTime\", getExpireTime())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\n\r\n/**\r\n * 用户和岗位关联 sys_user_post\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysUserPost\r\n{\r\n    /** 用户ID */\r\n    private Long userId;\r\n    \r\n    /** 岗位ID */\r\n    private Long postId;\r\n\r\n    public Long getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n\r\n    public void setUserId(Long userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public Long getPostId()\r\n    {\r\n        return postId;\r\n    }\r\n\r\n    public void setPostId(Long postId)\r\n    {\r\n        this.postId = postId;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"userId\", getUserId())\r\n            .append(\"postId\", getPostId())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java",
    "content": "package com.ruoyi.system.domain;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\n\r\n/**\r\n * 用户和角色关联 sys_user_role\r\n * \r\n * @author ruoyi\r\n */\r\npublic class SysUserRole\r\n{\r\n    /** 用户ID */\r\n    private Long userId;\r\n    \r\n    /** 角色ID */\r\n    private Long roleId;\r\n\r\n    public Long getUserId()\r\n    {\r\n        return userId;\r\n    }\r\n\r\n    public void setUserId(Long userId)\r\n    {\r\n        this.userId = userId;\r\n    }\r\n\r\n    public Long getRoleId()\r\n    {\r\n        return roleId;\r\n    }\r\n\r\n    public void setRoleId(Long roleId)\r\n    {\r\n        this.roleId = roleId;\r\n    }\r\n\r\n    @Override\r\n    public String toString() {\r\n        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)\r\n            .append(\"userId\", getUserId())\r\n            .append(\"roleId\", getRoleId())\r\n            .toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysConfig;\r\n\r\n/**\r\n * 参数配置 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysConfigMapper\r\n{\r\n    /**\r\n     * 查询参数配置信息\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 参数配置信息\r\n     */\r\n    public SysConfig selectConfig(SysConfig config);\r\n\r\n    /**\r\n     * 通过ID查询配置\r\n     * \r\n     * @param configId 参数ID\r\n     * @return 参数配置信息\r\n     */\r\n    public SysConfig selectConfigById(Long configId);\r\n\r\n    /**\r\n     * 查询参数配置列表\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 参数配置集合\r\n     */\r\n    public List<SysConfig> selectConfigList(SysConfig config);\r\n\r\n    /**\r\n     * 根据键名查询参数配置信息\r\n     * \r\n     * @param configKey 参数键名\r\n     * @return 参数配置信息\r\n     */\r\n    public SysConfig checkConfigKeyUnique(String configKey);\r\n\r\n    /**\r\n     * 新增参数配置\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 结果\r\n     */\r\n    public int insertConfig(SysConfig config);\r\n\r\n    /**\r\n     * 修改参数配置\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 结果\r\n     */\r\n    public int updateConfig(SysConfig config);\r\n\r\n    /**\r\n     * 删除参数配置\r\n     * \r\n     * @param configId 参数主键\r\n     * @return 结果\r\n     */\r\n    public int deleteConfigById(Long configId);\r\n\r\n    /**\r\n     * 批量删除参数配置\r\n     * \r\n     * @param configIds 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteConfigByIds(String[] configIds);\r\n}"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport org.apache.ibatis.annotations.Param;\r\nimport com.ruoyi.common.core.domain.entity.SysDept;\r\n\r\n/**\r\n * 部门管理 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysDeptMapper\r\n{\r\n    /**\r\n     * 查询下级部门数量\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    public int selectDeptCount(SysDept dept);\r\n\r\n    /**\r\n     * 查询部门是否存在用户\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 结果\r\n     */\r\n    public int checkDeptExistUser(Long deptId);\r\n\r\n    /**\r\n     * 查询部门管理数据\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 部门信息集合\r\n     */\r\n    public List<SysDept> selectDeptList(SysDept dept);\r\n\r\n    /**\r\n     * 删除部门管理信息\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 结果\r\n     */\r\n    public int deleteDeptById(Long deptId);\r\n\r\n    /**\r\n     * 新增部门信息\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    public int insertDept(SysDept dept);\r\n\r\n    /**\r\n     * 修改部门信息\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    public int updateDept(SysDept dept);\r\n\r\n    /**\r\n     * 修改子元素关系\r\n     * \r\n     * @param depts 子元素\r\n     * @return 结果\r\n     */\r\n    public int updateDeptChildren(@Param(\"depts\") List<SysDept> depts);\r\n\r\n    /**\r\n     * 根据部门ID查询信息\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 部门信息\r\n     */\r\n    public SysDept selectDeptById(Long deptId);\r\n\r\n    /**\r\n     * 校验部门名称是否唯一\r\n     * \r\n     * @param deptName 部门名称\r\n     * @param parentId 父部门ID\r\n     * @return 结果\r\n     */\r\n    public SysDept checkDeptNameUnique(@Param(\"deptName\") String deptName, @Param(\"parentId\") Long parentId);\r\n\r\n    /**\r\n     * 根据角色ID查询部门\r\n     *\r\n     * @param roleId 角色ID\r\n     * @return 部门列表\r\n     */\r\n    public List<String> selectRoleDeptTree(Long roleId);\r\n\r\n    /**\r\n     * 修改所在部门正常状态\r\n     * \r\n     * @param deptIds 部门ID组\r\n     */\r\n    public void updateDeptStatusNormal(Long[] deptIds);\r\n\r\n    /**\r\n     * 根据ID查询所有子部门\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 部门列表\r\n     */\r\n    public List<SysDept> selectChildrenDeptById(Long deptId);\r\n\r\n    /**\r\n     * 根据ID查询所有子部门（正常状态）\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 子部门数\r\n     */\r\n    public int selectNormalChildrenDeptById(Long deptId);\r\n\r\n    /**\r\n     * 保存部门排序\r\n     *\r\n     * @param dept 部门信息（含deptId和orderNum）\r\n     */\r\n    public void updateDeptSort(SysDept dept);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport org.apache.ibatis.annotations.Param;\r\nimport com.ruoyi.common.core.domain.entity.SysDictData;\r\n\r\n/**\r\n * 字典表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysDictDataMapper\r\n{\r\n    /**\r\n     * 根据条件分页查询字典数据\r\n     * \r\n     * @param dictData 字典数据信息\r\n     * @return 字典数据集合信息\r\n     */\r\n    public List<SysDictData> selectDictDataList(SysDictData dictData);\r\n\r\n    /**\r\n     * 根据字典类型查询字典数据\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 字典数据集合信息\r\n     */\r\n    public List<SysDictData> selectDictDataByType(String dictType);\r\n\r\n    /**\r\n     * 根据字典类型和字典键值查询字典数据信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @param dictValue 字典键值\r\n     * @return 字典标签\r\n     */\r\n    public String selectDictLabel(@Param(\"dictType\") String dictType, @Param(\"dictValue\") String dictValue);\r\n\r\n    /**\r\n     * 根据字典数据ID查询信息\r\n     * \r\n     * @param dictCode 字典数据ID\r\n     * @return 字典数据\r\n     */\r\n    public SysDictData selectDictDataById(Long dictCode);\r\n\r\n    /**\r\n     * 查询字典数据\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 字典数据\r\n     */\r\n    public int countDictDataByType(String dictType);\r\n\r\n    /**\r\n     * 通过字典ID删除字典数据信息\r\n     * \r\n     * @param dictCode 字典数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteDictDataById(Long dictCode);\r\n\r\n    /**\r\n     * 批量删除字典数据\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return 结果\r\n     */\r\n    public int deleteDictDataByIds(String[] ids);\r\n\r\n    /**\r\n     * 新增字典数据信息\r\n     * \r\n     * @param dictData 字典数据信息\r\n     * @return 结果\r\n     */\r\n    public int insertDictData(SysDictData dictData);\r\n\r\n    /**\r\n     * 修改字典数据信息\r\n     * \r\n     * @param dictData 字典数据信息\r\n     * @return 结果\r\n     */\r\n    public int updateDictData(SysDictData dictData);\r\n\r\n    /**\r\n     * 同步修改字典类型\r\n     * \r\n     * @param oldDictType 旧字典类型\r\n     * @param newDictType 新旧字典类型\r\n     * @return 结果\r\n     */\r\n    public int updateDictDataType(@Param(\"oldDictType\") String oldDictType, @Param(\"newDictType\") String newDictType);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.common.core.domain.entity.SysDictType;\r\n\r\n/**\r\n * 字典表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysDictTypeMapper\r\n{\r\n    /**\r\n     * 根据条件分页查询字典类型\r\n     * \r\n     * @param dictType 字典类型信息\r\n     * @return 字典类型集合信息\r\n     */\r\n    public List<SysDictType> selectDictTypeList(SysDictType dictType);\r\n\r\n    /**\r\n     * 根据所有字典类型\r\n     * \r\n     * @return 字典类型集合信息\r\n     */\r\n    public List<SysDictType> selectDictTypeAll();\r\n\r\n    /**\r\n     * 根据字典类型ID查询信息\r\n     * \r\n     * @param dictId 字典类型ID\r\n     * @return 字典类型\r\n     */\r\n    public SysDictType selectDictTypeById(Long dictId);\r\n\r\n    /**\r\n     * 根据字典类型查询信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 字典类型\r\n     */\r\n    public SysDictType selectDictTypeByType(String dictType);\r\n\r\n    /**\r\n     * 通过字典ID删除字典信息\r\n     * \r\n     * @param dictId 字典ID\r\n     * @return 结果\r\n     */\r\n    public int deleteDictTypeById(Long dictId);\r\n\r\n    /**\r\n     * 批量删除字典类型\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return 结果\r\n     */\r\n    public int deleteDictTypeByIds(Long[] ids);\r\n\r\n    /**\r\n     * 新增字典类型信息\r\n     * \r\n     * @param dictType 字典类型信息\r\n     * @return 结果\r\n     */\r\n    public int insertDictType(SysDictType dictType);\r\n\r\n    /**\r\n     * 修改字典类型信息\r\n     * \r\n     * @param dictType 字典类型信息\r\n     * @return 结果\r\n     */\r\n    public int updateDictType(SysDictType dictType);\r\n\r\n    /**\r\n     * 校验字典类型称是否唯一\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 结果\r\n     */\r\n    public SysDictType checkDictTypeUnique(String dictType);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysLogininfor;\r\n\r\n/**\r\n * 系统访问日志情况信息 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysLogininforMapper\r\n{\r\n    /**\r\n     * 新增系统登录日志\r\n     * \r\n     * @param logininfor 访问日志对象\r\n     */\r\n    public void insertLogininfor(SysLogininfor logininfor);\r\n\r\n    /**\r\n     * 查询系统登录日志集合\r\n     * \r\n     * @param logininfor 访问日志对象\r\n     * @return 登录记录集合\r\n     */\r\n    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);\r\n\r\n    /**\r\n     * 批量删除系统登录日志\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return 结果\r\n     */\r\n    public int deleteLogininforByIds(String[] ids);\r\n\r\n    /**\r\n     * 清空系统登录日志\r\n     * \r\n     * @return 结果\r\n     */\r\n    public int cleanLogininfor();\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport org.apache.ibatis.annotations.Param;\r\nimport com.ruoyi.common.core.domain.entity.SysMenu;\r\n\r\n/**\r\n * 菜单表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysMenuMapper\r\n{\r\n    /**\r\n     * 查询系统所有菜单（含按钮）\r\n     * \r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenuAll();\r\n\r\n    /**\r\n     * 根据用户ID查询菜单\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenuAllByUserId(Long userId);\r\n\r\n    /**\r\n     * 查询系统正常显示菜单（不含按钮）\r\n     * \r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenuNormalAll();\r\n\r\n    /**\r\n     * 根据用户ID查询菜单\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenusByUserId(Long userId);\r\n\r\n    /**\r\n     * 根据用户ID查询权限\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 权限列表\r\n     */\r\n    public List<String> selectPermsByUserId(Long userId);\r\n\r\n    /**\r\n     * 根据角色ID查询权限\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 权限列表\r\n     */\r\n    public List<String> selectPermsByRoleId(Long roleId);\r\n\r\n    /**\r\n     * 根据角色ID查询菜单\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 菜单列表\r\n     */\r\n    public List<String> selectMenuTree(Long roleId);\r\n\r\n    /**\r\n     * 查询系统菜单列表\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenuList(SysMenu menu);\r\n\r\n    /**\r\n     * 查询系统菜单列表\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenuListByUserId(SysMenu menu);\r\n\r\n    /**\r\n     * 删除菜单管理信息\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 结果\r\n     */\r\n    public int deleteMenuById(Long menuId);\r\n\r\n    /**\r\n     * 根据菜单ID查询信息\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 菜单信息\r\n     */\r\n    public SysMenu selectMenuById(Long menuId);\r\n\r\n    /**\r\n     * 查询菜单数量\r\n     * \r\n     * @param parentId 菜单父ID\r\n     * @return 结果\r\n     */\r\n    public int selectCountMenuByParentId(Long parentId);\r\n\r\n    /**\r\n     * 新增菜单信息\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    public int insertMenu(SysMenu menu);\r\n\r\n    /**\r\n     * 修改菜单信息\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    public int updateMenu(SysMenu menu);\r\n\r\n    /**\r\n     * 保存菜单排序\r\n     * \r\n     * @param menu 菜单信息\r\n     */\r\n    public void updateMenuSort(SysMenu menu);\r\n\r\n    /**\r\n     * 校验菜单名称是否唯一\r\n     * \r\n     * @param menuName 菜单名称\r\n     * @param parentId 父菜单ID\r\n     * @return 结果\r\n     */\r\n    public SysMenu checkMenuNameUnique(@Param(\"menuName\") String menuName, @Param(\"parentId\") Long parentId);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysNotice;\r\n\r\n/**\r\n * 公告 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysNoticeMapper\r\n{\r\n    /**\r\n     * 查询公告信息\r\n     * \r\n     * @param noticeId 公告ID\r\n     * @return 公告信息\r\n     */\r\n    public SysNotice selectNoticeById(Long noticeId);\r\n\r\n    /**\r\n     * 查询公告列表\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 公告集合\r\n     */\r\n    public List<SysNotice> selectNoticeList(SysNotice notice);\r\n\r\n    /**\r\n     * 新增公告\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 结果\r\n     */\r\n    public int insertNotice(SysNotice notice);\r\n\r\n    /**\r\n     * 修改公告\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 结果\r\n     */\r\n    public int updateNotice(SysNotice notice);\r\n\r\n    /**\r\n     * 批量删除公告\r\n     * \r\n     * @param noticeIds 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteNoticeByIds(String[] noticeIds);\r\n}"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeReadMapper.java",
    "content": "package com.ruoyi.system.mapper;\n\nimport java.util.List;\nimport org.apache.ibatis.annotations.Param;\nimport com.ruoyi.system.domain.SysNoticeRead;\nimport com.ruoyi.system.domain.SysNotice;\n\n/**\n * 公告已读记录 数据层\n *\n * @author ruoyi\n */\npublic interface SysNoticeReadMapper\n{\n    /**\n     * 新增已读记录（忽略重复）\n     *\n     * @param noticeRead 已读记录\n     * @return 结果\n     */\n    public int insertNoticeRead(SysNoticeRead noticeRead);\n\n    /**\n     * 查询某用户未读公告数量\n     *\n     * @param userId 用户ID\n     * @return 未读数量\n     */\n    public int selectUnreadCount(@Param(\"userId\") Long userId);\n\n    /**\n     * 查询某用户是否已读某公告\n     *\n     * @param noticeId 公告ID\n     * @param userId   用户ID\n     * @return 已读记录数（0未读 1已读）\n     */\n    public int selectIsRead(@Param(\"noticeId\") Long noticeId, @Param(\"userId\") Long userId);\n\n    /**\n     * 批量标记已读\n     *\n     * @param userId    用户ID\n     * @param noticeIds 公告ID数组\n     * @return 结果\n     */\n    public int insertNoticeReadBatch(@Param(\"userId\") Long userId, @Param(\"noticeIds\") Long[] noticeIds);\n\n    /**\n     * 查询带已读状态的公告列表（SQL层限制条数，一次查询完成）\n     *\n     * @param userId 用户ID\n     * @param limit  最多返回条数\n     * @return 带 isRead 标记的公告列表\n     */\n    public List<SysNotice> selectNoticeListWithReadStatus(@Param(\"userId\") Long userId, @Param(\"limit\") int limit);\n\n    /**\n     * 公告删除时清理对应已读记录\n     *\n     * @param noticeIds 公告ID数组\n     * @return 结果\n     */\n    public int deleteByNoticeIds(@Param(\"noticeIds\") String[] noticeIds);\n}\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysOperLog;\r\n\r\n/**\r\n * 操作日志 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysOperLogMapper\r\n{\r\n    /**\r\n     * 新增操作日志\r\n     * \r\n     * @param operLog 操作日志对象\r\n     */\r\n    public void insertOperlog(SysOperLog operLog);\r\n\r\n    /**\r\n     * 查询系统操作日志集合\r\n     * \r\n     * @param operLog 操作日志对象\r\n     * @return 操作日志集合\r\n     */\r\n    public List<SysOperLog> selectOperLogList(SysOperLog operLog);\r\n    \r\n    /**\r\n     * 批量删除系统操作日志\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return 结果\r\n     */\r\n    public int deleteOperLogByIds(String[] ids);\r\n    \r\n    /**\r\n     * 查询操作日志详细\r\n     * \r\n     * @param operId 操作ID\r\n     * @return 操作日志对象\r\n     */\r\n    public SysOperLog selectOperLogById(Long operId);\r\n    \r\n    /**\r\n     * 清空操作日志\r\n     */\r\n    public void cleanOperLog();\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysPost;\r\n\r\n/**\r\n * 岗位信息 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysPostMapper\r\n{\r\n    /**\r\n     * 查询岗位数据集合\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 岗位数据集合\r\n     */\r\n    public List<SysPost> selectPostList(SysPost post);\r\n\r\n    /**\r\n     * 查询所有岗位\r\n     * \r\n     * @return 岗位列表\r\n     */\r\n    public List<SysPost> selectPostAll();\r\n\r\n    /**\r\n     * 根据用户ID查询岗位\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 岗位列表\r\n     */\r\n    public List<SysPost> selectPostsByUserId(Long userId);\r\n\r\n    /**\r\n     * 通过岗位ID查询岗位信息\r\n     * \r\n     * @param postId 岗位ID\r\n     * @return 角色对象信息\r\n     */\r\n    public SysPost selectPostById(Long postId);\r\n\r\n    /**\r\n     * 批量删除岗位信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deletePostByIds(Long[] ids);\r\n\r\n    /**\r\n     * 修改岗位信息\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    public int updatePost(SysPost post);\r\n\r\n    /**\r\n     * 新增岗位信息\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    public int insertPost(SysPost post);\r\n\r\n    /**\r\n     * 校验岗位名称\r\n     * \r\n     * @param postName 岗位名称\r\n     * @return 结果\r\n     */\r\n    public SysPost checkPostNameUnique(String postName);\r\n\r\n    /**\r\n     * 校验岗位编码\r\n     * \r\n     * @param postCode 岗位编码\r\n     * @return 结果\r\n     */\r\n    public SysPost checkPostCodeUnique(String postCode);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysRoleDept;\r\n\r\n/**\r\n * 角色与部门关联表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysRoleDeptMapper\r\n{\r\n    /**\r\n     * 通过角色ID删除角色和部门关联\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    public int deleteRoleDeptByRoleId(Long roleId);\r\n\r\n    /**\r\n     * 批量删除角色部门关联信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteRoleDept(Long[] ids);\r\n\r\n    /**\r\n     * 查询部门使用数量\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 结果\r\n     */\r\n    public int selectCountRoleDeptByDeptId(Long deptId);\r\n\r\n    /**\r\n     * 批量新增角色部门信息\r\n     * \r\n     * @param roleDeptList 角色部门列表\r\n     * @return 结果\r\n     */\r\n    public int batchRoleDept(List<SysRoleDept> roleDeptList);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\n\r\n/**\r\n * 角色表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysRoleMapper\r\n{\r\n    /**\r\n     * 根据条件分页查询角色数据\r\n     * \r\n     * @param role 角色信息\r\n     * @return 角色数据集合信息\r\n     */\r\n    public List<SysRole> selectRoleList(SysRole role);\r\n\r\n    /**\r\n     * 根据用户ID查询角色\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 角色列表\r\n     */\r\n    public List<SysRole> selectRolesByUserId(Long userId);\r\n\r\n    /**\r\n     * 通过角色ID查询角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 角色对象信息\r\n     */\r\n    public SysRole selectRoleById(Long roleId);\r\n\r\n    /**\r\n     * 通过角色ID删除角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    public int deleteRoleById(Long roleId);\r\n\r\n    /**\r\n     * 批量角色用户信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteRoleByIds(Long[] ids);\r\n\r\n    /**\r\n     * 修改角色信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public int updateRole(SysRole role);\r\n\r\n    /**\r\n     * 新增角色信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public int insertRole(SysRole role);\r\n\r\n    /**\r\n     * 校验角色名称是否唯一\r\n     * \r\n     * @param roleName 角色名称\r\n     * @return 角色信息\r\n     */\r\n    public SysRole checkRoleNameUnique(String roleName);\r\n    \r\n    /**\r\n     * 校验角色权限是否唯一\r\n     * \r\n     * @param roleKey 角色权限\r\n     * @return 角色信息\r\n     */\r\n    public SysRole checkRoleKeyUnique(String roleKey);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysRoleMenu;\r\n\r\n/**\r\n * 角色与菜单关联表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysRoleMenuMapper\r\n{\r\n    /**\r\n     * 通过角色ID删除角色和菜单关联\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    public int deleteRoleMenuByRoleId(Long roleId);\r\n    \r\n    /**\r\n     * 批量删除角色菜单关联信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteRoleMenu(Long[] ids);\r\n    \r\n    /**\r\n     * 查询菜单使用数量\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 结果\r\n     */\r\n    public int selectCountRoleMenuByMenuId(Long menuId);\r\n    \r\n    /**\r\n     * 批量新增角色菜单信息\r\n     * \r\n     * @param roleMenuList 角色菜单列表\r\n     * @return 结果\r\n     */\r\n    public int batchRoleMenu(List<SysRoleMenu> roleMenuList);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport org.apache.ibatis.annotations.Param;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\n\r\n/**\r\n * 用户表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysUserMapper\r\n{\r\n    /**\r\n     * 根据条件分页查询用户列表\r\n     * \r\n     * @param sysUser 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    public List<SysUser> selectUserList(SysUser sysUser);\r\n\r\n    /**\r\n     * 根据条件分页查询已配用户角色列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    public List<SysUser> selectAllocatedList(SysUser user);\r\n\r\n    /**\r\n     * 根据条件分页查询未分配用户角色列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    public List<SysUser> selectUnallocatedList(SysUser user);\r\n\r\n    /**\r\n     * 通过用户名查询用户\r\n     * \r\n     * @param userName 用户名\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserByLoginName(String userName);\r\n\r\n    /**\r\n     * 通过手机号码查询用户\r\n     * \r\n     * @param phoneNumber 手机号码\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserByPhoneNumber(String phoneNumber);\r\n\r\n    /**\r\n     * 通过邮箱查询用户\r\n     * \r\n     * @param email 邮箱\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserByEmail(String email);\r\n\r\n    /**\r\n     * 通过用户ID查询用户\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserById(Long userId);\r\n\r\n    /**\r\n     * 通过用户ID删除用户\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserById(Long userId);\r\n\r\n    /**\r\n     * 批量删除用户信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserByIds(Long[] ids);\r\n\r\n    /**\r\n     * 修改用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public int updateUser(SysUser user);\r\n\r\n    /**\r\n     * 修改用户头像\r\n     * \r\n     * @param userId 用户ID\r\n     * @param avatar 头像地址\r\n     * @return 结果\r\n     */\r\n    public int updateUserAvatar(@Param(\"userId\") Long userId, @Param(\"avatar\") String avatar);\r\n\r\n    /**\r\n     * 修改用户状态\r\n     * \r\n     * @param userId 用户ID\r\n     * @param status 状态\r\n     * @return 结果\r\n     */\r\n    public int updateUserStatus(@Param(\"userId\") Long userId, @Param(\"status\") String status);\r\n\r\n    /**\r\n     * 重置用户密码\r\n     * \r\n     * @param userId 用户ID\r\n     * @param password 密码\r\n     * @param salt 盐\r\n     * @return 结果\r\n     */\r\n    public int resetUserPwd(@Param(\"userId\") Long userId, @Param(\"password\") String password, @Param(\"salt\") String salt);\r\n\r\n    /**\r\n     * 更新用户登录信息（IP和登录时间）\r\n     * \r\n     * @param userId 用户ID\r\n     * @param loginIp 登录IP地址\r\n     * @param loginDate 登录时间\r\n     * @return 结果\r\n     */\r\n    public int updateLoginInfo(@Param(\"userId\") Long userId, @Param(\"loginIp\") String loginIp, @Param(\"loginDate\") Date loginDate);\r\n\r\n    /**\r\n     * 新增用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public int insertUser(SysUser user);\r\n\r\n    /**\r\n     * 校验用户名称是否唯一\r\n     * \r\n     * @param loginName 登录名称\r\n     * @return 结果\r\n     */\r\n    public SysUser checkLoginNameUnique(String loginName);\r\n\r\n    /**\r\n     * 校验手机号码是否唯一\r\n     *\r\n     * @param phonenumber 手机号码\r\n     * @return 结果\r\n     */\r\n    public SysUser checkPhoneUnique(String phonenumber);\r\n\r\n    /**\r\n     * 校验email是否唯一\r\n     *\r\n     * @param email 用户邮箱\r\n     * @return 结果\r\n     */\r\n    public SysUser checkEmailUnique(String email);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserOnlineMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysUserOnline;\r\n\r\n/**\r\n * 在线用户 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysUserOnlineMapper\r\n{\r\n    /**\r\n     * 通过会话序号查询信息\r\n     * \r\n     * @param sessionId 会话ID\r\n     * @return 在线用户信息\r\n     */\r\n    public SysUserOnline selectOnlineById(String sessionId);\r\n\r\n    /**\r\n     * 通过会话序号删除信息\r\n     * \r\n     * @param sessionId 会话ID\r\n     * @return 在线用户信息\r\n     */\r\n    public int deleteOnlineById(String sessionId);\r\n\r\n    /**\r\n     * 保存会话信息\r\n     * \r\n     * @param online 会话信息\r\n     * @return 结果\r\n     */\r\n    public int saveOnline(SysUserOnline online);\r\n\r\n    /**\r\n     * 查询会话集合\r\n     * \r\n     * @param userOnline 会话参数\r\n     * @return 会话集合\r\n     */\r\n    public List<SysUserOnline> selectUserOnlineList(SysUserOnline userOnline);\r\n\r\n    /**\r\n     * 查询过期会话集合\r\n     * \r\n     * @param lastAccessTime 过期时间\r\n     * @return 会话集合\r\n     */\r\n    public List<SysUserOnline> selectOnlineByExpired(String lastAccessTime);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysUserPost;\r\n\r\n/**\r\n * 用户与岗位关联表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysUserPostMapper\r\n{\r\n    /**\r\n     * 通过用户ID删除用户和岗位关联\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserPostByUserId(Long userId);\r\n    \r\n    /**\r\n     * 通过岗位ID查询岗位使用数量\r\n     * \r\n     * @param postId 岗位ID\r\n     * @return 结果\r\n     */\r\n    public int countUserPostById(Long postId);\r\n    \r\n    /**\r\n     * 批量删除用户和岗位关联\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserPost(Long[] ids);\r\n\r\n    /**\r\n     * 批量新增用户岗位信息\r\n     * \r\n     * @param userPostList 用户岗位列表\r\n     * @return 结果\r\n     */\r\n    public int batchUserPost(List<SysUserPost> userPostList);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java",
    "content": "package com.ruoyi.system.mapper;\r\n\r\nimport java.util.List;\r\nimport org.apache.ibatis.annotations.Param;\r\nimport com.ruoyi.system.domain.SysUserRole;\r\n\r\n/**\r\n * 用户与角色关联表 数据层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface SysUserRoleMapper\r\n{\r\n    /**\r\n     * 通过用户ID查询用户和角色关联\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 用户和角色关联列表\r\n     */\r\n    public List<SysUserRole> selectUserRoleByUserId(Long userId);\r\n\r\n    /**\r\n     * 通过用户ID删除用户和角色关联\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserRoleByUserId(Long userId);\r\n\r\n    /**\r\n     * 批量删除用户和角色关联\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserRole(Long[] ids);\r\n\r\n    /**\r\n     * 通过角色ID查询角色使用数量\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    public int countUserRoleByRoleId(Long roleId);\r\n\r\n    /**\r\n     * 批量新增用户角色信息\r\n     * \r\n     * @param userRoleList 用户角色列表\r\n     * @return 结果\r\n     */\r\n    public int batchUserRole(List<SysUserRole> userRoleList);\r\n\r\n    /**\r\n     * 删除用户和角色关联信息\r\n     * \r\n     * @param userRole 用户和角色关联信息\r\n     * @return 结果\r\n     */\r\n    public int deleteUserRoleInfo(SysUserRole userRole);\r\n\r\n    /**\r\n     * 批量取消授权用户角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @param userIds 需要删除的用户数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserRoleInfos(@Param(\"roleId\") Long roleId, @Param(\"userIds\") Long[] userIds);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysConfig;\r\n\r\n/**\r\n * 参数配置 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysConfigService\r\n{\r\n    /**\r\n     * 查询参数配置信息\r\n     * \r\n     * @param configId 参数配置ID\r\n     * @return 参数配置信息\r\n     */\r\n    public SysConfig selectConfigById(Long configId);\r\n\r\n    /**\r\n     * 根据键名查询参数配置信息\r\n     * \r\n     * @param configKey 参数键名\r\n     * @return 参数键值\r\n     */\r\n    public String selectConfigByKey(String configKey);\r\n\r\n    /**\r\n     * 查询参数配置列表\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 参数配置集合\r\n     */\r\n    public List<SysConfig> selectConfigList(SysConfig config);\r\n\r\n    /**\r\n     * 新增参数配置\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 结果\r\n     */\r\n    public int insertConfig(SysConfig config);\r\n\r\n    /**\r\n     * 修改参数配置\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 结果\r\n     */\r\n    public int updateConfig(SysConfig config);\r\n\r\n    /**\r\n     * 批量删除参数配置信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     */\r\n    public void deleteConfigByIds(String ids);\r\n\r\n    /**\r\n     * 加载参数缓存数据\r\n     */\r\n    public void loadingConfigCache();\r\n\r\n    /**\r\n     * 清空参数缓存数据\r\n     */\r\n    public void clearConfigCache();\r\n\r\n    /**\r\n     * 重置参数缓存数据\r\n     */\r\n    public void resetConfigCache();\r\n\r\n    /**\r\n     * 校验参数键名是否唯一\r\n     * \r\n     * @param config 参数信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkConfigKeyUnique(SysConfig config);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysDept;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\n\r\n/**\r\n * 部门管理 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysDeptService\r\n{\r\n    /**\r\n     * 查询部门管理数据\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 部门信息集合\r\n     */\r\n    public List<SysDept> selectDeptList(SysDept dept);\r\n\r\n    /**\r\n     * 查询部门管理树\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 所有部门信息\r\n     */\r\n    public List<Ztree> selectDeptTree(SysDept dept);\r\n\r\n    /**\r\n     * 查询部门管理树（排除下级）\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 所有部门信息\r\n     */\r\n    public List<Ztree> selectDeptTreeExcludeChild(SysDept dept);\r\n\r\n    /**\r\n     * 根据角色ID查询菜单\r\n     *\r\n     * @param role 角色对象\r\n     * @return 菜单列表\r\n     */\r\n    public List<Ztree> roleDeptTreeData(SysRole role);\r\n\r\n    /**\r\n     * 根据父部门ID查询下级部门数量\r\n     * \r\n     * @param parentId 父部门ID\r\n     * @return 结果\r\n     */\r\n    public int selectDeptCount(Long parentId);\r\n\r\n    /**\r\n     * 查询部门是否存在用户\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 结果 true 存在 false 不存在\r\n     */\r\n    public boolean checkDeptExistUser(Long deptId);\r\n\r\n    /**\r\n     * 删除部门管理信息\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 结果\r\n     */\r\n    public int deleteDeptById(Long deptId);\r\n\r\n    /**\r\n     * 新增保存部门信息\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    public int insertDept(SysDept dept);\r\n\r\n    /**\r\n     * 修改保存部门信息\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    public int updateDept(SysDept dept);\r\n\r\n    /**\r\n     * 根据部门ID查询信息\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 部门信息\r\n     */\r\n    public SysDept selectDeptById(Long deptId);\r\n\r\n    /**\r\n     * 根据ID查询所有子部门（正常状态）\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 子部门数\r\n     */\r\n    public int selectNormalChildrenDeptById(Long deptId);\r\n\r\n    /**\r\n     * 校验部门名称是否唯一\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkDeptNameUnique(SysDept dept);\r\n\r\n    /**\r\n     * 校验部门是否有数据权限\r\n     * \r\n     * @param deptId 部门id\r\n     */\r\n    public void checkDeptDataScope(Long deptId);\r\n\r\n    /**\r\n     * 保存部门排序\r\n     *\r\n     * @param deptIds 部门ID数组\r\n     * @param orderNums 排序数组\r\n     */\r\n    public void updateDeptSort(String[] deptIds, String[] orderNums);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.common.core.domain.entity.SysDictData;\r\n\r\n/**\r\n * 字典 业务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysDictDataService\r\n{\r\n    /**\r\n     * 根据条件分页查询字典数据\r\n     * \r\n     * @param dictData 字典数据信息\r\n     * @return 字典数据集合信息\r\n     */\r\n    public List<SysDictData> selectDictDataList(SysDictData dictData);\r\n\r\n    /**\r\n     * 根据字典类型和字典键值查询字典数据信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @param dictValue 字典键值\r\n     * @return 字典标签\r\n     */\r\n    public String selectDictLabel(String dictType, String dictValue);\r\n\r\n    /**\r\n     * 根据字典数据ID查询信息\r\n     * \r\n     * @param dictCode 字典数据ID\r\n     * @return 字典数据\r\n     */\r\n    public SysDictData selectDictDataById(Long dictCode);\r\n\r\n    /**\r\n     * 批量删除字典数据\r\n     * \r\n     * @param ids 需要删除的数据\r\n     */\r\n    public void deleteDictDataByIds(String ids);\r\n\r\n    /**\r\n     * 新增保存字典数据信息\r\n     * \r\n     * @param dictData 字典数据信息\r\n     * @return 结果\r\n     */\r\n    public int insertDictData(SysDictData dictData);\r\n\r\n    /**\r\n     * 修改保存字典数据信息\r\n     * \r\n     * @param dictData 字典数据信息\r\n     * @return 结果\r\n     */\r\n    public int updateDictData(SysDictData dictData);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysDictData;\r\nimport com.ruoyi.common.core.domain.entity.SysDictType;\r\n\r\n/**\r\n * 字典 业务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysDictTypeService\r\n{\r\n    /**\r\n     * 根据条件分页查询字典类型\r\n     * \r\n     * @param dictType 字典类型信息\r\n     * @return 字典类型集合信息\r\n     */\r\n    public List<SysDictType> selectDictTypeList(SysDictType dictType);\r\n\r\n    /**\r\n     * 根据所有字典类型\r\n     * \r\n     * @return 字典类型集合信息\r\n     */\r\n    public List<SysDictType> selectDictTypeAll();\r\n\r\n    /**\r\n     * 根据字典类型查询字典数据\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 字典数据集合信息\r\n     */\r\n    public List<SysDictData> selectDictDataByType(String dictType);\r\n\r\n    /**\r\n     * 根据字典类型ID查询信息\r\n     * \r\n     * @param dictId 字典类型ID\r\n     * @return 字典类型\r\n     */\r\n    public SysDictType selectDictTypeById(Long dictId);\r\n\r\n    /**\r\n     * 根据字典类型查询信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 字典类型\r\n     */\r\n    public SysDictType selectDictTypeByType(String dictType);\r\n\r\n    /**\r\n     * 批量删除字典类型\r\n     * \r\n     * @param ids 需要删除的数据\r\n     */\r\n    public void deleteDictTypeByIds(String ids);\r\n\r\n    /**\r\n     * 加载字典缓存数据\r\n     */\r\n    public void loadingDictCache();\r\n\r\n    /**\r\n     * 清空字典缓存数据\r\n     */\r\n    public void clearDictCache();\r\n\r\n    /**\r\n     * 重置字典缓存数据\r\n     */\r\n    public void resetDictCache();\r\n\r\n    /**\r\n     * 新增保存字典类型信息\r\n     * \r\n     * @param dictType 字典类型信息\r\n     * @return 结果\r\n     */\r\n    public int insertDictType(SysDictType dictType);\r\n\r\n    /**\r\n     * 修改保存字典类型信息\r\n     * \r\n     * @param dictType 字典类型信息\r\n     * @return 结果\r\n     */\r\n    public int updateDictType(SysDictType dictType);\r\n\r\n    /**\r\n     * 校验字典类型称是否唯一\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 结果\r\n     */\r\n    public boolean checkDictTypeUnique(SysDictType dictType);\r\n\r\n    /**\r\n     * 查询字典类型树\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 所有字典类型\r\n     */\r\n    public List<Ztree> selectDictTree(SysDictType dictType);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysLogininfor;\r\n\r\n/**\r\n * 系统访问日志情况信息 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysLogininforService\r\n{\r\n    /**\r\n     * 新增系统登录日志\r\n     * \r\n     * @param logininfor 访问日志对象\r\n     */\r\n    public void insertLogininfor(SysLogininfor logininfor);\r\n\r\n    /**\r\n     * 查询系统登录日志集合\r\n     * \r\n     * @param logininfor 访问日志对象\r\n     * @return 登录记录集合\r\n     */\r\n    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);\r\n\r\n    /**\r\n     * 批量删除系统登录日志\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return 结果\r\n     */\r\n    public int deleteLogininforByIds(String ids);\r\n\r\n    /**\r\n     * 清空系统登录日志\r\n     */\r\n    public void cleanLogininfor();\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.Set;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysMenu;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\n\r\n/**\r\n * 菜单 业务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysMenuService\r\n{\r\n    /**\r\n     * 根据用户ID查询菜单\r\n     * \r\n     * @param user 用户信息\r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenusByUser(SysUser user);\r\n\r\n    /**\r\n     * 查询系统菜单列表\r\n     * \r\n     * @param menu 菜单信息\r\n     * @param userId 用户ID\r\n     * @return 菜单列表\r\n     */\r\n    public List<SysMenu> selectMenuList(SysMenu menu, Long userId);\r\n\r\n    /**\r\n     * 查询菜单集合\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 所有菜单信息\r\n     */\r\n    public List<SysMenu> selectMenuAll(Long userId);\r\n\r\n    /**\r\n     * 根据用户ID查询权限\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 权限列表\r\n     */\r\n    public Set<String> selectPermsByUserId(Long userId);\r\n\r\n    /**\r\n     * 根据角色ID查询权限\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 权限列表\r\n     */\r\n    public Set<String> selectPermsByRoleId(Long roleId);\r\n\r\n    /**\r\n     * 根据角色ID查询菜单\r\n     * \r\n     * @param role 角色对象\r\n     * @param userId 用户ID\r\n     * @return 菜单列表\r\n     */\r\n    public List<Ztree> roleMenuTreeData(SysRole role, Long userId);\r\n\r\n    /**\r\n     * 查询所有菜单信息\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 菜单列表\r\n     */\r\n    public List<Ztree> menuTreeData(Long userId);\r\n\r\n    /**\r\n     * 查询系统所有权限\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 权限列表\r\n     */\r\n    public Map<String, String> selectPermsAll(Long userId);\r\n\r\n    /**\r\n     * 删除菜单管理信息\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 结果\r\n     */\r\n    public int deleteMenuById(Long menuId);\r\n\r\n    /**\r\n     * 根据菜单ID查询信息\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 菜单信息\r\n     */\r\n    public SysMenu selectMenuById(Long menuId);\r\n\r\n    /**\r\n     * 查询菜单数量\r\n     * \r\n     * @param parentId 菜单父ID\r\n     * @return 结果\r\n     */\r\n    public int selectCountMenuByParentId(Long parentId);\r\n\r\n    /**\r\n     * 查询菜单使用数量\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 结果\r\n     */\r\n    public int selectCountRoleMenuByMenuId(Long menuId);\r\n\r\n    /**\r\n     * 新增保存菜单信息\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    public int insertMenu(SysMenu menu);\r\n\r\n    /**\r\n     * 修改保存菜单信息\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    public int updateMenu(SysMenu menu);\r\n\r\n    /**\r\n     * 保存菜单排序\r\n     * \r\n     * @param menuIds 菜单ID\r\n     * @param orderNums 排序ID\r\n     */\r\n    public void updateMenuSort(String[] menuIds, String[] orderNums);\r\n\r\n    /**\r\n     * 校验菜单名称是否唯一\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkMenuNameUnique(SysMenu menu);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeReadService.java",
    "content": "package com.ruoyi.system.service;\n\nimport java.util.List;\nimport com.ruoyi.system.domain.SysNotice;\n\n/**\n * 公告已读记录 服务层\n *\n * @author ruoyi\n */\npublic interface ISysNoticeReadService\n{\n    /**\n     * 标记已读（幂等，重复调用不报错）\n     *\n     * @param noticeId 公告ID\n     * @param userId   用户ID\n     */\n    public void markRead(Long noticeId, Long userId);\n\n    /**\n     * 查询某用户未读公告数量\n     *\n     * @param userId 用户ID\n     * @return 未读数量\n     */\n    public int selectUnreadCount(Long userId);\n\n    /**\n     * 查询公告列表并标记当前用户已读状态（用于首页展示）\n     *\n     * @param userId 用户ID\n     * @param limit  最多返回条数\n     * @return 带 isRead 标记的公告列表\n     */\n    public List<SysNotice> selectNoticeListWithReadStatus(Long userId, int limit);\n\n    /**\n     * 批量标记已读\n     *\n     * @param userId    用户ID\n     * @param noticeIds 公告ID数组\n     */\n    public void markReadBatch(Long userId, Long[] noticeIds);\n\n    /**\n     * 删除公告时清理对应已读记录\n     *\n     * @param ids 公告ID字符串（逗号分隔）\n     */\n    public void deleteByNoticeIds(String ids);\n}\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysNotice;\r\n\r\n/**\r\n * 公告 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysNoticeService\r\n{\r\n    /**\r\n     * 查询公告信息\r\n     * \r\n     * @param noticeId 公告ID\r\n     * @return 公告信息\r\n     */\r\n    public SysNotice selectNoticeById(Long noticeId);\r\n\r\n    /**\r\n     * 查询公告列表\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 公告集合\r\n     */\r\n    public List<SysNotice> selectNoticeList(SysNotice notice);\r\n\r\n    /**\r\n     * 新增公告\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 结果\r\n     */\r\n    public int insertNotice(SysNotice notice);\r\n\r\n    /**\r\n     * 修改公告\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 结果\r\n     */\r\n    public int updateNotice(SysNotice notice);\r\n\r\n    /**\r\n     * 删除公告信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteNoticeByIds(String ids);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysOperLog;\r\n\r\n/**\r\n * 操作日志 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysOperLogService\r\n{\r\n    /**\r\n     * 新增操作日志\r\n     * \r\n     * @param operLog 操作日志对象\r\n     */\r\n    public void insertOperlog(SysOperLog operLog);\r\n\r\n    /**\r\n     * 查询系统操作日志集合\r\n     * \r\n     * @param operLog 操作日志对象\r\n     * @return 操作日志集合\r\n     */\r\n    public List<SysOperLog> selectOperLogList(SysOperLog operLog);\r\n\r\n    /**\r\n     * 批量删除系统操作日志\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return 结果\r\n     */\r\n    public int deleteOperLogByIds(String ids);\r\n\r\n    /**\r\n     * 查询操作日志详细\r\n     * \r\n     * @param operId 操作ID\r\n     * @return 操作日志对象\r\n     */\r\n    public SysOperLog selectOperLogById(Long operId);\r\n\r\n    /**\r\n     * 清空操作日志\r\n     */\r\n    public void cleanOperLog();\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysPost;\r\n\r\n/**\r\n * 岗位信息 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysPostService\r\n{\r\n    /**\r\n     * 查询岗位信息集合\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 岗位信息集合\r\n     */\r\n    public List<SysPost> selectPostList(SysPost post);\r\n\r\n    /**\r\n     * 查询所有岗位\r\n     * \r\n     * @return 岗位列表\r\n     */\r\n    public List<SysPost> selectPostAll();\r\n\r\n    /**\r\n     * 根据用户ID查询岗位\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 岗位列表\r\n     */\r\n    public List<SysPost> selectPostsByUserId(Long userId);\r\n\r\n    /**\r\n     * 通过岗位ID查询岗位信息\r\n     * \r\n     * @param postId 岗位ID\r\n     * @return 角色对象信息\r\n     */\r\n    public SysPost selectPostById(Long postId);\r\n\r\n    /**\r\n     * 批量删除岗位信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    public int deletePostByIds(String ids);\r\n\r\n    /**\r\n     * 新增保存岗位信息\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    public int insertPost(SysPost post);\r\n\r\n    /**\r\n     * 修改保存岗位信息\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    public int updatePost(SysPost post);\r\n\r\n    /**\r\n     * 通过岗位ID查询岗位使用数量\r\n     * \r\n     * @param postId 岗位ID\r\n     * @return 结果\r\n     */\r\n    public int countUserPostById(Long postId);\r\n\r\n    /**\r\n     * 校验岗位名称\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkPostNameUnique(SysPost post);\r\n\r\n    /**\r\n     * 校验岗位编码\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkPostCodeUnique(SysPost post);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.List;\r\nimport java.util.Set;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.system.domain.SysUserRole;\r\n\r\n/**\r\n * 角色业务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysRoleService\r\n{\r\n    /**\r\n     * 根据条件分页查询角色数据\r\n     * \r\n     * @param role 角色信息\r\n     * @return 角色数据集合信息\r\n     */\r\n    public List<SysRole> selectRoleList(SysRole role);\r\n\r\n    /**\r\n     * 根据用户ID查询角色列表\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 权限列表\r\n     */\r\n    public Set<String> selectRoleKeys(Long userId);\r\n\r\n    /**\r\n     * 根据用户ID查询角色权限\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 角色列表\r\n     */\r\n    public List<SysRole> selectRolesByUserId(Long userId);\r\n\r\n    /**\r\n     * 查询所有角色\r\n     * \r\n     * @return 角色列表\r\n     */\r\n    public List<SysRole> selectRoleAll();\r\n\r\n    /**\r\n     * 通过角色ID查询角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 角色对象信息\r\n     */\r\n    public SysRole selectRoleById(Long roleId);\r\n\r\n    /**\r\n     * 通过角色ID删除角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    public boolean deleteRoleById(Long roleId);\r\n\r\n    /**\r\n     * 批量删除角色用户信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     * @throws Exception 异常\r\n     */\r\n    public int deleteRoleByIds(String ids);\r\n\r\n    /**\r\n     * 新增保存角色信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public int insertRole(SysRole role);\r\n\r\n    /**\r\n     * 修改保存角色信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public int updateRole(SysRole role);\r\n\r\n    /**\r\n     * 修改数据权限信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public int authDataScope(SysRole role);\r\n\r\n    /**\r\n     * 校验角色名称是否唯一\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkRoleNameUnique(SysRole role);\r\n\r\n    /**\r\n     * 校验角色权限是否唯一\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkRoleKeyUnique(SysRole role);\r\n\r\n    /**\r\n     * 校验角色是否允许操作\r\n     * \r\n     * @param role 角色信息\r\n     */\r\n    public void checkRoleAllowed(SysRole role);\r\n\r\n    /**\r\n     * 校验角色是否有数据权限\r\n     * \r\n     * @param roleIds 角色id\r\n     */\r\n    public void checkRoleDataScope(Long... roleIds);\r\n\r\n    /**\r\n     * 通过角色ID查询角色使用数量\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    public int countUserRoleByRoleId(Long roleId);\r\n\r\n    /**\r\n     * 角色状态修改\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    public int changeStatus(SysRole role);\r\n\r\n    /**\r\n     * 取消授权用户角色\r\n     * \r\n     * @param userRole 用户和角色关联信息\r\n     * @return 结果\r\n     */\r\n    public int deleteAuthUser(SysUserRole userRole);\r\n\r\n    /**\r\n     * 批量取消授权用户角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @param userIds 需要删除的用户数据ID\r\n     * @return 结果\r\n     */\r\n    public int deleteAuthUsers(Long roleId, String userIds);\r\n\r\n    /**\r\n     * 批量选择授权用户角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @param userIds 需要删除的用户数据ID\r\n     * @return 结果\r\n     */\r\n    public int insertAuthUsers(Long roleId, String userIds);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport com.ruoyi.system.domain.SysUserOnline;\r\n\r\n/**\r\n * 在线用户 服务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysUserOnlineService\r\n{\r\n    /**\r\n     * 通过会话序号查询信息\r\n     * \r\n     * @param sessionId 会话ID\r\n     * @return 在线用户信息\r\n     */\r\n    public SysUserOnline selectOnlineById(String sessionId);\r\n\r\n    /**\r\n     * 通过会话序号删除信息\r\n     * \r\n     * @param sessionId 会话ID\r\n     * @return 在线用户信息\r\n     */\r\n    public void deleteOnlineById(String sessionId);\r\n\r\n    /**\r\n     * 通过会话序号删除信息\r\n     * \r\n     * @param sessions 会话ID集合\r\n     * @return 在线用户信息\r\n     */\r\n    public void batchDeleteOnline(List<String> sessions);\r\n\r\n    /**\r\n     * 保存会话信息\r\n     * \r\n     * @param online 会话信息\r\n     */\r\n    public void saveOnline(SysUserOnline online);\r\n\r\n    /**\r\n     * 查询会话集合\r\n     * \r\n     * @param userOnline 分页参数\r\n     * @return 会话集合\r\n     */\r\n    public List<SysUserOnline> selectUserOnlineList(SysUserOnline userOnline);\r\n\r\n    /**\r\n     * 强退用户\r\n     * \r\n     * @param sessionId 会话ID\r\n     */\r\n    public void forceLogout(String sessionId);\r\n\r\n    /**\r\n     * 清理用户缓存\r\n     * \r\n     * @param loginName 登录名称\r\n     * @param sessionId 会话ID\r\n     */\r\n    public void removeUserCache(String loginName, String sessionId);\r\n\r\n    /**\r\n     * 查询会话集合\r\n     * \r\n     * @param expiredDate 有效期\r\n     * @return 会话集合\r\n     */\r\n    public List<SysUserOnline> selectOnlineByExpired(Date expiredDate);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java",
    "content": "package com.ruoyi.system.service;\r\n\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.system.domain.SysUserRole;\r\n\r\n/**\r\n * 用户 业务层\r\n * \r\n * @author ruoyi\r\n */\r\npublic interface ISysUserService\r\n{\r\n    /**\r\n     * 根据条件分页查询用户列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    public List<SysUser> selectUserList(SysUser user);\r\n\r\n    /**\r\n     * 根据条件分页查询已分配用户角色列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    public List<SysUser> selectAllocatedList(SysUser user);\r\n\r\n    /**\r\n     * 根据条件分页查询未分配用户角色列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    public List<SysUser> selectUnallocatedList(SysUser user);\r\n\r\n    /**\r\n     * 通过用户名查询用户\r\n     * \r\n     * @param userName 用户名\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserByLoginName(String userName);\r\n\r\n    /**\r\n     * 通过手机号码查询用户\r\n     * \r\n     * @param phoneNumber 手机号码\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserByPhoneNumber(String phoneNumber);\r\n\r\n    /**\r\n     * 通过邮箱查询用户\r\n     * \r\n     * @param email 邮箱\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserByEmail(String email);\r\n\r\n    /**\r\n     * 通过用户ID查询用户\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 用户对象信息\r\n     */\r\n    public SysUser selectUserById(Long userId);\r\n\r\n    /**\r\n     * 通过用户ID查询用户和角色关联\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 用户和角色关联列表\r\n     */\r\n    public List<SysUserRole> selectUserRoleByUserId(Long userId);\r\n\r\n    /**\r\n     * 通过用户ID删除用户\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    public int deleteUserById(Long userId);\r\n\r\n    /**\r\n     * 批量删除用户信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     * @throws Exception 异常\r\n     */\r\n    public int deleteUserByIds(String ids);\r\n\r\n    /**\r\n     * 保存用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public int insertUser(SysUser user);\r\n\r\n    /**\r\n     * 注册用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public boolean registerUser(SysUser user);\r\n\r\n    /**\r\n     * 保存用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public int updateUser(SysUser user);\r\n\r\n    /**\r\n     * 修改用户详细信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public int updateUserInfo(SysUser user);\r\n\r\n    /**\r\n     * 修改用户头像\r\n     * \r\n     * @param userId 用户ID\r\n     * @param avatar 头像地址\r\n     * @return 结果\r\n     */\r\n    public boolean updateUserAvatar(Long userId, String avatar);\r\n\r\n    /**\r\n     * 更新用户登录信息（IP和登录时间）\r\n     * \r\n     * @param userId 用户ID\r\n     * @param loginIp 登录IP地址\r\n     * @param loginDate 登录时间\r\n     * @return 结果\r\n     */\r\n    public void updateLoginInfo(Long userId, String loginIp, Date loginDate);\r\n\r\n    /**\r\n     * 用户授权角色\r\n     * \r\n     * @param userId 用户ID\r\n     * @param roleIds 角色组\r\n     */\r\n    public void insertUserAuth(Long userId, Long[] roleIds);\r\n\r\n    /**\r\n     * 修改用户密码信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public int resetUserPwd(SysUser user);\r\n\r\n    /**\r\n     * 校验用户名称是否唯一\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkLoginNameUnique(SysUser user);\r\n\r\n    /**\r\n     * 校验手机号码是否唯一\r\n     *\r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkPhoneUnique(SysUser user);\r\n\r\n    /**\r\n     * 校验email是否唯一\r\n     *\r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public boolean checkEmailUnique(SysUser user);\r\n\r\n    /**\r\n     * 校验用户是否允许操作\r\n     * \r\n     * @param user 用户信息\r\n     */\r\n    public void checkUserAllowed(SysUser user);\r\n\r\n    /**\r\n     * 校验用户是否有数据权限\r\n     * \r\n     * @param userId 用户id\r\n     */\r\n    public void checkUserDataScope(Long userId);\r\n\r\n    /**\r\n     * 根据用户ID查询用户所属角色组\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    public String selectUserRoleGroup(Long userId);\r\n\r\n    /**\r\n     * 根据用户ID查询用户所属岗位组\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    public String selectUserPostGroup(Long userId);\r\n\r\n    /**\r\n     * 导入用户数据\r\n     * \r\n     * @param userList 用户数据列表\r\n     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据\r\n     * @param operName 操作用户\r\n     * @return 结果\r\n     */\r\n    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);\r\n\r\n    /**\r\n     * 用户状态修改\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    public int changeStatus(SysUser user);\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.List;\r\nimport jakarta.annotation.PostConstruct;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.constant.Constants;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.CacheUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.system.domain.SysConfig;\r\nimport com.ruoyi.system.mapper.SysConfigMapper;\r\nimport com.ruoyi.system.service.ISysConfigService;\r\n\r\n/**\r\n * 参数配置 服务层实现\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysConfigServiceImpl implements ISysConfigService\r\n{\r\n    @Autowired\r\n    private SysConfigMapper configMapper;\r\n\r\n    /**\r\n     * 项目启动时，初始化参数到缓存\r\n     */\r\n    @PostConstruct\r\n    public void init()\r\n    {\r\n        loadingConfigCache();\r\n    }\r\n\r\n    /**\r\n     * 查询参数配置信息\r\n     * \r\n     * @param configId 参数配置ID\r\n     * @return 参数配置信息\r\n     */\r\n    @Override\r\n    public SysConfig selectConfigById(Long configId)\r\n    {\r\n        SysConfig config = new SysConfig();\r\n        config.setConfigId(configId);\r\n        return configMapper.selectConfig(config);\r\n    }\r\n\r\n    /**\r\n     * 根据键名查询参数配置信息\r\n     * \r\n     * @param configKey 参数key\r\n     * @return 参数键值\r\n     */\r\n    @Override\r\n    public String selectConfigByKey(String configKey)\r\n    {\r\n        String configValue = Convert.toStr(CacheUtils.get(getCacheName(), getCacheKey(configKey)));\r\n        if (StringUtils.isNotEmpty(configValue))\r\n        {\r\n            return configValue;\r\n        }\r\n        SysConfig config = new SysConfig();\r\n        config.setConfigKey(configKey);\r\n        SysConfig retConfig = configMapper.selectConfig(config);\r\n        if (StringUtils.isNotNull(retConfig))\r\n        {\r\n            CacheUtils.put(getCacheName(), getCacheKey(configKey), retConfig.getConfigValue());\r\n            return retConfig.getConfigValue();\r\n        }\r\n        return StringUtils.EMPTY;\r\n    }\r\n\r\n    /**\r\n     * 查询参数配置列表\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 参数配置集合\r\n     */\r\n    @Override\r\n    public List<SysConfig> selectConfigList(SysConfig config)\r\n    {\r\n        return configMapper.selectConfigList(config);\r\n    }\r\n\r\n    /**\r\n     * 新增参数配置\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertConfig(SysConfig config)\r\n    {\r\n        int row = configMapper.insertConfig(config);\r\n        if (row > 0)\r\n        {\r\n            CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue());\r\n        }\r\n        return row;\r\n    }\r\n\r\n    /**\r\n     * 修改参数配置\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int updateConfig(SysConfig config)\r\n    {\r\n        SysConfig temp = configMapper.selectConfigById(config.getConfigId());\r\n        if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey()))\r\n        {\r\n            CacheUtils.remove(getCacheName(), getCacheKey(temp.getConfigKey()));\r\n        }\r\n\r\n        int row = configMapper.updateConfig(config);\r\n        if (row > 0)\r\n        {\r\n            CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue());\r\n        }\r\n        return row;\r\n    }\r\n\r\n    /**\r\n     * 批量删除参数配置对象\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     */\r\n    @Override\r\n    public void deleteConfigByIds(String ids)\r\n    {\r\n        Long[] configIds = Convert.toLongArray(ids);\r\n        for (Long configId : configIds)\r\n        {\r\n            SysConfig config = selectConfigById(configId);\r\n            if (StringUtils.equals(UserConstants.YES, config.getConfigType()))\r\n            {\r\n                throw new ServiceException(String.format(\"内置参数【%1$s】不能删除 \", config.getConfigKey()));\r\n            }\r\n            configMapper.deleteConfigById(configId);\r\n            CacheUtils.remove(getCacheName(), getCacheKey(config.getConfigKey()));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 加载参数缓存数据\r\n     */\r\n    @Override\r\n    public void loadingConfigCache()\r\n    {\r\n        List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig());\r\n        for (SysConfig config : configsList)\r\n        {\r\n            CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue());\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 清空参数缓存数据\r\n     */\r\n    @Override\r\n    public void clearConfigCache()\r\n    {\r\n        CacheUtils.removeAll(getCacheName());\r\n    }\r\n\r\n    /**\r\n     * 重置参数缓存数据\r\n     */\r\n    @Override\r\n    public void resetConfigCache()\r\n    {\r\n        clearConfigCache();\r\n        loadingConfigCache();\r\n    }\r\n\r\n    /**\r\n     * 校验参数键名是否唯一\r\n     * \r\n     * @param config 参数配置信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkConfigKeyUnique(SysConfig config)\r\n    {\r\n        Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId();\r\n        SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey());\r\n        if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 获取cache name\r\n     * \r\n     * @return 缓存名\r\n     */\r\n    private String getCacheName()\r\n    {\r\n        return Constants.SYS_CONFIG_CACHE;\r\n    }\r\n\r\n    /**\r\n     * 设置cache key\r\n     * \r\n     * @param configKey 参数键\r\n     * @return 缓存键key\r\n     */\r\n    private String getCacheKey(String configKey)\r\n    {\r\n        return Constants.SYS_CONFIG_KEY + configKey;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport org.apache.commons.lang3.ArrayUtils;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport org.springframework.transaction.annotation.Transactional;\r\nimport com.ruoyi.common.annotation.DataScope;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysDept;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.system.mapper.SysDeptMapper;\r\nimport com.ruoyi.system.service.ISysDeptService;\r\n\r\n/**\r\n * 部门管理 服务实现\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysDeptServiceImpl implements ISysDeptService\r\n{\r\n    @Autowired\r\n    private SysDeptMapper deptMapper;\r\n\r\n    /**\r\n     * 查询部门管理数据\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 部门信息集合\r\n     */\r\n    @Override\r\n    @DataScope(deptAlias = \"d\")\r\n    public List<SysDept> selectDeptList(SysDept dept)\r\n    {\r\n        return deptMapper.selectDeptList(dept);\r\n    }\r\n\r\n    /**\r\n     * 查询部门管理树\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 所有部门信息\r\n     */\r\n    @Override\r\n    @DataScope(deptAlias = \"d\")\r\n    public List<Ztree> selectDeptTree(SysDept dept)\r\n    {\r\n        List<SysDept> deptList = deptMapper.selectDeptList(dept);\r\n        List<Ztree> ztrees = initZtree(deptList);\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 查询部门管理树（排除下级）\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 所有部门信息\r\n     */\r\n    @Override\r\n    @DataScope(deptAlias = \"d\")\r\n    public List<Ztree> selectDeptTreeExcludeChild(SysDept dept)\r\n    {\r\n        Long excludeId = dept.getExcludeId();\r\n        List<SysDept> depts = deptMapper.selectDeptList(dept);\r\n        if (excludeId.intValue() > 0)\r\n        {\r\n            depts.removeIf(d -> d.getDeptId().intValue() == excludeId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), \",\"), excludeId + \"\"));\r\n        }\r\n        List<Ztree> ztrees = initZtree(depts);\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 根据角色ID查询部门（数据权限）\r\n     *\r\n     * @param role 角色对象\r\n     * @return 部门列表（数据权限）\r\n     */\r\n    @Override\r\n    public List<Ztree> roleDeptTreeData(SysRole role)\r\n    {\r\n        Long roleId = role.getRoleId();\r\n        List<Ztree> ztrees = new ArrayList<Ztree>();\r\n        List<SysDept> deptList = SpringUtils.getAopProxy(this).selectDeptList(new SysDept());\r\n        if (StringUtils.isNotNull(roleId))\r\n        {\r\n            List<String> roleDeptList = deptMapper.selectRoleDeptTree(roleId);\r\n            ztrees = initZtree(deptList, roleDeptList);\r\n        }\r\n        else\r\n        {\r\n            ztrees = initZtree(deptList);\r\n        }\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 对象转部门树\r\n     *\r\n     * @param deptList 部门列表\r\n     * @return 树结构列表\r\n     */\r\n    public List<Ztree> initZtree(List<SysDept> deptList)\r\n    {\r\n        return initZtree(deptList, null);\r\n    }\r\n\r\n    /**\r\n     * 对象转部门树\r\n     *\r\n     * @param deptList 部门列表\r\n     * @param roleDeptList 角色已存在菜单列表\r\n     * @return 树结构列表\r\n     */\r\n    public List<Ztree> initZtree(List<SysDept> deptList, List<String> roleDeptList)\r\n    {\r\n\r\n        List<Ztree> ztrees = new ArrayList<Ztree>();\r\n        boolean isCheck = StringUtils.isNotNull(roleDeptList);\r\n        for (SysDept dept : deptList)\r\n        {\r\n            if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()))\r\n            {\r\n                Ztree ztree = new Ztree();\r\n                ztree.setId(dept.getDeptId());\r\n                ztree.setpId(dept.getParentId());\r\n                ztree.setName(dept.getDeptName());\r\n                ztree.setTitle(dept.getDeptName());\r\n                if (isCheck)\r\n                {\r\n                    ztree.setChecked(roleDeptList.contains(dept.getDeptId() + dept.getDeptName()));\r\n                }\r\n                ztrees.add(ztree);\r\n            }\r\n        }\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 根据父部门ID查询下级部门数量\r\n     * \r\n     * @param parentId 部门ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int selectDeptCount(Long parentId)\r\n    {\r\n        SysDept dept = new SysDept();\r\n        dept.setParentId(parentId);\r\n        return deptMapper.selectDeptCount(dept);\r\n    }\r\n\r\n    /**\r\n     * 查询部门是否存在用户\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 结果 true 存在 false 不存在\r\n     */\r\n    @Override\r\n    public boolean checkDeptExistUser(Long deptId)\r\n    {\r\n        int result = deptMapper.checkDeptExistUser(deptId);\r\n        return result > 0;\r\n    }\r\n\r\n    /**\r\n     * 删除部门管理信息\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deleteDeptById(Long deptId)\r\n    {\r\n        return deptMapper.deleteDeptById(deptId);\r\n    }\r\n\r\n    /**\r\n     * 新增保存部门信息\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertDept(SysDept dept)\r\n    {\r\n        SysDept info = deptMapper.selectDeptById(dept.getParentId());\r\n        // 如果父节点不为\"正常\"状态,则不允许新增子节点\r\n        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))\r\n        {\r\n            throw new ServiceException(\"部门停用，不允许新增\");\r\n        }\r\n        dept.setAncestors(info.getAncestors() + \",\" + dept.getParentId());\r\n        return deptMapper.insertDept(dept);\r\n    }\r\n\r\n    /**\r\n     * 修改保存部门信息\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int updateDept(SysDept dept)\r\n    {\r\n        SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());\r\n        SysDept oldDept = selectDeptById(dept.getDeptId());\r\n        if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept))\r\n        {\r\n            String newAncestors = newParentDept.getAncestors() + \",\" + newParentDept.getDeptId();\r\n            String oldAncestors = oldDept.getAncestors();\r\n            dept.setAncestors(newAncestors);\r\n            updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);\r\n        }\r\n        int result = deptMapper.updateDept(dept);\r\n        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())\r\n                && !StringUtils.equals(\"0\", dept.getAncestors()))\r\n        {\r\n            // 如果该部门是启用状态，则启用该部门的所有上级部门\r\n            updateParentDeptStatusNormal(dept);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * 修改该部门的父级部门状态\r\n     * \r\n     * @param dept 当前部门\r\n     */\r\n    private void updateParentDeptStatusNormal(SysDept dept)\r\n    {\r\n        String ancestors = dept.getAncestors();\r\n        Long[] deptIds = Convert.toLongArray(ancestors);\r\n        deptMapper.updateDeptStatusNormal(deptIds);\r\n    }\r\n\r\n    /**\r\n     * 修改子元素关系\r\n     * \r\n     * @param deptId 被修改的部门ID\r\n     * @param newAncestors 新的父ID集合\r\n     * @param oldAncestors 旧的父ID集合\r\n     */\r\n    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)\r\n    {\r\n        List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);\r\n        for (SysDept child : children)\r\n        {\r\n            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));\r\n        }\r\n        if (children.size() > 0)\r\n        {\r\n            deptMapper.updateDeptChildren(children);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 根据部门ID查询信息\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 部门信息\r\n     */\r\n    @Override\r\n    public SysDept selectDeptById(Long deptId)\r\n    {\r\n        return deptMapper.selectDeptById(deptId);\r\n    }\r\n\r\n    /**\r\n     * 根据ID查询所有子部门（正常状态）\r\n     * \r\n     * @param deptId 部门ID\r\n     * @return 子部门数\r\n     */\r\n    @Override\r\n    public int selectNormalChildrenDeptById(Long deptId)\r\n    {\r\n        return deptMapper.selectNormalChildrenDeptById(deptId);\r\n    }\r\n\r\n    /**\r\n     * 校验部门名称是否唯一\r\n     * \r\n     * @param dept 部门信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkDeptNameUnique(SysDept dept)\r\n    {\r\n        Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();\r\n        SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());\r\n        if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 校验部门是否有数据权限\r\n     * \r\n     * @param deptId 部门id\r\n     */\r\n    @Override\r\n    public void checkDeptDataScope(Long deptId)\r\n    {\r\n        if (!ShiroUtils.isAdmin() && StringUtils.isNotNull(deptId))\r\n        {\r\n            SysDept dept = new SysDept();\r\n            dept.setDeptId(deptId);\r\n            List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);\r\n            if (StringUtils.isEmpty(depts))\r\n            {\r\n                throw new ServiceException(\"没有权限访问部门数据！\");\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 保存部门排序\r\n     *\r\n     * @param deptIds 部门ID数组\r\n     * @param orderNums 排序数组\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public void updateDeptSort(String[] deptIds, String[] orderNums)\r\n    {\r\n        try\r\n        {\r\n            for (int i = 0; i < deptIds.length; i++)\r\n            {\r\n                SysDept dept = new SysDept();\r\n                dept.setDeptId(Convert.toLong(deptIds[i]));\r\n                dept.setOrderNum(Convert.toInt(orderNums[i]));\r\n                deptMapper.updateDeptSort(dept);\r\n            }\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new ServiceException(\"保存排序异常，请联系管理员\");\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.List;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.core.domain.entity.SysDictData;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.utils.DictUtils;\r\nimport com.ruoyi.system.mapper.SysDictDataMapper;\r\nimport com.ruoyi.system.service.ISysDictDataService;\r\n\r\n/**\r\n * 字典 业务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysDictDataServiceImpl implements ISysDictDataService\r\n{\r\n    @Autowired\r\n    private SysDictDataMapper dictDataMapper;\r\n\r\n    /**\r\n     * 根据条件分页查询字典数据\r\n     * \r\n     * @param dictData 字典数据信息\r\n     * @return 字典数据集合信息\r\n     */\r\n    @Override\r\n    public List<SysDictData> selectDictDataList(SysDictData dictData)\r\n    {\r\n        return dictDataMapper.selectDictDataList(dictData);\r\n    }\r\n\r\n    /**\r\n     * 根据字典类型和字典键值查询字典数据信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @param dictValue 字典键值\r\n     * @return 字典标签\r\n     */\r\n    @Override\r\n    public String selectDictLabel(String dictType, String dictValue)\r\n    {\r\n        return dictDataMapper.selectDictLabel(dictType, dictValue);\r\n    }\r\n\r\n    /**\r\n     * 根据字典数据ID查询信息\r\n     * \r\n     * @param dictCode 字典数据ID\r\n     * @return 字典数据\r\n     */\r\n    @Override\r\n    public SysDictData selectDictDataById(Long dictCode)\r\n    {\r\n        return dictDataMapper.selectDictDataById(dictCode);\r\n    }\r\n\r\n    /**\r\n     * 批量删除字典数据\r\n     * \r\n     * @param ids 需要删除的数据\r\n     */\r\n    @Override\r\n    public void deleteDictDataByIds(String ids)\r\n    {\r\n        Long[] dictCodes = Convert.toLongArray(ids);\r\n        for (Long dictCode : dictCodes)\r\n        {\r\n            SysDictData data = selectDictDataById(dictCode);\r\n            dictDataMapper.deleteDictDataById(dictCode);\r\n            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());\r\n            DictUtils.setDictCache(data.getDictType(), dictDatas);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 新增保存字典数据信息\r\n     * \r\n     * @param data 字典数据信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertDictData(SysDictData data)\r\n    {\r\n        int row = dictDataMapper.insertDictData(data);\r\n        if (row > 0)\r\n        {\r\n            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());\r\n            DictUtils.setDictCache(data.getDictType(), dictDatas);\r\n        }\r\n        return row;\r\n    }\r\n\r\n    /**\r\n     * 修改保存字典数据信息\r\n     * \r\n     * @param data 字典数据信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int updateDictData(SysDictData data)\r\n    {\r\n        int row = dictDataMapper.updateDictData(data);\r\n        if (row > 0)\r\n        {\r\n            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());\r\n            DictUtils.setDictCache(data.getDictType(), dictDatas);\r\n        }\r\n        return row;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Comparator;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\nimport jakarta.annotation.PostConstruct;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport org.springframework.transaction.annotation.Transactional;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysDictData;\r\nimport com.ruoyi.common.core.domain.entity.SysDictType;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.DictUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.system.mapper.SysDictDataMapper;\r\nimport com.ruoyi.system.mapper.SysDictTypeMapper;\r\nimport com.ruoyi.system.service.ISysDictTypeService;\r\n\r\n/**\r\n * 字典 业务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysDictTypeServiceImpl implements ISysDictTypeService\r\n{\r\n    @Autowired\r\n    private SysDictTypeMapper dictTypeMapper;\r\n\r\n    @Autowired\r\n    private SysDictDataMapper dictDataMapper;\r\n\r\n    /**\r\n     * 项目启动时，初始化字典到缓存\r\n     */\r\n    @PostConstruct\r\n    public void init()\r\n    {\r\n        loadingDictCache();\r\n    }\r\n\r\n    /**\r\n     * 根据条件分页查询字典类型\r\n     * \r\n     * @param dictType 字典类型信息\r\n     * @return 字典类型集合信息\r\n     */\r\n    @Override\r\n    public List<SysDictType> selectDictTypeList(SysDictType dictType)\r\n    {\r\n        return dictTypeMapper.selectDictTypeList(dictType);\r\n    }\r\n\r\n    /**\r\n     * 根据所有字典类型\r\n     * \r\n     * @return 字典类型集合信息\r\n     */\r\n    @Override\r\n    public List<SysDictType> selectDictTypeAll()\r\n    {\r\n        return dictTypeMapper.selectDictTypeAll();\r\n    }\r\n\r\n    /**\r\n     * 根据字典类型查询字典数据\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 字典数据集合信息\r\n     */\r\n    @Override\r\n    public List<SysDictData> selectDictDataByType(String dictType)\r\n    {\r\n        List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);\r\n        if (StringUtils.isNotEmpty(dictDatas))\r\n        {\r\n            return dictDatas;\r\n        }\r\n        dictDatas = dictDataMapper.selectDictDataByType(dictType);\r\n        if (StringUtils.isNotEmpty(dictDatas))\r\n        {\r\n            DictUtils.setDictCache(dictType, dictDatas);\r\n            return dictDatas;\r\n        }\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * 根据字典类型ID查询信息\r\n     * \r\n     * @param dictId 字典类型ID\r\n     * @return 字典类型\r\n     */\r\n    @Override\r\n    public SysDictType selectDictTypeById(Long dictId)\r\n    {\r\n        return dictTypeMapper.selectDictTypeById(dictId);\r\n    }\r\n\r\n    /**\r\n     * 根据字典类型查询信息\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 字典类型\r\n     */\r\n    @Override\r\n    public SysDictType selectDictTypeByType(String dictType)\r\n    {\r\n        return dictTypeMapper.selectDictTypeByType(dictType);\r\n    }\r\n\r\n    /**\r\n     * 批量删除字典类型\r\n     * \r\n     * @param ids 需要删除的数据\r\n     */\r\n    @Override\r\n    public void deleteDictTypeByIds(String ids)\r\n    {\r\n        Long[] dictIds = Convert.toLongArray(ids);\r\n        for (Long dictId : dictIds)\r\n        {\r\n            SysDictType dictType = selectDictTypeById(dictId);\r\n            if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0)\r\n            {\r\n                throw new ServiceException(String.format(\"%1$s已分配,不能删除\", dictType.getDictName()));\r\n            }\r\n            dictTypeMapper.deleteDictTypeById(dictId);\r\n            DictUtils.removeDictCache(dictType.getDictType());\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 加载字典缓存数据\r\n     */\r\n    @Override\r\n    public void loadingDictCache()\r\n    {\r\n        SysDictData dictData = new SysDictData();\r\n        dictData.setStatus(\"0\");\r\n        Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType));\r\n        for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet())\r\n        {\r\n            DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 清空字典缓存数据\r\n     */\r\n    @Override\r\n    public void clearDictCache()\r\n    {\r\n        DictUtils.clearDictCache();\r\n    }\r\n\r\n    /**\r\n     * 重置字典缓存数据\r\n     */\r\n    @Override\r\n    public void resetDictCache()\r\n    {\r\n        clearDictCache();\r\n        loadingDictCache();\r\n    }\r\n\r\n    /**\r\n     * 新增保存字典类型信息\r\n     * \r\n     * @param dict 字典类型信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertDictType(SysDictType dict)\r\n    {\r\n        int row = dictTypeMapper.insertDictType(dict);\r\n        if (row > 0)\r\n        {\r\n            DictUtils.setDictCache(dict.getDictType(), null);\r\n        }\r\n        return row;\r\n    }\r\n\r\n    /**\r\n     * 修改保存字典类型信息\r\n     * \r\n     * @param dict 字典类型信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int updateDictType(SysDictType dict)\r\n    {\r\n        SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId());\r\n        dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType());\r\n        int row = dictTypeMapper.updateDictType(dict);\r\n        if (row > 0)\r\n        {\r\n            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType());\r\n            DictUtils.setDictCache(dict.getDictType(), dictDatas);\r\n        }\r\n        return row;\r\n    }\r\n\r\n    /**\r\n     * 校验字典类型称是否唯一\r\n     * \r\n     * @param dict 字典类型\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkDictTypeUnique(SysDictType dict)\r\n    {\r\n        Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();\r\n        SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType());\r\n        if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 查询字典类型树\r\n     * \r\n     * @param dictType 字典类型\r\n     * @return 所有字典类型\r\n     */\r\n    @Override\r\n    public List<Ztree> selectDictTree(SysDictType dictType)\r\n    {\r\n        List<Ztree> ztrees = new ArrayList<Ztree>();\r\n        List<SysDictType> dictList = dictTypeMapper.selectDictTypeList(dictType);\r\n        for (SysDictType dict : dictList)\r\n        {\r\n            if (UserConstants.DICT_NORMAL.equals(dict.getStatus()))\r\n            {\r\n                Ztree ztree = new Ztree();\r\n                ztree.setId(dict.getDictId());\r\n                ztree.setName(transDictName(dict));\r\n                ztree.setTitle(dict.getDictType());\r\n                ztrees.add(ztree);\r\n            }\r\n        }\r\n        return ztrees;\r\n    }\r\n\r\n    public String transDictName(SysDictType dictType)\r\n    {\r\n        StringBuffer sb = new StringBuffer();\r\n        sb.append(\"(\" + dictType.getDictName() + \")\");\r\n        sb.append(\"&nbsp;&nbsp;&nbsp;\" + dictType.getDictType());\r\n        return sb.toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.List;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.system.domain.SysLogininfor;\r\nimport com.ruoyi.system.mapper.SysLogininforMapper;\r\nimport com.ruoyi.system.service.ISysLogininforService;\r\n\r\n/**\r\n * 系统访问日志情况信息 服务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysLogininforServiceImpl implements ISysLogininforService\r\n{\r\n\r\n    @Autowired\r\n    private SysLogininforMapper logininforMapper;\r\n\r\n    /**\r\n     * 新增系统登录日志\r\n     * \r\n     * @param logininfor 访问日志对象\r\n     */\r\n    @Override\r\n    public void insertLogininfor(SysLogininfor logininfor)\r\n    {\r\n        logininforMapper.insertLogininfor(logininfor);\r\n    }\r\n\r\n    /**\r\n     * 查询系统登录日志集合\r\n     * \r\n     * @param logininfor 访问日志对象\r\n     * @return 登录记录集合\r\n     */\r\n    @Override\r\n    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor)\r\n    {\r\n        return logininforMapper.selectLogininforList(logininfor);\r\n    }\r\n\r\n    /**\r\n     * 批量删除系统登录日志\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deleteLogininforByIds(String ids)\r\n    {\r\n        return logininforMapper.deleteLogininforByIds(Convert.toStrArray(ids));\r\n    }\r\n\r\n    /**\r\n     * 清空系统登录日志\r\n     */\r\n    @Override\r\n    public void cleanLogininfor()\r\n    {\r\n        logininforMapper.cleanLogininfor();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.text.MessageFormat;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.HashSet;\r\nimport java.util.Iterator;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.LinkedList;\r\nimport java.util.List;\r\nimport java.util.Set;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport org.springframework.transaction.annotation.Transactional;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.Ztree;\r\nimport com.ruoyi.common.core.domain.entity.SysMenu;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.system.mapper.SysMenuMapper;\r\nimport com.ruoyi.system.mapper.SysRoleMenuMapper;\r\nimport com.ruoyi.system.service.ISysMenuService;\r\n\r\n/**\r\n * 菜单 业务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysMenuServiceImpl implements ISysMenuService\r\n{\r\n    public static final String PREMISSION_STRING = \"perms[\\\"{0}\\\"]\";\r\n\r\n    @Autowired\r\n    private SysMenuMapper menuMapper;\r\n\r\n    @Autowired\r\n    private SysRoleMenuMapper roleMenuMapper;\r\n\r\n    /**\r\n     * 根据用户查询菜单\r\n     * \r\n     * @param user 用户信息\r\n     * @return 菜单列表\r\n     */\r\n    @Override\r\n    public List<SysMenu> selectMenusByUser(SysUser user)\r\n    {\r\n        List<SysMenu> menus = new LinkedList<SysMenu>();\r\n        // 管理员显示所有菜单信息\r\n        if (user.isAdmin())\r\n        {\r\n            menus = menuMapper.selectMenuNormalAll();\r\n        }\r\n        else\r\n        {\r\n            menus = menuMapper.selectMenusByUserId(user.getUserId());\r\n        }\r\n        return getChildPerms(menus, 0);\r\n    }\r\n\r\n    /**\r\n     * 查询菜单集合\r\n     * \r\n     * @return 所有菜单信息\r\n     */\r\n    @Override\r\n    public List<SysMenu> selectMenuList(SysMenu menu, Long userId)\r\n    {\r\n        List<SysMenu> menuList = null;\r\n        if (ShiroUtils.isAdmin(userId))\r\n        {\r\n            menuList = menuMapper.selectMenuList(menu);\r\n        }\r\n        else\r\n        {\r\n            menu.getParams().put(\"userId\", userId);\r\n            menuList = menuMapper.selectMenuListByUserId(menu);\r\n        }\r\n        return menuList;\r\n    }\r\n\r\n    /**\r\n     * 查询菜单集合\r\n     * \r\n     * @return 所有菜单信息\r\n     */\r\n    @Override\r\n    public List<SysMenu> selectMenuAll(Long userId)\r\n    {\r\n        List<SysMenu> menuList = null;\r\n        if (ShiroUtils.isAdmin(userId))\r\n        {\r\n            menuList = menuMapper.selectMenuAll();\r\n        }\r\n        else\r\n        {\r\n            menuList = menuMapper.selectMenuAllByUserId(userId);\r\n        }\r\n        return menuList;\r\n    }\r\n\r\n    /**\r\n     * 根据用户ID查询权限\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 权限列表\r\n     */\r\n    @Override\r\n    public Set<String> selectPermsByUserId(Long userId)\r\n    {\r\n        List<String> perms = menuMapper.selectPermsByUserId(userId);\r\n        Set<String> permsSet = new HashSet<>();\r\n        for (String perm : perms)\r\n        {\r\n            if (StringUtils.isNotEmpty(perm))\r\n            {\r\n                permsSet.addAll(Arrays.asList(perm.trim().split(\",\")));\r\n            }\r\n        }\r\n        return permsSet;\r\n    }\r\n\r\n    /**\r\n     * 根据角色ID查询权限\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 权限列表\r\n     */\r\n    @Override\r\n    public Set<String> selectPermsByRoleId(Long roleId)\r\n    {\r\n        List<String> perms = menuMapper.selectPermsByRoleId(roleId);\r\n        Set<String> permsSet = new HashSet<>();\r\n        for (String perm : perms)\r\n        {\r\n            if (StringUtils.isNotEmpty(perm))\r\n            {\r\n                permsSet.addAll(Arrays.asList(perm.trim().split(\",\")));\r\n            }\r\n        }\r\n        return permsSet;\r\n    }\r\n\r\n    /**\r\n     * 根据角色ID查询菜单\r\n     * \r\n     * @param role 角色对象\r\n     * @return 菜单列表\r\n     */\r\n    @Override\r\n    public List<Ztree> roleMenuTreeData(SysRole role, Long userId)\r\n    {\r\n        Long roleId = role.getRoleId();\r\n        List<Ztree> ztrees = new ArrayList<Ztree>();\r\n        List<SysMenu> menuList = selectMenuAll(userId);\r\n        if (StringUtils.isNotNull(roleId))\r\n        {\r\n            List<String> roleMenuList = menuMapper.selectMenuTree(roleId);\r\n            ztrees = initZtree(menuList, roleMenuList, true);\r\n        }\r\n        else\r\n        {\r\n            ztrees = initZtree(menuList, null, true);\r\n        }\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 查询所有菜单\r\n     * \r\n     * @return 菜单列表\r\n     */\r\n    @Override\r\n    public List<Ztree> menuTreeData(Long userId)\r\n    {\r\n        List<SysMenu> menuList = selectMenuAll(userId);\r\n        List<Ztree> ztrees = initZtree(menuList);\r\n        return ztrees;\r\n    }\r\n\r\n    /**\r\n     * 查询系统所有权限\r\n     * \r\n     * @return 权限列表\r\n     */\r\n    @Override\r\n    public LinkedHashMap<String, String> selectPermsAll(Long userId)\r\n    {\r\n        LinkedHashMap<String, String> section = new LinkedHashMap<>();\r\n        List<SysMenu> permissions = selectMenuAll(userId);\r\n        if (StringUtils.isNotEmpty(permissions))\r\n        {\r\n            for (SysMenu menu : permissions)\r\n            {\r\n                section.put(menu.getUrl(), MessageFormat.format(PREMISSION_STRING, menu.getPerms()));\r\n            }\r\n        }\r\n        return section;\r\n    }\r\n\r\n    /**\r\n     * 对象转菜单树\r\n     * \r\n     * @param menuList 菜单列表\r\n     * @return 树结构列表\r\n     */\r\n    public List<Ztree> initZtree(List<SysMenu> menuList)\r\n    {\r\n        return initZtree(menuList, null, false);\r\n    }\r\n\r\n    /**\r\n     * 对象转菜单树\r\n     * \r\n     * @param menuList 菜单列表\r\n     * @param roleMenuList 角色已存在菜单列表\r\n     * @param permsFlag 是否需要显示权限标识\r\n     * @return 树结构列表\r\n     */\r\n    public List<Ztree> initZtree(List<SysMenu> menuList, List<String> roleMenuList, boolean permsFlag)\r\n    {\r\n        List<Ztree> ztrees = new ArrayList<Ztree>();\r\n        boolean isCheck = StringUtils.isNotNull(roleMenuList);\r\n        for (SysMenu menu : menuList)\r\n        {\r\n            Ztree ztree = new Ztree();\r\n            ztree.setId(menu.getMenuId());\r\n            ztree.setpId(menu.getParentId());\r\n            ztree.setName(transMenuName(menu, permsFlag));\r\n            ztree.setTitle(menu.getMenuName());\r\n            if (isCheck)\r\n            {\r\n                ztree.setChecked(roleMenuList.contains(menu.getMenuId() + menu.getPerms()));\r\n            }\r\n            ztrees.add(ztree);\r\n        }\r\n        return ztrees;\r\n    }\r\n\r\n    public String transMenuName(SysMenu menu, boolean permsFlag)\r\n    {\r\n        StringBuffer sb = new StringBuffer();\r\n        sb.append(menu.getMenuName());\r\n        if (permsFlag)\r\n        {\r\n            sb.append(\"<font color=\\\"#888\\\">&nbsp;&nbsp;&nbsp;\" + menu.getPerms() + \"</font>\");\r\n        }\r\n        return sb.toString();\r\n    }\r\n\r\n    /**\r\n     * 删除菜单管理信息\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deleteMenuById(Long menuId)\r\n    {\r\n        return menuMapper.deleteMenuById(menuId);\r\n    }\r\n\r\n    /**\r\n     * 根据菜单ID查询信息\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 菜单信息\r\n     */\r\n    @Override\r\n    public SysMenu selectMenuById(Long menuId)\r\n    {\r\n        return menuMapper.selectMenuById(menuId);\r\n    }\r\n\r\n    /**\r\n     * 查询子菜单数量\r\n     * \r\n     * @param parentId 父级菜单ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int selectCountMenuByParentId(Long parentId)\r\n    {\r\n        return menuMapper.selectCountMenuByParentId(parentId);\r\n    }\r\n\r\n    /**\r\n     * 查询菜单使用数量\r\n     * \r\n     * @param menuId 菜单ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int selectCountRoleMenuByMenuId(Long menuId)\r\n    {\r\n        return roleMenuMapper.selectCountRoleMenuByMenuId(menuId);\r\n    }\r\n\r\n    /**\r\n     * 新增保存菜单信息\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertMenu(SysMenu menu)\r\n    {\r\n        return menuMapper.insertMenu(menu);\r\n    }\r\n\r\n    /**\r\n     * 修改保存菜单信息\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int updateMenu(SysMenu menu)\r\n    {\r\n        return menuMapper.updateMenu(menu);\r\n    }\r\n\r\n    /**\r\n     * 保存菜单排序\r\n     * \r\n     * @param menuIds 菜单ID\r\n     * @param orderNums 排序ID\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public void updateMenuSort(String[] menuIds, String[] orderNums)\r\n    {\r\n        try\r\n        {\r\n            for (int i = 0; i < menuIds.length; i++)\r\n            {\r\n                SysMenu menu = new SysMenu();\r\n                menu.setMenuId(Convert.toLong(menuIds[i]));\r\n                menu.setOrderNum(orderNums[i]);\r\n                menuMapper.updateMenuSort(menu);\r\n            }\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            throw new ServiceException(\"保存排序异常，请联系管理员\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 校验菜单名称是否唯一\r\n     * \r\n     * @param menu 菜单信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkMenuNameUnique(SysMenu menu)\r\n    {\r\n        Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();\r\n        SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId());\r\n        if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 根据父节点的ID获取所有子节点\r\n     * \r\n     * @param list 分类表\r\n     * @param parentId 传入的父节点ID\r\n     * @return String\r\n     */\r\n    public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId)\r\n    {\r\n        List<SysMenu> returnList = new ArrayList<SysMenu>();\r\n        for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)\r\n        {\r\n            SysMenu t = (SysMenu) iterator.next();\r\n            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点\r\n            if (t.getParentId() == parentId)\r\n            {\r\n                recursionFn(list, t);\r\n                returnList.add(t);\r\n            }\r\n        }\r\n        return returnList;\r\n    }\r\n\r\n    /**\r\n     * 递归列表\r\n     * \r\n     * @param list\r\n     * @param t\r\n     */\r\n    private void recursionFn(List<SysMenu> list, SysMenu t)\r\n    {\r\n        // 得到子节点列表\r\n        List<SysMenu> childList = getChildList(list, t);\r\n        t.setChildren(childList);\r\n        for (SysMenu tChild : childList)\r\n        {\r\n            if (hasChild(list, tChild))\r\n            {\r\n                recursionFn(list, tChild);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 得到子节点列表\r\n     */\r\n    private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t)\r\n    {\r\n        List<SysMenu> tlist = new ArrayList<SysMenu>();\r\n        Iterator<SysMenu> it = list.iterator();\r\n        while (it.hasNext())\r\n        {\r\n            SysMenu n = (SysMenu) it.next();\r\n            if (n.getParentId().longValue() == t.getMenuId().longValue())\r\n            {\r\n                tlist.add(n);\r\n            }\r\n        }\r\n        return tlist;\r\n    }\r\n\r\n    /**\r\n     * 判断是否有子节点\r\n     */\r\n    private boolean hasChild(List<SysMenu> list, SysMenu t)\r\n    {\r\n        return getChildList(list, t).size() > 0;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeReadServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\n\nimport java.util.List;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.ruoyi.common.core.text.Convert;\nimport com.ruoyi.system.domain.SysNoticeRead;\nimport com.ruoyi.system.domain.SysNotice;\nimport com.ruoyi.system.mapper.SysNoticeReadMapper;\nimport com.ruoyi.system.service.ISysNoticeReadService;\n\n/**\n * 公告已读记录 服务层实现\n *\n * @author ruoyi\n */\n@Service\npublic class SysNoticeReadServiceImpl implements ISysNoticeReadService\n{\n    @Autowired\n    private SysNoticeReadMapper noticeReadMapper;\n\n    /**\n     * 标记已读\n     */\n    @Override\n    public void markRead(Long noticeId, Long userId)\n    {\n        SysNoticeRead record = new SysNoticeRead();\n        record.setNoticeId(noticeId);\n        record.setUserId(userId);\n        noticeReadMapper.insertNoticeRead(record);\n    }\n\n    /**\n     * 查询某用户未读公告数量\n     */\n    @Override\n    public int selectUnreadCount(Long userId)\n    {\n        return noticeReadMapper.selectUnreadCount(userId);\n    }\n\n    /**\n     * 查询公告列表并标记当前用户已读状态\n     */\n    @Override\n    public List<SysNotice> selectNoticeListWithReadStatus(Long userId, int limit)\n    {\n        return noticeReadMapper.selectNoticeListWithReadStatus(userId, limit);\n    }\n\n    /**\n     * 批量标记已读\n     */\n    @Override\n    public void markReadBatch(Long userId, Long[] noticeIds)\n    {\n        if (noticeIds == null || noticeIds.length == 0)\n        {\n            return;\n        }\n        noticeReadMapper.insertNoticeReadBatch(userId, noticeIds);\n    }\n\n    /**\n     * 删除公告时清理对应已读记录\n     */\n    @Override\n    public void deleteByNoticeIds(String ids)\n    {\n        noticeReadMapper.deleteByNoticeIds(Convert.toStrArray(ids));\n    }\n}\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.List;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.system.domain.SysNotice;\r\nimport com.ruoyi.system.mapper.SysNoticeMapper;\r\nimport com.ruoyi.system.service.ISysNoticeService;\r\n\r\n/**\r\n * 公告 服务层实现\r\n * \r\n * @author ruoyi\r\n * @date 2018-06-25\r\n */\r\n@Service\r\npublic class SysNoticeServiceImpl implements ISysNoticeService\r\n{\r\n    @Autowired\r\n    private SysNoticeMapper noticeMapper;\r\n\r\n    /**\r\n     * 查询公告信息\r\n     * \r\n     * @param noticeId 公告ID\r\n     * @return 公告信息\r\n     */\r\n    @Override\r\n    public SysNotice selectNoticeById(Long noticeId)\r\n    {\r\n        return noticeMapper.selectNoticeById(noticeId);\r\n    }\r\n\r\n    /**\r\n     * 查询公告列表\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 公告集合\r\n     */\r\n    @Override\r\n    public List<SysNotice> selectNoticeList(SysNotice notice)\r\n    {\r\n        return noticeMapper.selectNoticeList(notice);\r\n    }\r\n\r\n    /**\r\n     * 新增公告\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertNotice(SysNotice notice)\r\n    {\r\n        return noticeMapper.insertNotice(notice);\r\n    }\r\n\r\n    /**\r\n     * 修改公告\r\n     * \r\n     * @param notice 公告信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int updateNotice(SysNotice notice)\r\n    {\r\n        return noticeMapper.updateNotice(notice);\r\n    }\r\n\r\n    /**\r\n     * 删除公告对象\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deleteNoticeByIds(String ids)\r\n    {\r\n        return noticeMapper.deleteNoticeByIds(Convert.toStrArray(ids));\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.List;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.system.domain.SysOperLog;\r\nimport com.ruoyi.system.mapper.SysOperLogMapper;\r\nimport com.ruoyi.system.service.ISysOperLogService;\r\n\r\n/**\r\n * 操作日志 服务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysOperLogServiceImpl implements ISysOperLogService\r\n{\r\n    @Autowired\r\n    private SysOperLogMapper operLogMapper;\r\n\r\n    /**\r\n     * 新增操作日志\r\n     * \r\n     * @param operLog 操作日志对象\r\n     */\r\n    @Override\r\n    public void insertOperlog(SysOperLog operLog)\r\n    {\r\n        operLogMapper.insertOperlog(operLog);\r\n    }\r\n\r\n    /**\r\n     * 查询系统操作日志集合\r\n     * \r\n     * @param operLog 操作日志对象\r\n     * @return 操作日志集合\r\n     */\r\n    @Override\r\n    public List<SysOperLog> selectOperLogList(SysOperLog operLog)\r\n    {\r\n        return operLogMapper.selectOperLogList(operLog);\r\n    }\r\n\r\n    /**\r\n     * 批量删除系统操作日志\r\n     * \r\n     * @param ids 需要删除的数据\r\n     * @return\r\n     */\r\n    @Override\r\n    public int deleteOperLogByIds(String ids)\r\n    {\r\n        return operLogMapper.deleteOperLogByIds(Convert.toStrArray(ids));\r\n    }\r\n\r\n    /**\r\n     * 查询操作日志详细\r\n     * \r\n     * @param operId 操作ID\r\n     * @return 操作日志对象\r\n     */\r\n    @Override\r\n    public SysOperLog selectOperLogById(Long operId)\r\n    {\r\n        return operLogMapper.selectOperLogById(operId);\r\n    }\r\n\r\n    /**\r\n     * 清空操作日志\r\n     */\r\n    @Override\r\n    public void cleanOperLog()\r\n    {\r\n        operLogMapper.cleanOperLog();\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.List;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.system.domain.SysPost;\r\nimport com.ruoyi.system.mapper.SysPostMapper;\r\nimport com.ruoyi.system.mapper.SysUserPostMapper;\r\nimport com.ruoyi.system.service.ISysPostService;\r\n\r\n/**\r\n * 岗位信息 服务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysPostServiceImpl implements ISysPostService\r\n{\r\n    @Autowired\r\n    private SysPostMapper postMapper;\r\n\r\n    @Autowired\r\n    private SysUserPostMapper userPostMapper;\r\n\r\n    /**\r\n     * 查询岗位信息集合\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 岗位信息集合\r\n     */\r\n    @Override\r\n    public List<SysPost> selectPostList(SysPost post)\r\n    {\r\n        return postMapper.selectPostList(post);\r\n    }\r\n\r\n    /**\r\n     * 查询所有岗位\r\n     * \r\n     * @return 岗位列表\r\n     */\r\n    @Override\r\n    public List<SysPost> selectPostAll()\r\n    {\r\n        return postMapper.selectPostAll();\r\n    }\r\n\r\n    /**\r\n     * 根据用户ID查询岗位\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 岗位列表\r\n     */\r\n    @Override\r\n    public List<SysPost> selectPostsByUserId(Long userId)\r\n    {\r\n        List<SysPost> userPosts = postMapper.selectPostsByUserId(userId);\r\n        List<SysPost> posts = postMapper.selectPostAll();\r\n        for (SysPost post : posts)\r\n        {\r\n            for (SysPost userRole : userPosts)\r\n            {\r\n                if (post.getPostId().longValue() == userRole.getPostId().longValue())\r\n                {\r\n                    post.setFlag(true);\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n        return posts;\r\n    }\r\n\r\n    /**\r\n     * 通过岗位ID查询岗位信息\r\n     * \r\n     * @param postId 岗位ID\r\n     * @return 角色对象信息\r\n     */\r\n    @Override\r\n    public SysPost selectPostById(Long postId)\r\n    {\r\n        return postMapper.selectPostById(postId);\r\n    }\r\n\r\n    /**\r\n     * 批量删除岗位信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deletePostByIds(String ids)\r\n    {\r\n        Long[] postIds = Convert.toLongArray(ids);\r\n        for (Long postId : postIds)\r\n        {\r\n            SysPost post = selectPostById(postId);\r\n            if (countUserPostById(postId) > 0)\r\n            {\r\n                throw new ServiceException(String.format(\"%1$s已分配,不能删除\", post.getPostName()));\r\n            }\r\n        }\r\n        return postMapper.deletePostByIds(postIds);\r\n    }\r\n\r\n    /**\r\n     * 新增保存岗位信息\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertPost(SysPost post)\r\n    {\r\n        return postMapper.insertPost(post);\r\n    }\r\n\r\n    /**\r\n     * 修改保存岗位信息\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int updatePost(SysPost post)\r\n    {\r\n        return postMapper.updatePost(post);\r\n    }\r\n\r\n    /**\r\n     * 通过岗位ID查询岗位使用数量\r\n     * \r\n     * @param postId 岗位ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int countUserPostById(Long postId)\r\n    {\r\n        return userPostMapper.countUserPostById(postId);\r\n    }\r\n\r\n    /**\r\n     * 校验岗位名称是否唯一\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkPostNameUnique(SysPost post)\r\n    {\r\n        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();\r\n        SysPost info = postMapper.checkPostNameUnique(post.getPostName());\r\n        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 校验岗位编码是否唯一\r\n     * \r\n     * @param post 岗位信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkPostCodeUnique(SysPost post)\r\n    {\r\n        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();\r\n        SysPost info = postMapper.checkPostCodeUnique(post.getPostCode());\r\n        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.HashSet;\r\nimport java.util.List;\r\nimport java.util.Set;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport org.springframework.transaction.annotation.Transactional;\r\nimport com.ruoyi.common.annotation.DataScope;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.system.domain.SysRoleDept;\r\nimport com.ruoyi.system.domain.SysRoleMenu;\r\nimport com.ruoyi.system.domain.SysUserRole;\r\nimport com.ruoyi.system.mapper.SysRoleDeptMapper;\r\nimport com.ruoyi.system.mapper.SysRoleMapper;\r\nimport com.ruoyi.system.mapper.SysRoleMenuMapper;\r\nimport com.ruoyi.system.mapper.SysUserRoleMapper;\r\nimport com.ruoyi.system.service.ISysRoleService;\r\n\r\n/**\r\n * 角色 业务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysRoleServiceImpl implements ISysRoleService\r\n{\r\n    @Autowired\r\n    private SysRoleMapper roleMapper;\r\n\r\n    @Autowired\r\n    private SysRoleMenuMapper roleMenuMapper;\r\n\r\n    @Autowired\r\n    private SysUserRoleMapper userRoleMapper;\r\n\r\n    @Autowired\r\n    private SysRoleDeptMapper roleDeptMapper;\r\n\r\n    /**\r\n     * 根据条件分页查询角色数据\r\n     * \r\n     * @param role 角色信息\r\n     * @return 角色数据集合信息\r\n     */\r\n    @Override\r\n    @DataScope(deptAlias = \"d\")\r\n    public List<SysRole> selectRoleList(SysRole role)\r\n    {\r\n        return roleMapper.selectRoleList(role);\r\n    }\r\n\r\n    /**\r\n     * 根据用户ID查询权限\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 权限列表\r\n     */\r\n    @Override\r\n    public Set<String> selectRoleKeys(Long userId)\r\n    {\r\n        List<SysRole> perms = roleMapper.selectRolesByUserId(userId);\r\n        Set<String> permsSet = new HashSet<>();\r\n        for (SysRole perm : perms)\r\n        {\r\n            if (StringUtils.isNotNull(perm))\r\n            {\r\n                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(\",\")));\r\n            }\r\n        }\r\n        return permsSet;\r\n    }\r\n\r\n    /**\r\n     * 根据用户ID查询角色\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 角色列表\r\n     */\r\n    @Override\r\n    public List<SysRole> selectRolesByUserId(Long userId)\r\n    {\r\n        List<SysRole> userRoles = roleMapper.selectRolesByUserId(userId);\r\n        List<SysRole> roles = selectRoleAll();\r\n        for (SysRole role : roles)\r\n        {\r\n            for (SysRole userRole : userRoles)\r\n            {\r\n                if (role.getRoleId().longValue() == userRole.getRoleId().longValue())\r\n                {\r\n                    role.setFlag(true);\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n        return roles;\r\n    }\r\n\r\n    /**\r\n     * 查询所有角色\r\n     * \r\n     * @return 角色列表\r\n     */\r\n    @Override\r\n    public List<SysRole> selectRoleAll()\r\n    {\r\n        return SpringUtils.getAopProxy(this).selectRoleList(new SysRole());\r\n    }\r\n\r\n    /**\r\n     * 通过角色ID查询角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 角色对象信息\r\n     */\r\n    @Override\r\n    public SysRole selectRoleById(Long roleId)\r\n    {\r\n        return roleMapper.selectRoleById(roleId);\r\n    }\r\n\r\n    /**\r\n     * 通过角色ID删除角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public boolean deleteRoleById(Long roleId)\r\n    {\r\n        // 删除角色与菜单关联\r\n        roleMenuMapper.deleteRoleMenuByRoleId(roleId);\r\n        // 删除角色与部门关联\r\n        roleDeptMapper.deleteRoleDeptByRoleId(roleId);\r\n        return roleMapper.deleteRoleById(roleId) > 0 ? true : false;\r\n    }\r\n\r\n    /**\r\n     * 批量删除角色信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @throws Exception\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int deleteRoleByIds(String ids)\r\n    {\r\n        Long[] roleIds = Convert.toLongArray(ids);\r\n        for (Long roleId : roleIds)\r\n        {\r\n            checkRoleAllowed(new SysRole(roleId));\r\n            checkRoleDataScope(roleId);\r\n            SysRole role = selectRoleById(roleId);\r\n            if (countUserRoleByRoleId(roleId) > 0)\r\n            {\r\n                throw new ServiceException(String.format(\"%1$s已分配,不能删除\", role.getRoleName()));\r\n            }\r\n        }\r\n        // 删除角色与菜单关联\r\n        roleMenuMapper.deleteRoleMenu(roleIds);\r\n        // 删除角色与部门关联\r\n        roleDeptMapper.deleteRoleDept(roleIds);\r\n        return roleMapper.deleteRoleByIds(roleIds);\r\n    }\r\n\r\n    /**\r\n     * 新增保存角色信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int insertRole(SysRole role)\r\n    {\r\n        // 新增角色信息\r\n        roleMapper.insertRole(role);\r\n        return insertRoleMenu(role);\r\n    }\r\n\r\n    /**\r\n     * 修改保存角色信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int updateRole(SysRole role)\r\n    {\r\n        // 修改角色信息\r\n        roleMapper.updateRole(role);\r\n        // 删除角色与菜单关联\r\n        roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId());\r\n        return insertRoleMenu(role);\r\n    }\r\n\r\n    /**\r\n     * 修改数据权限信息\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int authDataScope(SysRole role)\r\n    {\r\n        // 修改角色信息\r\n        roleMapper.updateRole(role);\r\n        // 删除角色与部门关联\r\n        roleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId());\r\n        // 新增角色和部门信息（数据权限）\r\n        return insertRoleDept(role);\r\n    }\r\n\r\n    /**\r\n     * 新增角色菜单信息\r\n     * \r\n     * @param role 角色对象\r\n     */\r\n    public int insertRoleMenu(SysRole role)\r\n    {\r\n        int rows = 1;\r\n        // 新增用户与角色管理\r\n        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();\r\n        for (Long menuId : role.getMenuIds())\r\n        {\r\n            SysRoleMenu rm = new SysRoleMenu();\r\n            rm.setRoleId(role.getRoleId());\r\n            rm.setMenuId(menuId);\r\n            list.add(rm);\r\n        }\r\n        if (list.size() > 0)\r\n        {\r\n            rows = roleMenuMapper.batchRoleMenu(list);\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 新增角色部门信息(数据权限)\r\n     *\r\n     * @param role 角色对象\r\n     */\r\n    public int insertRoleDept(SysRole role)\r\n    {\r\n        int rows = 1;\r\n        // 新增角色与部门（数据权限）管理\r\n        List<SysRoleDept> list = new ArrayList<SysRoleDept>();\r\n        for (Long deptId : role.getDeptIds())\r\n        {\r\n            SysRoleDept rd = new SysRoleDept();\r\n            rd.setRoleId(role.getRoleId());\r\n            rd.setDeptId(deptId);\r\n            list.add(rd);\r\n        }\r\n        if (list.size() > 0)\r\n        {\r\n            rows = roleDeptMapper.batchRoleDept(list);\r\n        }\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 校验角色名称是否唯一\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkRoleNameUnique(SysRole role)\r\n    {\r\n        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();\r\n        SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName());\r\n        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 校验角色权限是否唯一\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkRoleKeyUnique(SysRole role)\r\n    {\r\n        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();\r\n        SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey());\r\n        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 校验角色是否允许操作\r\n     * \r\n     * @param role 角色信息\r\n     */\r\n    @Override\r\n    public void checkRoleAllowed(SysRole role)\r\n    {\r\n        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin())\r\n        {\r\n            throw new ServiceException(\"不允许操作超级管理员角色\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 校验角色是否有数据权限\r\n     * \r\n     * @param roleIds 角色id\r\n     */\r\n    @Override\r\n    public void checkRoleDataScope(Long... roleIds)\r\n    {\r\n        if (!ShiroUtils.isAdmin())\r\n        {\r\n            for (Long roleId : roleIds)\r\n            {\r\n                SysRole role = new SysRole();\r\n                role.setRoleId(roleId);\r\n                List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);\r\n                if (StringUtils.isEmpty(roles))\r\n                {\r\n                    throw new ServiceException(\"没有权限访问角色数据！\");\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 通过角色ID查询角色使用数量\r\n     * \r\n     * @param roleId 角色ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int countUserRoleByRoleId(Long roleId)\r\n    {\r\n        return userRoleMapper.countUserRoleByRoleId(roleId);\r\n    }\r\n\r\n    /**\r\n     * 角色状态修改\r\n     * \r\n     * @param role 角色信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int changeStatus(SysRole role)\r\n    {\r\n        return roleMapper.updateRole(role);\r\n    }\r\n\r\n    /**\r\n     * 取消授权用户角色\r\n     * \r\n     * @param userRole 用户和角色关联信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deleteAuthUser(SysUserRole userRole)\r\n    {\r\n        return userRoleMapper.deleteUserRoleInfo(userRole);\r\n    }\r\n\r\n    /**\r\n     * 批量取消授权用户角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @param userIds 需要删除的用户数据ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int deleteAuthUsers(Long roleId, String userIds)\r\n    {\r\n        return userRoleMapper.deleteUserRoleInfos(roleId, Convert.toLongArray(userIds));\r\n    }\r\n\r\n    /**\r\n     * 批量选择授权用户角色\r\n     * \r\n     * @param roleId 角色ID\r\n     * @param userIds 需要授权的用户数据ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int insertAuthUsers(Long roleId, String userIds)\r\n    {\r\n        Long[] users = Convert.toLongArray(userIds);\r\n        // 新增用户与角色管理\r\n        List<SysUserRole> list = new ArrayList<SysUserRole>();\r\n        for (Long userId : users)\r\n        {\r\n            SysUserRole ur = new SysUserRole();\r\n            ur.setUserId(userId);\r\n            ur.setRoleId(roleId);\r\n            list.add(ur);\r\n        }\r\n        return userRoleMapper.batchUserRole(list);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.Date;\r\nimport java.util.Deque;\r\nimport java.util.List;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport org.apache.shiro.cache.Cache;\r\nimport org.apache.shiro.cache.ehcache.EhCacheManager;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport com.ruoyi.common.constant.ShiroConstants;\r\nimport com.ruoyi.common.utils.DateUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.system.domain.SysUserOnline;\r\nimport com.ruoyi.system.mapper.SysUserOnlineMapper;\r\nimport com.ruoyi.system.service.ISysUserOnlineService;\r\n\r\n/**\r\n * 在线用户 服务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysUserOnlineServiceImpl implements ISysUserOnlineService\r\n{\r\n    @Autowired\r\n    private SysUserOnlineMapper userOnlineDao;\r\n\r\n    /**\r\n     * 通过会话序号查询信息\r\n     * \r\n     * @param sessionId 会话ID\r\n     * @return 在线用户信息\r\n     */\r\n    @Override\r\n    public SysUserOnline selectOnlineById(String sessionId)\r\n    {\r\n        return userOnlineDao.selectOnlineById(sessionId);\r\n    }\r\n\r\n    /**\r\n     * 通过会话序号删除信息\r\n     * \r\n     * @param sessionId 会话ID\r\n     * @return 在线用户信息\r\n     */\r\n    @Override\r\n    public void deleteOnlineById(String sessionId)\r\n    {\r\n        SysUserOnline userOnline = selectOnlineById(sessionId);\r\n        if (StringUtils.isNotNull(userOnline))\r\n        {\r\n            userOnlineDao.deleteOnlineById(sessionId);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 通过会话序号删除信息\r\n     * \r\n     * @param sessions 会话ID集合\r\n     * @return 在线用户信息\r\n     */\r\n    @Override\r\n    public void batchDeleteOnline(List<String> sessions)\r\n    {\r\n        for (String sessionId : sessions)\r\n        {\r\n            SysUserOnline userOnline = selectOnlineById(sessionId);\r\n            if (StringUtils.isNotNull(userOnline))\r\n            {\r\n                userOnlineDao.deleteOnlineById(sessionId);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 保存会话信息\r\n     * \r\n     * @param online 会话信息\r\n     */\r\n    @Override\r\n    public void saveOnline(SysUserOnline online)\r\n    {\r\n        userOnlineDao.saveOnline(online);\r\n    }\r\n\r\n    /**\r\n     * 查询会话集合\r\n     * \r\n     * @param userOnline 在线用户\r\n     */\r\n    @Override\r\n    public List<SysUserOnline> selectUserOnlineList(SysUserOnline userOnline)\r\n    {\r\n        return userOnlineDao.selectUserOnlineList(userOnline);\r\n    }\r\n\r\n    /**\r\n     * 强退用户\r\n     * \r\n     * @param sessionId 会话ID\r\n     */\r\n    @Override\r\n    public void forceLogout(String sessionId)\r\n    {\r\n        userOnlineDao.deleteOnlineById(sessionId);\r\n    }\r\n\r\n    /**\r\n     * 清理用户缓存\r\n     * \r\n     * @param loginName 登录名称\r\n     * @param sessionId 会话ID\r\n     */\r\n    @Override\r\n    public void removeUserCache(String loginName, String sessionId)\r\n    {\r\n        EhCacheManager ehCacheManager = SpringUtils.getBean(EhCacheManager.class);\r\n        Cache<String, Deque<Serializable>> cache = ehCacheManager.getCache(ShiroConstants.SYS_USERCACHE);\r\n        Deque<Serializable> deque = cache.get(loginName);\r\n        if (StringUtils.isEmpty(deque) || deque.size() == 0)\r\n        {\r\n            return;\r\n        }\r\n        deque.remove(sessionId);\r\n    }\r\n\r\n    /**\r\n     * 查询会话集合\r\n     * \r\n     * @param expiredDate 失效日期\r\n     */\r\n    @Override\r\n    public List<SysUserOnline> selectOnlineByExpired(Date expiredDate)\r\n    {\r\n        String lastAccessTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, expiredDate);\r\n        return userOnlineDao.selectOnlineByExpired(lastAccessTime);\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java",
    "content": "package com.ruoyi.system.service.impl;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.stream.Collectors;\r\nimport jakarta.validation.ConstraintViolationException;\r\nimport jakarta.validation.Validator;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\nimport org.springframework.transaction.annotation.Transactional;\r\nimport org.springframework.util.CollectionUtils;\r\nimport com.ruoyi.common.annotation.DataScope;\r\nimport com.ruoyi.common.constant.UserConstants;\r\nimport com.ruoyi.common.core.domain.entity.SysRole;\r\nimport com.ruoyi.common.core.domain.entity.SysUser;\r\nimport com.ruoyi.common.core.text.Convert;\r\nimport com.ruoyi.common.exception.ServiceException;\r\nimport com.ruoyi.common.utils.ExceptionUtil;\r\nimport com.ruoyi.common.utils.ShiroUtils;\r\nimport com.ruoyi.common.utils.StringUtils;\r\nimport com.ruoyi.common.utils.bean.BeanValidators;\r\nimport com.ruoyi.common.utils.html.EscapeUtil;\r\nimport com.ruoyi.common.utils.security.Md5Utils;\r\nimport com.ruoyi.common.utils.spring.SpringUtils;\r\nimport com.ruoyi.system.domain.SysPost;\r\nimport com.ruoyi.system.domain.SysUserPost;\r\nimport com.ruoyi.system.domain.SysUserRole;\r\nimport com.ruoyi.system.mapper.SysPostMapper;\r\nimport com.ruoyi.system.mapper.SysRoleMapper;\r\nimport com.ruoyi.system.mapper.SysUserMapper;\r\nimport com.ruoyi.system.mapper.SysUserPostMapper;\r\nimport com.ruoyi.system.mapper.SysUserRoleMapper;\r\nimport com.ruoyi.system.service.ISysConfigService;\r\nimport com.ruoyi.system.service.ISysDeptService;\r\nimport com.ruoyi.system.service.ISysUserService;\r\n\r\n/**\r\n * 用户 业务层处理\r\n * \r\n * @author ruoyi\r\n */\r\n@Service\r\npublic class SysUserServiceImpl implements ISysUserService\r\n{\r\n    private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);\r\n\r\n    @Autowired\r\n    private SysUserMapper userMapper;\r\n\r\n    @Autowired\r\n    private SysRoleMapper roleMapper;\r\n\r\n    @Autowired\r\n    private SysPostMapper postMapper;\r\n\r\n    @Autowired\r\n    private SysUserPostMapper userPostMapper;\r\n\r\n    @Autowired\r\n    private SysUserRoleMapper userRoleMapper;\r\n\r\n    @Autowired\r\n    private ISysConfigService configService;\r\n\r\n    @Autowired\r\n    private ISysDeptService deptService;\r\n\r\n    @Autowired\r\n    protected Validator validator;\r\n\r\n    /**\r\n     * 根据条件分页查询用户列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    @Override\r\n    @DataScope(deptAlias = \"d\", userAlias = \"u\")\r\n    public List<SysUser> selectUserList(SysUser user)\r\n    {\r\n        return userMapper.selectUserList(user);\r\n    }\r\n\r\n    /**\r\n     * 根据条件分页查询已分配用户角色列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    @Override\r\n    @DataScope(deptAlias = \"d\", userAlias = \"u\")\r\n    public List<SysUser> selectAllocatedList(SysUser user)\r\n    {\r\n        return userMapper.selectAllocatedList(user);\r\n    }\r\n\r\n    /**\r\n     * 根据条件分页查询未分配用户角色列表\r\n     * \r\n     * @param user 用户信息\r\n     * @return 用户信息集合信息\r\n     */\r\n    @Override\r\n    @DataScope(deptAlias = \"d\", userAlias = \"u\")\r\n    public List<SysUser> selectUnallocatedList(SysUser user)\r\n    {\r\n        return userMapper.selectUnallocatedList(user);\r\n    }\r\n\r\n    /**\r\n     * 通过用户名查询用户\r\n     * \r\n     * @param userName 用户名\r\n     * @return 用户对象信息\r\n     */\r\n    @Override\r\n    public SysUser selectUserByLoginName(String userName)\r\n    {\r\n        return userMapper.selectUserByLoginName(userName);\r\n    }\r\n\r\n    /**\r\n     * 通过手机号码查询用户\r\n     * \r\n     * @param phoneNumber 手机号码\r\n     * @return 用户对象信息\r\n     */\r\n    @Override\r\n    public SysUser selectUserByPhoneNumber(String phoneNumber)\r\n    {\r\n        return userMapper.selectUserByPhoneNumber(phoneNumber);\r\n    }\r\n\r\n    /**\r\n     * 通过邮箱查询用户\r\n     * \r\n     * @param email 邮箱\r\n     * @return 用户对象信息\r\n     */\r\n    @Override\r\n    public SysUser selectUserByEmail(String email)\r\n    {\r\n        return userMapper.selectUserByEmail(email);\r\n    }\r\n\r\n    /**\r\n     * 通过用户ID查询用户\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 用户对象信息\r\n     */\r\n    @Override\r\n    public SysUser selectUserById(Long userId)\r\n    {\r\n        return userMapper.selectUserById(userId);\r\n    }\r\n\r\n    /**\r\n     * 通过用户ID查询用户和角色关联\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 用户和角色关联列表\r\n     */\r\n    @Override\r\n    public List<SysUserRole> selectUserRoleByUserId(Long userId)\r\n    {\r\n        return userRoleMapper.selectUserRoleByUserId(userId);\r\n    }\r\n\r\n    /**\r\n     * 通过用户ID删除用户\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int deleteUserById(Long userId)\r\n    {\r\n        // 删除用户与角色关联\r\n        userRoleMapper.deleteUserRoleByUserId(userId);\r\n        // 删除用户与岗位表\r\n        userPostMapper.deleteUserPostByUserId(userId);\r\n        return userMapper.deleteUserById(userId);\r\n    }\r\n\r\n    /**\r\n     * 批量删除用户信息\r\n     * \r\n     * @param ids 需要删除的数据ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int deleteUserByIds(String ids)\r\n    {\r\n        Long[] userIds = Convert.toLongArray(ids);\r\n        for (Long userId : userIds)\r\n        {\r\n            checkUserAllowed(new SysUser(userId));\r\n            checkUserDataScope(userId);\r\n        }\r\n        // 删除用户与角色关联\r\n        userRoleMapper.deleteUserRole(userIds);\r\n        // 删除用户与岗位关联\r\n        userPostMapper.deleteUserPost(userIds);\r\n        return userMapper.deleteUserByIds(userIds);\r\n    }\r\n\r\n    /**\r\n     * 新增保存用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int insertUser(SysUser user)\r\n    {\r\n        // 新增用户信息\r\n        int rows = userMapper.insertUser(user);\r\n        // 新增用户岗位关联\r\n        insertUserPost(user);\r\n        // 新增用户与角色管理\r\n        insertUserRole(user.getUserId(), user.getRoleIds());\r\n        return rows;\r\n    }\r\n\r\n    /**\r\n     * 注册用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean registerUser(SysUser user)\r\n    {\r\n        user.setUserType(UserConstants.REGISTER_USER_TYPE);\r\n        return userMapper.insertUser(user) > 0;\r\n    }\r\n\r\n    /**\r\n     * 修改保存用户信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public int updateUser(SysUser user)\r\n    {\r\n        Long userId = user.getUserId();\r\n        // 删除用户与角色关联\r\n        userRoleMapper.deleteUserRoleByUserId(userId);\r\n        // 新增用户与角色管理\r\n        insertUserRole(user.getUserId(), user.getRoleIds());\r\n        // 删除用户与岗位关联\r\n        userPostMapper.deleteUserPostByUserId(userId);\r\n        // 新增用户与岗位管理\r\n        insertUserPost(user);\r\n        return userMapper.updateUser(user);\r\n    }\r\n\r\n    /**\r\n     * 修改用户个人详细信息\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int updateUserInfo(SysUser user)\r\n    {\r\n        return userMapper.updateUser(user);\r\n    }\r\n\r\n    /**\r\n     * 修改用户头像\r\n     * \r\n     * @param userId 用户ID\r\n     * @param avatar 头像地址\r\n     * @return 结果\r\n     */\r\n    public boolean updateUserAvatar(Long userId, String avatar)\r\n    {\r\n        return userMapper.updateUserAvatar(userId, avatar) > 0;\r\n    }\r\n\r\n    /**\r\n     * 更新用户登录信息（IP和登录时间）\r\n     * \r\n     * @param userId 用户ID\r\n     * @param loginIp 登录IP地址\r\n     * @param loginDate 登录时间\r\n     * @return 结果\r\n     */\r\n    public void updateLoginInfo(Long userId, String loginIp, Date loginDate)\r\n    {\r\n        userMapper.updateLoginInfo(userId, loginIp, loginDate);\r\n    }\r\n\r\n    /**\r\n     * 用户授权角色\r\n     * \r\n     * @param userId 用户ID\r\n     * @param roleIds 角色组\r\n     */\r\n    @Override\r\n    @Transactional\r\n    public void insertUserAuth(Long userId, Long[] roleIds)\r\n    {\r\n        userRoleMapper.deleteUserRoleByUserId(userId);\r\n        insertUserRole(userId, roleIds);\r\n    }\r\n\r\n    /**\r\n     * 修改用户密码\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int resetUserPwd(SysUser user)\r\n    {\r\n        return userMapper.resetUserPwd(user.getUserId(), user.getPassword(), user.getSalt());\r\n    }\r\n\r\n    /**\r\n     * 新增用户角色信息\r\n     * \r\n     * @param userId 用户ID\r\n     * @param roleIds 角色组\r\n     */\r\n    public void insertUserRole(Long userId, Long[] roleIds)\r\n    {\r\n        if (StringUtils.isNotNull(roleIds))\r\n        {\r\n            // 新增用户与角色管理\r\n            List<SysUserRole> list = new ArrayList<SysUserRole>();\r\n            for (Long roleId : roleIds)\r\n            {\r\n                SysUserRole ur = new SysUserRole();\r\n                ur.setUserId(userId);\r\n                ur.setRoleId(roleId);\r\n                list.add(ur);\r\n            }\r\n            if (list.size() > 0)\r\n            {\r\n                userRoleMapper.batchUserRole(list);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 新增用户岗位信息\r\n     * \r\n     * @param user 用户对象\r\n     */\r\n    public void insertUserPost(SysUser user)\r\n    {\r\n        Long[] posts = user.getPostIds();\r\n        if (StringUtils.isNotNull(posts))\r\n        {\r\n            // 新增用户与岗位管理\r\n            List<SysUserPost> list = new ArrayList<SysUserPost>();\r\n            for (Long postId : posts)\r\n            {\r\n                SysUserPost up = new SysUserPost();\r\n                up.setUserId(user.getUserId());\r\n                up.setPostId(postId);\r\n                list.add(up);\r\n            }\r\n            if (list.size() > 0)\r\n            {\r\n                userPostMapper.batchUserPost(list);\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 校验用户名称是否唯一\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public boolean checkLoginNameUnique(SysUser user)\r\n    {\r\n        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();\r\n        SysUser info = userMapper.checkLoginNameUnique(user.getLoginName());\r\n        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 校验手机号码是否唯一\r\n     *\r\n     * @param user 用户信息\r\n     * @return\r\n     */\r\n    @Override\r\n    public boolean checkPhoneUnique(SysUser user)\r\n    {\r\n        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();\r\n        SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());\r\n        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 校验email是否唯一\r\n     *\r\n     * @param user 用户信息\r\n     * @return\r\n     */\r\n    @Override\r\n    public boolean checkEmailUnique(SysUser user)\r\n    {\r\n        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();\r\n        SysUser info = userMapper.checkEmailUnique(user.getEmail());\r\n        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())\r\n        {\r\n            return UserConstants.NOT_UNIQUE;\r\n        }\r\n        return UserConstants.UNIQUE;\r\n    }\r\n\r\n    /**\r\n     * 校验用户是否允许操作\r\n     * \r\n     * @param user 用户信息\r\n     */\r\n    @Override\r\n    public void checkUserAllowed(SysUser user)\r\n    {\r\n        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())\r\n        {\r\n            throw new ServiceException(\"不允许操作超级管理员用户\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 校验用户是否有数据权限\r\n     * \r\n     * @param userId 用户id\r\n     */\r\n    @Override\r\n    public void checkUserDataScope(Long userId)\r\n    {\r\n        if (!ShiroUtils.isAdmin())\r\n        {\r\n            SysUser user = new SysUser();\r\n            user.setUserId(userId);\r\n            List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);\r\n            if (StringUtils.isEmpty(users))\r\n            {\r\n                throw new ServiceException(\"没有权限访问用户数据！\");\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 查询用户所属角色组\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public String selectUserRoleGroup(Long userId)\r\n    {\r\n        List<SysRole> list = roleMapper.selectRolesByUserId(userId);\r\n        if (CollectionUtils.isEmpty(list))\r\n        {\r\n            return StringUtils.EMPTY;\r\n        }\r\n        return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(\",\"));\r\n    }\r\n\r\n    /**\r\n     * 查询用户所属岗位组\r\n     * \r\n     * @param userId 用户ID\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public String selectUserPostGroup(Long userId)\r\n    {\r\n        List<SysPost> list = postMapper.selectPostsByUserId(userId);\r\n        if (CollectionUtils.isEmpty(list))\r\n        {\r\n            return StringUtils.EMPTY;\r\n        }\r\n        return list.stream().map(SysPost::getPostName).collect(Collectors.joining(\",\"));\r\n    }\r\n\r\n    /**\r\n     * 导入用户数据\r\n     * \r\n     * @param userList 用户数据列表\r\n     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据\r\n     * @param operName 操作用户\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName)\r\n    {\r\n        if (StringUtils.isNull(userList) || userList.size() == 0)\r\n        {\r\n            throw new ServiceException(\"导入用户数据不能为空！\");\r\n        }\r\n        int successNum = 0;\r\n        int failureNum = 0;\r\n        StringBuilder successMsg = new StringBuilder();\r\n        StringBuilder failureMsg = new StringBuilder();\r\n        for (SysUser user : userList)\r\n        {\r\n            try\r\n            {\r\n                // 验证是否存在这个用户\r\n                SysUser u = userMapper.selectUserByLoginName(user.getLoginName());\r\n                if (StringUtils.isNull(u))\r\n                {\r\n                    BeanValidators.validateWithException(validator, user);\r\n                    deptService.checkDeptDataScope(user.getDeptId());\r\n                    String password = configService.selectConfigByKey(\"sys.user.initPassword\");\r\n                    user.setPassword(Md5Utils.hash(user.getLoginName() + password));\r\n                    user.setCreateBy(operName);\r\n                    userMapper.insertUser(user);\r\n                    successNum++;\r\n                    successMsg.append(\"<br/>\" + successNum + \"、账号 \" + user.getLoginName() + \" 导入成功\");\r\n                }\r\n                else if (isUpdateSupport)\r\n                {\r\n                    BeanValidators.validateWithException(validator, user);\r\n                    checkUserAllowed(u);\r\n                    checkUserDataScope(u.getUserId());\r\n                    deptService.checkDeptDataScope(user.getDeptId());\r\n                    user.setUserId(u.getUserId());\r\n                    user.setDeptId(u.getDeptId());\r\n                    user.setUpdateBy(operName);\r\n                    userMapper.updateUser(user);\r\n                    successNum++;\r\n                    successMsg.append(\"<br/>\" + successNum + \"、账号 \" + user.getLoginName() + \" 更新成功\");\r\n                }\r\n                else\r\n                {\r\n                    failureNum++;\r\n                    failureMsg.append(\"<br/>\" + failureNum + \"、账号 \" + user.getLoginName() + \" 已存在\");\r\n                }\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                failureNum++;\r\n                String loginName = user.getLoginName();\r\n                if (ExceptionUtil.isCausedBy(e, ConstraintViolationException.class))\r\n                {\r\n                    loginName = EscapeUtil.clean(loginName);\r\n                }\r\n                String msg = \"<br/>\" + failureNum + \"、账号 \" + loginName + \" 导入失败：\";\r\n                failureMsg.append(msg + e.getMessage());\r\n                log.error(msg, e);\r\n            }\r\n        }\r\n        if (failureNum > 0)\r\n        {\r\n            failureMsg.insert(0, \"很抱歉，导入失败！共 \" + failureNum + \" 条数据格式不正确，错误如下：\");\r\n            throw new ServiceException(failureMsg.toString());\r\n        }\r\n        else\r\n        {\r\n            successMsg.insert(0, \"恭喜您，数据已全部导入成功！共 \" + successNum + \" 条，数据如下：\");\r\n        }\r\n        return successMsg.toString();\r\n    }\r\n\r\n    /**\r\n     * 用户状态修改\r\n     * \r\n     * @param user 用户信息\r\n     * @return 结果\r\n     */\r\n    @Override\r\n    public int changeStatus(SysUser user)\r\n    {\r\n        return userMapper.updateUserStatus(user.getUserId(), user.getStatus());\r\n    }\r\n}\r\n"
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysConfigMapper\">\r\n    \r\n    <resultMap type=\"SysConfig\" id=\"SysConfigResult\">\r\n    \t<id     property=\"configId\"      column=\"config_id\"      />\r\n        <result property=\"configName\"    column=\"config_name\"    />\r\n        <result property=\"configKey\"     column=\"config_key\"     />\r\n        <result property=\"configValue\"   column=\"config_value\"   />\r\n        <result property=\"configType\"    column=\"config_type\"    />\r\n        <result property=\"createBy\"      column=\"create_by\"      />\r\n        <result property=\"createTime\"    column=\"create_time\"    />\r\n        <result property=\"updateBy\"      column=\"update_by\"      />\r\n        <result property=\"updateTime\"    column=\"update_time\"    />\r\n    </resultMap>\r\n    \r\n    <sql id=\"selectConfigVo\">\r\n        select config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark \r\n\t\tfrom sys_config\r\n    </sql>\r\n    \r\n    <!-- 查询条件 -->\r\n\t<sql id=\"sqlwhereSearch\">\r\n\t\t<where>\r\n\t\t\t<if test=\"configId !=null\">\r\n\t\t\t\tand config_id = #{configId}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"configKey !=null and configKey != ''\">\r\n\t\t\t\tand config_key = #{configKey}\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t</sql>\r\n    \r\n    <select id=\"selectConfig\" parameterType=\"SysConfig\" resultMap=\"SysConfigResult\">\r\n        <include refid=\"selectConfigVo\"/>\r\n        <include refid=\"sqlwhereSearch\"/>\r\n    </select>\r\n    \r\n    <select id=\"selectConfigList\" parameterType=\"SysConfig\" resultMap=\"SysConfigResult\">\r\n        <include refid=\"selectConfigVo\"/>\r\n        <where>\r\n\t\t\t<if test=\"configName != null and configName != ''\">\r\n\t\t\t\tAND config_name like concat('%', #{configName}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"configType != null and configType != ''\">\r\n\t\t\t\tAND config_type = #{configType}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"configKey != null and configKey != ''\">\r\n\t\t\t\tAND config_key like concat('%', #{configKey}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.beginTime != null and params.beginTime != ''\"><!-- 开始时间检索 -->\r\n\t\t\t\tand date_format(create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.endTime != null and params.endTime != ''\"><!-- 结束时间检索 -->\r\n\t\t\t\tand date_format(create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')\r\n\t\t\t</if>\r\n\t\t</where>\r\n    </select>\r\n    \r\n    <select id=\"selectConfigById\" parameterType=\"Long\" resultMap=\"SysConfigResult\">\r\n\t\t<include refid=\"selectConfigVo\"/>\r\n\t\twhere config_id = #{configId}\r\n\t</select>\r\n    \r\n    <select id=\"checkConfigKeyUnique\" parameterType=\"String\" resultMap=\"SysConfigResult\">\r\n        <include refid=\"selectConfigVo\"/>\r\n        where config_key = #{configKey} limit 1\r\n    </select>\r\n    \r\n    <insert id=\"insertConfig\" parameterType=\"SysConfig\">\r\n        insert into sys_config (\r\n\t\t\t<if test=\"configName != null and configName != '' \">config_name,</if>\r\n\t\t\t<if test=\"configKey != null and configKey != '' \">config_key,</if>\r\n\t\t\t<if test=\"configValue != null and configValue != '' \">config_value,</if>\r\n\t\t\t<if test=\"configType != null and configType != '' \">config_type,</if>\r\n\t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n\t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\tcreate_time\r\n        )values(\r\n\t\t\t<if test=\"configName != null and configName != ''\">#{configName},</if>\r\n\t\t\t<if test=\"configKey != null and configKey != ''\">#{configKey},</if>\r\n\t\t\t<if test=\"configValue != null and configValue != ''\">#{configValue},</if>\r\n\t\t\t<if test=\"configType != null and configType != ''\">#{configType},</if>\r\n\t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n\t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\tsysdate()\r\n\t\t)\r\n    </insert>\r\n\t \r\n    <update id=\"updateConfig\" parameterType=\"SysConfig\">\r\n        update sys_config \r\n        <set>\r\n            <if test=\"configName != null and configName != ''\">config_name = #{configName},</if>\r\n            <if test=\"configKey != null and configKey != ''\">config_key = #{configKey},</if>\r\n            <if test=\"configValue != null and configValue != ''\">config_value = #{configValue},</if>\r\n            <if test=\"configType != null and configType != ''\">config_type = #{configType},</if>\r\n            <if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n            <if test=\"remark != null\">remark = #{remark},</if>\r\n \t\t\tupdate_time = sysdate()\r\n        </set>\r\n        where config_id = #{configId}\r\n    </update>\r\n\t\r\n\t<delete id=\"deleteConfigById\" parameterType=\"Long\">\r\n\t\tdelete from sys_config where config_id = #{configId}\r\n\t</delete>\r\n\t\r\n    <delete id=\"deleteConfigByIds\" parameterType=\"String\">\r\n        delete from sys_config where config_id in \r\n        <foreach item=\"configId\" collection=\"array\" open=\"(\" separator=\",\" close=\")\">\r\n        \t#{configId}\r\n        </foreach>\r\n    </delete>\r\n    \r\n</mapper>"
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysDeptMapper\">\r\n\r\n\t<resultMap type=\"SysDept\" id=\"SysDeptResult\">\r\n\t\t<id     property=\"deptId\"     column=\"dept_id\"     />\r\n\t\t<result property=\"parentId\"   column=\"parent_id\"   />\r\n\t\t<result property=\"ancestors\"  column=\"ancestors\"   />\r\n\t\t<result property=\"deptName\"   column=\"dept_name\"   />\r\n\t\t<result property=\"orderNum\"   column=\"order_num\"   />\r\n\t\t<result property=\"leader\"     column=\"leader\"      />\r\n\t\t<result property=\"phone\"      column=\"phone\"       />\r\n\t\t<result property=\"email\"      column=\"email\"       />\r\n\t\t<result property=\"status\"     column=\"status\"      />\r\n\t\t<result property=\"delFlag\"    column=\"del_flag\"    />\r\n\t\t<result property=\"parentName\" column=\"parent_name\" />\r\n\t\t<result property=\"createBy\"   column=\"create_by\"   />\r\n\t\t<result property=\"createTime\" column=\"create_time\" />\r\n\t\t<result property=\"updateBy\"   column=\"update_by\"   />\r\n\t\t<result property=\"updateTime\" column=\"update_time\" />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectDeptVo\">\r\n        select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time \r\n        from sys_dept d\r\n    </sql>\r\n    \r\n\t<select id=\"selectRoleDeptTree\" parameterType=\"Long\" resultType=\"String\">\r\n\t\tselect concat(d.dept_id, d.dept_name) as dept_name\r\n\t\tfrom sys_dept d\r\n\t\t\tleft join sys_role_dept rd on d.dept_id = rd.dept_id\r\n\t\twhere d.del_flag = '0' and rd.role_id = #{roleId}\r\n\t\torder by d.parent_id, d.order_num\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDeptList\" parameterType=\"SysDept\" resultMap=\"SysDeptResult\">\r\n        <include refid=\"selectDeptVo\"/>\r\n        where d.del_flag = '0'\r\n\t\t<if test=\"deptId != null and deptId != 0\">\r\n\t\t\tAND dept_id = #{deptId}\r\n\t\t</if>\r\n        <if test=\"parentId != null and parentId != 0\">\r\n\t\t\tAND parent_id = #{parentId}\r\n\t\t</if>\r\n\t\t<if test=\"deptName != null and deptName != ''\">\r\n\t\t\tAND dept_name like concat('%', #{deptName}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"status != null and status != ''\">\r\n\t\t\tAND status = #{status}\r\n\t\t</if>\r\n\t\t<!-- 数据范围过滤 -->\r\n\t\t${params.dataScope}\r\n\t\torder by d.parent_id, d.order_num\r\n    </select>\r\n\t\r\n\t<select id=\"checkDeptExistUser\" parameterType=\"Long\" resultType=\"int\">\r\n\t\tselect count(1) from sys_user where dept_id = #{deptId} and del_flag = '0'\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDeptCount\" parameterType=\"SysDept\" resultType=\"int\">\r\n\t\tselect count(1) from sys_dept\r\n\t\twhere del_flag = '0'\r\n\t\t<if test=\"deptId != null and deptId != 0\"> and dept_id = #{deptId} </if>\r\n\t\t<if test=\"parentId != null and parentId != 0\"> and parent_id = #{parentId} </if>\r\n\t</select>\r\n\t\r\n\t<select id=\"checkDeptNameUnique\" resultMap=\"SysDeptResult\">\r\n\t    <include refid=\"selectDeptVo\"/>\r\n\t\twhere dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' limit 1\r\n\t</select>\r\n\r\n\t<select id=\"selectDeptById\" parameterType=\"Long\" resultMap=\"SysDeptResult\">\r\n\t\tselect d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status,\r\n\t\t\t(select dept_name from sys_dept where dept_id = d.parent_id) parent_name\r\n\t\tfrom sys_dept d\r\n\t\twhere d.dept_id = #{deptId}\r\n\t</select>\r\n\r\n\t<select id=\"selectChildrenDeptById\" parameterType=\"Long\" resultMap=\"SysDeptResult\">\r\n\t\tselect * from sys_dept where find_in_set(#{deptId}, ancestors)\r\n\t</select>\r\n\t\r\n\t<select id=\"selectNormalChildrenDeptById\" parameterType=\"Long\" resultType=\"int\">\r\n\t\tselect count(*) from sys_dept where status = 0 and del_flag = '0' and find_in_set(#{deptId}, ancestors)\r\n\t</select>\r\n\t\r\n\t<insert id=\"insertDept\" parameterType=\"SysDept\">\r\n \t\tinsert into sys_dept(\r\n \t\t\t<if test=\"deptId != null and deptId != 0\">dept_id,</if>\r\n \t\t\t<if test=\"parentId != null and parentId != 0\">parent_id,</if>\r\n \t\t\t<if test=\"deptName != null and deptName != ''\">dept_name,</if>\r\n \t\t\t<if test=\"ancestors != null and ancestors != ''\">ancestors,</if>\r\n \t\t\t<if test=\"orderNum != null\">order_num,</if>\r\n \t\t\t<if test=\"leader != null and leader != ''\">leader,</if>\r\n \t\t\t<if test=\"phone != null and phone != ''\">phone,</if>\r\n \t\t\t<if test=\"email != null and email != ''\">email,</if>\r\n \t\t\t<if test=\"status != null\">status,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t\t<if test=\"deptId != null and deptId != 0\">#{deptId},</if>\r\n \t\t\t<if test=\"parentId != null and parentId != 0\">#{parentId},</if>\r\n \t\t\t<if test=\"deptName != null and deptName != ''\">#{deptName},</if>\r\n \t\t\t<if test=\"ancestors != null and ancestors != ''\">#{ancestors},</if>\r\n \t\t\t<if test=\"orderNum != null\">#{orderNum},</if>\r\n \t\t\t<if test=\"leader != null and leader != ''\">#{leader},</if>\r\n \t\t\t<if test=\"phone != null and phone != ''\">#{phone},</if>\r\n \t\t\t<if test=\"email != null and email != ''\">#{email},</if>\r\n \t\t\t<if test=\"status != null\">#{status},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\t\r\n\t<update id=\"updateDept\" parameterType=\"SysDept\">\r\n \t\tupdate sys_dept\r\n \t\t<set>\r\n \t\t\t<if test=\"parentId != null and parentId != 0\">parent_id = #{parentId},</if>\r\n \t\t\t<if test=\"deptName != null and deptName != ''\">dept_name = #{deptName},</if>\r\n \t\t\t<if test=\"ancestors != null and ancestors != ''\">ancestors = #{ancestors},</if>\r\n \t\t\t<if test=\"orderNum != null\">order_num = #{orderNum},</if>\r\n \t\t\t<if test=\"leader != null\">leader = #{leader},</if>\r\n \t\t\t<if test=\"phone != null\">phone = #{phone},</if>\r\n \t\t\t<if test=\"email != null\">email = #{email},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status = #{status},</if>\r\n \t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\tupdate_time = sysdate()\r\n \t\t</set>\r\n \t\twhere dept_id = #{deptId}\r\n\t</update>\r\n\t\r\n\t<update id=\"updateDeptChildren\" parameterType=\"java.util.List\">\r\n\t    update sys_dept set ancestors =\r\n\t    <foreach collection=\"depts\" item=\"item\" index=\"index\"\r\n\t        separator=\" \" open=\"case dept_id\" close=\"end\">\r\n\t        when #{item.deptId} then #{item.ancestors}\r\n\t    </foreach>\r\n\t    where dept_id in\r\n\t    <foreach collection=\"depts\" item=\"item\" index=\"index\"\r\n\t        separator=\",\" open=\"(\" close=\")\">\r\n\t        #{item.deptId}\r\n\t    </foreach>\r\n\t </update>\r\n\r\n\t<delete id=\"deleteDeptById\" parameterType=\"Long\">\r\n\t\tupdate sys_dept set del_flag = '2' where dept_id = #{deptId}\r\n\t</delete>\r\n\t\r\n\t<update id=\"updateDeptStatusNormal\" parameterType=\"Long\">\r\n \t    update sys_dept set status = '0' where dept_id in \r\n \t    <foreach collection=\"array\" item=\"deptId\" open=\"(\" separator=\",\" close=\")\">\r\n        \t#{deptId}\r\n        </foreach>\r\n\t</update>\r\n\r\n\t<update id=\"updateDeptSort\" parameterType=\"SysDept\">\r\n\t\tupdate sys_dept set order_num = #{orderNum} where dept_id = #{deptId}\r\n\t</update>\r\n\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysDictDataMapper\">\r\n\t\r\n\t<resultMap type=\"SysDictData\" id=\"SysDictDataResult\">\r\n\t\t<id     property=\"dictCode\"   column=\"dict_code\"   />\r\n\t\t<result property=\"dictSort\"   column=\"dict_sort\"   />\r\n\t\t<result property=\"dictLabel\"  column=\"dict_label\"  />\r\n\t\t<result property=\"dictValue\"  column=\"dict_value\"  />\r\n\t\t<result property=\"dictType\"   column=\"dict_type\"   />\r\n\t\t<result property=\"cssClass\"   column=\"css_class\"   />\r\n\t\t<result property=\"listClass\"  column=\"list_class\"  />\r\n\t\t<result property=\"isDefault\"  column=\"is_default\"  />\r\n\t\t<result property=\"status\"     column=\"status\"      />\r\n\t\t<result property=\"createBy\"   column=\"create_by\"   />\r\n\t\t<result property=\"createTime\" column=\"create_time\" />\r\n\t\t<result property=\"updateBy\"   column=\"update_by\"   />\r\n\t\t<result property=\"updateTime\" column=\"update_time\" />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectDictDataVo\">\r\n        select dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark \r\n\t\tfrom sys_dict_data\r\n    </sql>\r\n\r\n\t<select id=\"selectDictDataList\" parameterType=\"SysDictData\" resultMap=\"SysDictDataResult\">\r\n\t    <include refid=\"selectDictDataVo\"/>\r\n\t\t<where>\r\n\t\t    <if test=\"dictType != null and dictType != ''\">\r\n\t\t\t\tAND dict_type = #{dictType}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"dictLabel != null and dictLabel != ''\">\r\n\t\t\t\tAND dict_label like concat('%', #{dictLabel}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"status != null and status != ''\">\r\n\t\t\t\tAND status = #{status}\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDictDataByType\" parameterType=\"String\" resultMap=\"SysDictDataResult\">\r\n\t\t<include refid=\"selectDictDataVo\"/>\r\n\t\twhere status = '0' and dict_type = #{dictType} order by dict_sort asc\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDictLabel\" resultType=\"String\">\r\n\t\tselect dict_label from sys_dict_data\r\n\t\twhere dict_type = #{dictType} and dict_value = #{dictValue}\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDictDataById\" parameterType=\"Long\" resultMap=\"SysDictDataResult\">\r\n\t\t<include refid=\"selectDictDataVo\"/>\r\n\t\twhere dict_code = #{dictCode}\r\n\t</select>\r\n\t\r\n\t<select id=\"countDictDataByType\" resultType=\"Integer\">\r\n\t    select count(1) from sys_dict_data where dict_type=#{dictType}  \r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteDictDataById\" parameterType=\"Long\">\r\n \t\tdelete from sys_dict_data where dict_code = #{dictCode}\r\n \t</delete>\r\n\t\r\n \t<delete id=\"deleteDictDataByIds\" parameterType=\"String\">\r\n \t\tdelete from sys_dict_data where dict_code in\r\n \t\t<foreach collection=\"array\" item=\"dictCode\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{dictCode}\r\n        </foreach> \r\n \t</delete>\r\n \t\r\n\t<update id=\"updateDictData\" parameterType=\"SysDictData\">\r\n \t\tupdate sys_dict_data\r\n \t\t<set>\r\n \t\t\t<if test=\"dictSort != null\">dict_sort = #{dictSort},</if>\r\n \t\t\t<if test=\"dictLabel != null and dictLabel != ''\">dict_label = #{dictLabel},</if>\r\n \t\t\t<if test=\"dictValue != null and dictValue != ''\">dict_value = #{dictValue},</if>\r\n \t\t\t<if test=\"dictType != null and dictType != ''\">dict_type = #{dictType},</if>\r\n \t\t\t<if test=\"cssClass != null\">css_class = #{cssClass},</if>\r\n \t\t\t<if test=\"listClass != null\">list_class = #{listClass},</if>\r\n \t\t\t<if test=\"isDefault != null and isDefault != ''\">is_default = #{isDefault},</if>\r\n \t\t\t<if test=\"status != null\">status = #{status},</if>\r\n \t\t\t<if test=\"remark != null\">remark = #{remark},</if>\r\n \t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\tupdate_time = sysdate()\r\n \t\t</set>\r\n \t\twhere dict_code = #{dictCode}\r\n\t</update>\r\n\t\r\n\t<update id=\"updateDictDataType\" parameterType=\"String\">\r\n \t\tupdate sys_dict_data set dict_type = #{newDictType} where dict_type = #{oldDictType}\r\n\t</update>\r\n \t\r\n \t<insert id=\"insertDictData\" parameterType=\"SysDictData\">\r\n \t\tinsert into sys_dict_data(\r\n \t\t\t<if test=\"dictSort != null\">dict_sort,</if>\r\n \t\t\t<if test=\"dictLabel != null and dictLabel != ''\">dict_label,</if>\r\n \t\t\t<if test=\"dictValue != null and dictValue != ''\">dict_value,</if>\r\n \t\t\t<if test=\"dictType != null and dictType != ''\">dict_type,</if>\r\n \t\t\t<if test=\"cssClass != null and cssClass != ''\">css_class,</if>\r\n \t\t\t<if test=\"listClass != null and listClass != ''\">list_class,</if>\r\n \t\t\t<if test=\"isDefault != null and isDefault != ''\">is_default,</if>\r\n \t\t\t<if test=\"status != null\">status,</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t    <if test=\"dictSort != null\">#{dictSort},</if>\r\n \t\t    <if test=\"dictLabel != null and dictLabel != ''\">#{dictLabel},</if>\r\n \t\t\t<if test=\"dictValue != null and dictValue != ''\">#{dictValue},</if>\r\n \t\t\t<if test=\"dictType != null and dictType != ''\">#{dictType},</if>\r\n \t\t\t<if test=\"cssClass != null and cssClass != ''\">#{cssClass},</if>\r\n \t\t\t<if test=\"listClass != null and listClass != ''\">#{listClass},</if>\r\n \t\t\t<if test=\"isDefault != null and isDefault != ''\">#{isDefault},</if>\r\n \t\t\t<if test=\"status != null\">#{status},</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\t\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysDictTypeMapper\">\r\n\r\n\t<resultMap type=\"SysDictType\" id=\"SysDictTypeResult\">\r\n\t\t<id     property=\"dictId\"     column=\"dict_id\"     />\r\n\t\t<result property=\"dictName\"   column=\"dict_name\"   />\r\n\t\t<result property=\"dictType\"   column=\"dict_type\"   />\r\n\t\t<result property=\"status\"     column=\"status\"      />\r\n\t\t<result property=\"createBy\"   column=\"create_by\"   />\r\n\t\t<result property=\"createTime\" column=\"create_time\" />\r\n\t\t<result property=\"updateBy\"   column=\"update_by\"   />\r\n\t\t<result property=\"updateTime\" column=\"update_time\" />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectDictTypeVo\">\r\n        select dict_id, dict_name, dict_type, status, create_by, create_time, remark \r\n\t\tfrom sys_dict_type\r\n    </sql>\r\n\r\n\t<select id=\"selectDictTypeList\" parameterType=\"SysDictType\" resultMap=\"SysDictTypeResult\">\r\n\t    <include refid=\"selectDictTypeVo\"/>\r\n\t\t<where>\r\n\t\t    <if test=\"dictName != null and dictName != ''\">\r\n\t\t\t\tAND dict_name like concat('%', #{dictName}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"status != null and status != ''\">\r\n\t\t\t\tAND status = #{status}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"dictType != null and dictType != ''\">\r\n\t\t\t\tAND dict_type like concat('%', #{dictType}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.beginTime != null and params.beginTime != ''\"><!-- 开始时间检索 -->\r\n\t\t\t\tand date_format(create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.endTime != null and params.endTime != ''\"><!-- 结束时间检索 -->\r\n\t\t\t\tand date_format(create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')\r\n\t\t\t</if>\r\n\t    </where>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDictTypeAll\" resultMap=\"SysDictTypeResult\">\r\n\t\t<include refid=\"selectDictTypeVo\"/>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDictTypeById\" parameterType=\"Long\" resultMap=\"SysDictTypeResult\">\r\n\t\t<include refid=\"selectDictTypeVo\"/>\r\n\t\twhere dict_id = #{dictId}\r\n\t</select>\r\n\t\r\n\t<select id=\"selectDictTypeByType\" parameterType=\"String\" resultMap=\"SysDictTypeResult\">\r\n\t\t<include refid=\"selectDictTypeVo\"/>\r\n\t\twhere dict_type = #{dictType}\r\n\t</select>\r\n\t\r\n\t<select id=\"checkDictTypeUnique\" parameterType=\"String\" resultMap=\"SysDictTypeResult\">\r\n\t\t<include refid=\"selectDictTypeVo\"/>\r\n\t\twhere dict_type = #{dictType} limit 1\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteDictTypeById\" parameterType=\"Long\">\r\n \t\tdelete from sys_dict_type where dict_id = #{dictId}\r\n \t</delete>\r\n\t\r\n\t<delete id=\"deleteDictTypeByIds\" parameterType=\"Long\">\r\n \t\tdelete from sys_dict_type where dict_id in\r\n \t\t<foreach collection=\"array\" item=\"dictId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{dictId}\r\n        </foreach> \r\n \t</delete>\r\n\r\n \t<update id=\"updateDictType\" parameterType=\"SysDictType\">\r\n \t\tupdate sys_dict_type\r\n \t\t<set>\r\n \t\t\t<if test=\"dictName != null and dictName != ''\">dict_name = #{dictName},</if>\r\n \t\t\t<if test=\"dictType != null and dictType != ''\">dict_type = #{dictType},</if>\r\n \t\t\t<if test=\"status != null\">status = #{status},</if>\r\n \t\t\t<if test=\"remark != null\">remark = #{remark},</if>\r\n \t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\tupdate_time = sysdate()\r\n \t\t</set>\r\n \t\twhere dict_id = #{dictId}\r\n\t</update>\r\n \t\r\n \t<insert id=\"insertDictType\" parameterType=\"SysDictType\">\r\n \t\tinsert into sys_dict_type(\r\n \t\t\t<if test=\"dictName != null and dictName != ''\">dict_name,</if>\r\n \t\t\t<if test=\"dictType != null and dictType != ''\">dict_type,</if>\r\n \t\t\t<if test=\"status != null\">status,</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t\t<if test=\"dictName != null and dictName != ''\">#{dictName},</if>\r\n \t\t\t<if test=\"dictType != null and dictType != ''\">#{dictType},</if>\r\n \t\t\t<if test=\"status != null\">#{status},</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\t\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysLogininforMapper\">\r\n\r\n\t<resultMap type=\"SysLogininfor\" id=\"SysLogininforResult\">\r\n\t\t<id     property=\"infoId\"        column=\"info_id\"           />\r\n\t\t<result property=\"loginName\"     column=\"login_name\"        />\r\n\t\t<result property=\"status\"        column=\"status\"            />\r\n\t\t<result property=\"ipaddr\"        column=\"ipaddr\"            />\r\n\t\t<result property=\"loginLocation\" column=\"login_location\"    />\r\n\t\t<result property=\"browser\"       column=\"browser\"           />\r\n\t\t<result property=\"os\"            column=\"os\"                />\r\n\t\t<result property=\"msg\"           column=\"msg\"               />\r\n\t\t<result property=\"loginTime\"     column=\"login_time\"        />\r\n\t</resultMap>\r\n\r\n\t<insert id=\"insertLogininfor\" parameterType=\"SysLogininfor\">\r\n\t\tinsert into sys_logininfor (login_name, status, ipaddr, login_location, browser, os, msg, login_time)\r\n\t\tvalues (#{loginName}, #{status}, #{ipaddr}, #{loginLocation}, #{browser}, #{os}, #{msg}, sysdate())\r\n\t</insert>\r\n\t\r\n\t<select id=\"selectLogininforList\" parameterType=\"SysLogininfor\" resultMap=\"SysLogininforResult\">\r\n\t\tselect info_id,login_name,ipaddr,login_location,browser,os,status,msg,login_time from sys_logininfor\r\n\t\t<where>\r\n\t\t\t<if test=\"ipaddr != null and ipaddr != ''\">\r\n\t\t\t\tAND ipaddr like concat('%', #{ipaddr}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"status != null and status != ''\">\r\n\t\t\t\tAND status = #{status}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"loginName != null and loginName != ''\">\r\n\t\t\t\tAND login_name like concat('%', #{loginName}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.beginTime != null and params.beginTime != ''\"><!-- 开始时间检索 -->\r\n\t\t\t\tAND login_time &gt;= #{params.beginTime}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.endTime != null and params.endTime != ''\"><!-- 结束时间检索 -->\r\n\t\t\t\tAND login_time &lt;= #{params.endTime}\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteLogininforByIds\" parameterType=\"String\">\r\n \t\tdelete from sys_logininfor where info_id in\r\n \t\t<foreach collection=\"array\" item=\"infoId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{infoId}\r\n        </foreach> \r\n \t</delete>\r\n    \r\n    <update id=\"cleanLogininfor\">\r\n        truncate table sys_logininfor\r\n    </update>\r\n    \r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\n\t\tPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\t\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysMenuMapper\">\r\n\r\n\t<resultMap type=\"SysMenu\" id=\"SysMenuResult\">\r\n\t\t<id     property=\"menuId\"         column=\"menu_id\"        />\r\n\t\t<result property=\"menuName\"       column=\"menu_name\"      />\r\n\t\t<result property=\"parentName\"     column=\"parent_name\"    />\r\n\t\t<result property=\"parentId\"       column=\"parent_id\"      />\r\n\t\t<result property=\"orderNum\"       column=\"order_num\"      />\r\n\t\t<result property=\"url\"            column=\"url\"            />\r\n\t\t<result property=\"target\"         column=\"target\"         />\r\n\t\t<result property=\"menuType\"       column=\"menu_type\"      />\r\n\t\t<result property=\"visible\"        column=\"visible\"        />\r\n\t\t<result property=\"isRefresh\"      column=\"is_refresh\"     />\r\n\t\t<result property=\"perms\"          column=\"perms\"          />\r\n\t\t<result property=\"icon\"           column=\"icon\"           />\r\n\t\t<result property=\"createBy\"       column=\"create_by\"      />\r\n\t\t<result property=\"createTime\"     column=\"create_time\"    />\r\n\t\t<result property=\"updateTime\"     column=\"update_time\"    />\r\n\t\t<result property=\"updateBy\"       column=\"update_by\"      />\r\n\t\t<result property=\"remark\"         column=\"remark\"         />\r\n\t</resultMap>\r\n\r\n\t<sql id=\"selectMenuVo\">\r\n        select menu_id, menu_name, parent_id, order_num, url, target, menu_type, visible, is_refresh, ifnull(perms,'') as perms, icon, create_by, create_time \r\n\t\tfrom sys_menu\r\n    </sql>\r\n\r\n\t<select id=\"selectMenusByUserId\" parameterType=\"Long\" resultMap=\"SysMenuResult\">\r\n\t\tselect distinct m.menu_id, m.parent_id, m.menu_name, m.url, m.visible, m.is_refresh, ifnull(m.perms,'') as perms, m.target, m.menu_type, m.icon, m.order_num, m.create_time\r\n\t\tfrom sys_menu m\r\n\t\t\t left join sys_role_menu rm on m.menu_id = rm.menu_id\r\n\t\t\t left join sys_user_role ur on rm.role_id = ur.role_id\r\n\t\t\t LEFT JOIN sys_role ro on ur.role_id = ro.role_id\r\n\t\twhere ur.user_id = #{userId} and m.menu_type in ('M', 'C') and m.visible = 0  AND ro.status = 0\r\n\t\torder by m.parent_id, m.order_num\r\n\t</select>\r\n\r\n\t<select id=\"selectMenuNormalAll\" resultMap=\"SysMenuResult\">\r\n\t\tselect distinct m.menu_id, m.parent_id, m.menu_name, m.url, m.visible, m.is_refresh, ifnull(m.perms,'') as perms, m.target, m.menu_type, m.icon, m.order_num, m.create_time\r\n\t\tfrom sys_menu m\r\n\t\twhere m.menu_type in ('M', 'C') and m.visible = 0\r\n\t\torder by m.parent_id, m.order_num\r\n\t</select>\r\n\r\n\t<select id=\"selectMenuAll\" resultMap=\"SysMenuResult\">\r\n\t\t<include refid=\"selectMenuVo\"/>\r\n\t\torder by parent_id, order_num\r\n\t</select>\r\n\r\n\t<select id=\"selectMenuAllByUserId\" parameterType=\"Long\" resultMap=\"SysMenuResult\">\r\n\t\tselect distinct m.menu_id, m.parent_id, m.menu_name, m.url, m.visible, m.is_refresh, ifnull(m.perms,'') as perms, m.target, m.menu_type, m.icon, m.order_num, m.create_time\r\n\t\tfrom sys_menu m\r\n\t\t\t left join sys_role_menu rm on m.menu_id = rm.menu_id\r\n\t\t\t left join sys_user_role ur on rm.role_id = ur.role_id\r\n\t\t\t LEFT JOIN sys_role ro on ur.role_id = ro.role_id\r\n\t\twhere ur.user_id = #{userId}\r\n\t\torder by m.parent_id, m.order_num\r\n\t</select>\r\n\r\n\t<select id=\"selectPermsByUserId\" parameterType=\"Long\" resultType=\"String\">\r\n\t\tselect distinct m.perms\r\n\t\tfrom sys_menu m\r\n\t\t\t left join sys_role_menu rm on m.menu_id = rm.menu_id\r\n\t\t\t left join sys_user_role ur on rm.role_id = ur.role_id\r\n\t\t\t left join sys_role r on r.role_id = ur.role_id\r\n\t\twhere m.visible = '0' and r.status = '0' and ur.user_id = #{userId}\r\n\t</select>\r\n\r\n\t<select id=\"selectPermsByRoleId\" parameterType=\"Long\" resultType=\"String\">\r\n\t\tselect distinct m.perms\r\n\t\tfrom sys_menu m\r\n\t\t\t left join sys_role_menu rm on m.menu_id = rm.menu_id\r\n\t\twhere m.visible = '0' and rm.role_id = #{roleId}\r\n\t</select>\r\n\r\n\t<select id=\"selectMenuTree\" parameterType=\"Long\" resultType=\"String\">\r\n\t\tselect concat(m.menu_id, ifnull(m.perms,'')) as perms\r\n\t\tfrom sys_menu m\r\n\t\t\tleft join sys_role_menu rm on m.menu_id = rm.menu_id\r\n\t\twhere rm.role_id = #{roleId}\r\n\t\torder by m.parent_id, m.order_num\r\n\t</select>\r\n\r\n\t<select id=\"selectMenuList\" parameterType=\"SysMenu\" resultMap=\"SysMenuResult\">\r\n\t\t<include refid=\"selectMenuVo\"/>\r\n\t\t<where>\r\n\t\t\t<if test=\"menuName != null and menuName != ''\">\r\n\t\t\t\tAND menu_name like concat('%', #{menuName}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"visible != null and visible != ''\">\r\n\t\t\t\tAND visible = #{visible}\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t\torder by parent_id, order_num\r\n\t</select>\r\n\r\n\t<select id=\"selectMenuListByUserId\" parameterType=\"SysMenu\" resultMap=\"SysMenuResult\">\r\n\t\tselect distinct m.menu_id, m.parent_id, m.menu_name, m.url, m.visible, m.is_refresh, ifnull(m.perms,'') as perms, m.target, m.menu_type, m.icon, m.order_num, m.create_time\r\n\t\tfrom sys_menu m\r\n\t\tleft join sys_role_menu rm on m.menu_id = rm.menu_id\r\n\t\tleft join sys_user_role ur on rm.role_id = ur.role_id\r\n\t\tLEFT JOIN sys_role ro on ur.role_id = ro.role_id\r\n\t\twhere ur.user_id = #{params.userId}\r\n\t\t<if test=\"menuName != null and menuName != ''\">\r\n\t\t\tAND m.menu_name like concat('%', #{menuName}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"visible != null and visible != ''\">\r\n\t\t\tAND m.visible = #{visible}\r\n\t\t</if>\r\n\t\torder by m.parent_id, m.order_num\r\n\t</select>\r\n\r\n\t<delete id=\"deleteMenuById\" parameterType=\"Long\">\r\n\t    delete from sys_menu where menu_id = #{menuId} or parent_id = #{menuId}\r\n\t</delete>\r\n\r\n\t<select id=\"selectMenuById\" parameterType=\"Long\" resultMap=\"SysMenuResult\">\r\n\t\tSELECT t.menu_id, t.parent_id, t.menu_name, t.order_num, t.url, t.target, t.menu_type, t.visible, t.is_refresh, t.perms, t.icon, t.remark,\r\n\t\t\t(SELECT menu_name FROM sys_menu WHERE menu_id = t.parent_id) parent_name\r\n\t\tFROM sys_menu t\r\n\t\twhere t.menu_id = #{menuId}\r\n\t</select>\r\n\r\n\t<select id=\"selectCountMenuByParentId\" resultType=\"Integer\">\r\n\t    select count(1) from sys_menu where parent_id=#{menuId}  \r\n\t</select>\r\n\r\n\t<select id=\"checkMenuNameUnique\" parameterType=\"SysMenu\" resultMap=\"SysMenuResult\">\r\n\t\t<include refid=\"selectMenuVo\"/>\r\n\t\twhere menu_name=#{menuName} and parent_id = #{parentId} limit 1\r\n\t</select>\r\n\r\n\t<update id=\"updateMenu\" parameterType=\"SysMenu\">\r\n\t\tupdate sys_menu\r\n\t\t<set>\r\n\t\t\t<if test=\"menuName != null and menuName != ''\">menu_name = #{menuName},</if>\r\n\t\t\t<if test=\"parentId != null and parentId != 0\">parent_id = #{parentId},</if>\r\n\t\t\t<if test=\"orderNum != null\">order_num = #{orderNum},</if>\r\n\t\t\t<if test=\"url != null\">url = #{url},</if>\r\n\t\t\t<if test=\"target != null and target != ''\">target = #{target},</if>\r\n\t\t\t<if test=\"menuType != null and menuType != ''\">menu_type = #{menuType},</if>\r\n\t\t\t<if test=\"visible != null\">visible = #{visible},</if>\r\n\t\t\t<if test=\"isRefresh != null\">is_refresh = #{isRefresh},</if>\r\n\t\t\t<if test=\"perms !=null\">perms = #{perms},</if>\r\n\t\t\t<if test=\"icon !=null and icon != ''\">icon = #{icon},</if>\r\n\t\t\t<if test=\"remark != null\">remark = #{remark},</if>\r\n\t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n\t\t\tupdate_time = sysdate()\r\n\t\t</set>\r\n\t\twhere menu_id = #{menuId}\r\n\t</update>\r\n\r\n\t<insert id=\"insertMenu\" parameterType=\"SysMenu\">\r\n\t\tinsert into sys_menu(\r\n\t\t<if test=\"menuId != null and menuId != 0\">menu_id,</if>\r\n\t\t<if test=\"parentId != null and parentId != 0\">parent_id,</if>\r\n\t\t<if test=\"menuName != null and menuName != ''\">menu_name,</if>\r\n\t\t<if test=\"orderNum != null\">order_num,</if>\r\n\t\t<if test=\"url != null and url != ''\">url,</if>\r\n\t\t<if test=\"target != null and target != ''\">target,</if>\r\n\t\t<if test=\"menuType != null and menuType != ''\">menu_type,</if>\r\n\t\t<if test=\"visible != null\">visible,</if>\r\n\t\t<if test=\"isRefresh != null\">is_refresh,</if>\r\n\t\t<if test=\"perms !=null and perms != ''\">perms,</if>\r\n\t\t<if test=\"icon != null and icon != ''\">icon,</if>\r\n\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n\t\tcreate_time\r\n\t\t)values(\r\n\t\t<if test=\"menuId != null and menuId != 0\">#{menuId},</if>\r\n\t\t<if test=\"parentId != null and parentId != 0\">#{parentId},</if>\r\n\t\t<if test=\"menuName != null and menuName != ''\">#{menuName},</if>\r\n\t\t<if test=\"orderNum != null\">#{orderNum},</if>\r\n\t\t<if test=\"url != null and url != ''\">#{url},</if>\r\n\t\t<if test=\"target != null and target != ''\">#{target},</if>\r\n\t\t<if test=\"menuType != null and menuType != ''\">#{menuType},</if>\r\n\t\t<if test=\"visible != null\">#{visible},</if>\r\n\t\t<if test=\"isRefresh != null\">#{isRefresh},</if>\r\n\t\t<if test=\"perms !=null and perms != ''\">#{perms},</if>\r\n\t\t<if test=\"icon != null and icon != ''\">#{icon},</if>\r\n\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n\t\tsysdate()\r\n\t\t)\r\n\t</insert>\r\n\r\n\t<update id=\"updateMenuSort\" parameterType=\"SysMenu\">\r\n\t    update sys_menu\r\n\t    set order_num = #{orderNum}\r\n\t    where menu_id = #{menuId}\r\n\t</update>\r\n\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysNoticeMapper\">\r\n    \r\n    <resultMap type=\"SysNotice\" id=\"SysNoticeResult\">\r\n        <result property=\"noticeId\"       column=\"notice_id\"       />\r\n        <result property=\"noticeTitle\"    column=\"notice_title\"    />\r\n        <result property=\"noticeType\"     column=\"notice_type\"     />\r\n        <result property=\"noticeContent\"  column=\"notice_content\"  />\r\n        <result property=\"status\"         column=\"status\"          />\r\n        <result property=\"createBy\"       column=\"create_by\"       />\r\n        <result property=\"createTime\"     column=\"create_time\"     />\r\n        <result property=\"updateBy\"       column=\"update_by\"       />\r\n        <result property=\"updateTime\"     column=\"update_time\"     />\r\n        <result property=\"remark\"         column=\"remark\"          />\r\n    </resultMap>\r\n    \r\n    <sql id=\"selectNoticeVo\">\r\n        select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark \r\n\t\tfrom sys_notice\r\n    </sql>\r\n    \r\n    <select id=\"selectNoticeById\" parameterType=\"Long\" resultMap=\"SysNoticeResult\">\r\n        <include refid=\"selectNoticeVo\"/>\r\n        where notice_id = #{noticeId}\r\n    </select>\r\n    \r\n    <select id=\"selectNoticeList\" parameterType=\"SysNotice\" resultMap=\"SysNoticeResult\">\r\n        <include refid=\"selectNoticeVo\"/>\r\n        <where>\r\n\t\t\t<if test=\"noticeTitle != null and noticeTitle != ''\">\r\n\t\t\t\tAND notice_title like concat('%', #{noticeTitle}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"noticeType != null and noticeType != ''\">\r\n\t\t\t\tAND notice_type = #{noticeType}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"createBy != null and createBy != ''\">\r\n\t\t\t\tAND create_by like concat('%', #{createBy}, '%')\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t\torder by notice_id desc\r\n    </select>\r\n    \r\n    <insert id=\"insertNotice\" parameterType=\"SysNotice\">\r\n        insert into sys_notice (\r\n\t\t\t<if test=\"noticeTitle != null and noticeTitle != '' \">notice_title, </if>\r\n\t\t\t<if test=\"noticeType != null and noticeType != '' \">notice_type, </if>\r\n\t\t\t<if test=\"noticeContent != null and noticeContent != '' \">notice_content, </if>\r\n\t\t\t<if test=\"status != null and status != '' \">status, </if>\r\n\t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n\t\t\t<if test=\"noticeTitle != null and noticeTitle != ''\">#{noticeTitle}, </if>\r\n\t\t\t<if test=\"noticeType != null and noticeType != ''\">#{noticeType}, </if>\r\n\t\t\t<if test=\"noticeContent != null and noticeContent != ''\">#{noticeContent}, </if>\r\n\t\t\t<if test=\"status != null and status != ''\">#{status}, </if>\r\n\t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\tsysdate()\r\n\t\t)\r\n    </insert>\r\n\t \r\n    <update id=\"updateNotice\" parameterType=\"SysNotice\">\r\n        update sys_notice \r\n        <set>\r\n            <if test=\"noticeTitle != null and noticeTitle != ''\">notice_title = #{noticeTitle}, </if>\r\n            <if test=\"noticeType != null and noticeType != ''\">notice_type = #{noticeType}, </if>\r\n            <if test=\"noticeContent != null\">notice_content = #{noticeContent}, </if>\r\n            <if test=\"status != null and status != ''\">status = #{status}, </if>\r\n            <if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\tupdate_time = sysdate()\r\n        </set>\r\n        where notice_id = #{noticeId}\r\n    </update>\r\n\t\r\n    <delete id=\"deleteNoticeByIds\" parameterType=\"String\">\r\n        delete from sys_notice where notice_id in \r\n        <foreach item=\"noticeId\" collection=\"array\" open=\"(\" separator=\",\" close=\")\">\r\n            #{noticeId}\r\n        </foreach>\r\n    </delete>\r\n    \r\n</mapper>"
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysNoticeReadMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.ruoyi.system.mapper.SysNoticeReadMapper\">\n\n    <resultMap type=\"SysNoticeRead\" id=\"SysNoticeReadResult\">\n        <id     property=\"readId\"   column=\"read_id\"     />\n        <result property=\"noticeId\" column=\"notice_id\"   />\n        <result property=\"userId\"   column=\"user_id\"     />\n        <result property=\"readTime\" column=\"read_time\"   />\n    </resultMap>\n\n    <!-- 新增已读记录 -->\n    <insert id=\"insertNoticeRead\" parameterType=\"SysNoticeRead\">\n        insert ignore into sys_notice_read (notice_id, user_id, read_time)\n        values (#{noticeId}, #{userId}, sysdate())\n    </insert>\n\n    <!-- 查询未读数量：正常状态公告 减去 当前用户已读数 -->\n    <select id=\"selectUnreadCount\" resultType=\"int\">\n        select count(*) from sys_notice n\n        where n.status = '0' and not exists (select 1 from sys_notice_read r where r.notice_id = n.notice_id and r.user_id = #{userId})\n    </select>\n\n    <!-- 查询是否已读 -->\n    <select id=\"selectIsRead\" resultType=\"int\">\n        select count(*) from sys_notice_read where notice_id = #{noticeId} and user_id = #{userId}\n    </select>\n\n    <!-- 查询带已读状态的公告列表（直接在SQL中限制条数） -->\n    <select id=\"selectNoticeListWithReadStatus\" resultType=\"SysNotice\">\n        select\n            n.notice_id    as noticeId,\n            n.notice_title as noticeTitle,\n            n.notice_type  as noticeType,\n            n.status,\n            n.create_by    as createBy,\n            n.create_time  as createTime,\n            case when r.notice_id is not null then true else false end as isRead\n        from sys_notice n\n        left join sys_notice_read r\n            on r.notice_id = n.notice_id and r.user_id = #{userId}\n        where n.status = '0'\n        order by n.notice_id desc\n        limit #{limit}\n    </select>\n\n    <!-- 批量标记已读 -->\n    <insert id=\"insertNoticeReadBatch\">\n        insert ignore into sys_notice_read (notice_id, user_id, read_time)\n        values\n        <foreach collection=\"noticeIds\" item=\"noticeId\" separator=\",\">\n            (#{noticeId}, #{userId}, sysdate())\n        </foreach>\n    </insert>\n\n    <!-- 删除公告时清理已读记录 -->\n    <delete id=\"deleteByNoticeIds\">\n        delete from sys_notice_read where notice_id in\n        <foreach collection=\"noticeIds\" item=\"noticeId\" open=\"(\" separator=\",\" close=\")\">\n            #{noticeId}\n        </foreach>\n    </delete>\n\n</mapper>\n"
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysOperLogMapper\">\r\n\r\n\t<resultMap type=\"SysOperLog\" id=\"SysOperLogResult\">\r\n\t\t<id     property=\"operId\"         column=\"oper_id\"        />\r\n\t\t<result property=\"title\"          column=\"title\"          />\r\n\t\t<result property=\"businessType\"   column=\"business_type\"  />\r\n\t\t<result property=\"method\"         column=\"method\"         />\r\n\t\t<result property=\"requestMethod\"  column=\"request_method\" />\r\n\t\t<result property=\"operatorType\"   column=\"operator_type\"  />\r\n\t\t<result property=\"operName\"       column=\"oper_name\"      />\r\n\t\t<result property=\"deptName\"       column=\"dept_name\"      />\r\n\t\t<result property=\"operUrl\"        column=\"oper_url\"       />\r\n\t\t<result property=\"operIp\"         column=\"oper_ip\"        />\r\n\t\t<result property=\"operLocation\"   column=\"oper_location\"  />\r\n\t\t<result property=\"operParam\"      column=\"oper_param\"     />\r\n\t\t<result property=\"jsonResult\"     column=\"json_result\"    />\r\n\t\t<result property=\"status\"         column=\"status\"         />\r\n\t\t<result property=\"errorMsg\"       column=\"error_msg\"      />\r\n\t\t<result property=\"operTime\"       column=\"oper_time\"      />\r\n\t\t<result property=\"costTime\"       column=\"cost_time\"      />\r\n\t</resultMap>\r\n\r\n\t<sql id=\"selectOperLogVo\">\r\n        select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time, cost_time\r\n        from sys_oper_log\r\n    </sql>\r\n    \r\n\t<insert id=\"insertOperlog\" parameterType=\"SysOperLog\">\r\n\t\tinsert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, cost_time, oper_time)\r\n        values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate())\r\n\t</insert>\r\n\t\r\n\t<select id=\"selectOperLogList\" parameterType=\"SysOperLog\" resultMap=\"SysOperLogResult\">\r\n\t\t<include refid=\"selectOperLogVo\"/>\r\n\t\t<where>\r\n\t\t\t<if test=\"operIp != null and operIp != ''\">\r\n\t\t\t\tAND oper_ip like concat('%', #{operIp}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"title != null and title != ''\">\r\n\t\t\t\tAND title like concat('%', #{title}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"businessType != null\">\r\n\t\t\t\tAND business_type = #{businessType}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"businessTypes != null and businessTypes.length > 0\">\r\n\t\t\t    AND business_type in\r\n\t\t\t    <foreach collection=\"businessTypes\" item=\"businessType\" open=\"(\" separator=\",\" close=\")\">\r\n\t\t \t\t\t#{businessType}\r\n\t\t        </foreach> \r\n\t\t\t</if>\r\n\t\t\t<if test=\"status != null\">\r\n\t\t\t\tAND status = #{status}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"operName != null and operName != ''\">\r\n\t\t\t\tAND oper_name like concat('%', #{operName}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.beginTime != null and params.beginTime != ''\"><!-- 开始时间检索 -->\r\n\t\t\t\tAND oper_time &gt;= #{params.beginTime}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"params.endTime != null and params.endTime != ''\"><!-- 结束时间检索 -->\r\n\t\t\t\tAND oper_time &lt;= #{params.endTime}\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteOperLogByIds\" parameterType=\"String\">\r\n \t\tdelete from sys_oper_log where oper_id in\r\n \t\t<foreach collection=\"array\" item=\"operId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{operId}\r\n        </foreach> \r\n \t</delete>\r\n \t\r\n \t<select id=\"selectOperLogById\" parameterType=\"Long\" resultMap=\"SysOperLogResult\">\r\n\t\t<include refid=\"selectOperLogVo\"/>\r\n\t\twhere oper_id = #{operId}\r\n\t</select>\r\n\t\r\n\t<update id=\"cleanOperLog\">\r\n        truncate table sys_oper_log\r\n    </update>\r\n\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysPostMapper\">\r\n\r\n\t<resultMap type=\"SysPost\" id=\"SysPostResult\">\r\n\t\t<id     property=\"postId\"        column=\"post_id\"       />\r\n\t\t<result property=\"postCode\"      column=\"post_code\"     />\r\n\t\t<result property=\"postName\"      column=\"post_name\"     />\r\n\t\t<result property=\"postSort\"      column=\"post_sort\"     />\r\n\t\t<result property=\"status\"        column=\"status\"        />\r\n\t\t<result property=\"createBy\"      column=\"create_by\"     />\r\n\t\t<result property=\"createTime\"    column=\"create_time\"   />\r\n\t\t<result property=\"updateBy\"      column=\"update_by\"     />\r\n\t\t<result property=\"updateTime\"    column=\"update_time\"   />\r\n\t\t<result property=\"remark\"        column=\"remark\"        />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectPostVo\">\r\n        select post_id, post_code, post_name, post_sort, status, create_by, create_time, remark \r\n\t\tfrom sys_post\r\n    </sql>\r\n\t\r\n\t<select id=\"selectPostList\" parameterType=\"SysPost\" resultMap=\"SysPostResult\">\r\n\t    <include refid=\"selectPostVo\"/>\r\n\t\t<where>\r\n\t\t\t<if test=\"postCode != null and postCode != ''\">\r\n\t\t\t\tAND post_code like concat('%', #{postCode}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"status != null and status != ''\">\r\n\t\t\t\tAND status = #{status}\r\n\t\t\t</if>\r\n\t\t\t<if test=\"postName != null and postName != ''\">\r\n\t\t\t\tAND post_name like concat('%', #{postName}, '%')\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectPostAll\" resultMap=\"SysPostResult\">\r\n\t\t<include refid=\"selectPostVo\"/>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectPostsByUserId\" parameterType=\"Long\" resultMap=\"SysPostResult\">\r\n\t\tSELECT p.post_id, p.post_name, p.post_code\r\n\t\tFROM sys_user u\r\n\t\t\t LEFT JOIN sys_user_post up ON u.user_id = up.user_id\r\n\t\t\t LEFT JOIN sys_post p ON up.post_id = p.post_id\r\n\t\tWHERE up.user_id = #{userId}\r\n\t</select>\r\n\t\r\n\t<select id=\"selectPostById\" parameterType=\"Long\" resultMap=\"SysPostResult\">\r\n\t\t<include refid=\"selectPostVo\"/>\r\n\t\twhere post_id = #{postId}\r\n\t</select>\r\n\t\r\n\t<select id=\"checkPostNameUnique\" parameterType=\"String\" resultMap=\"SysPostResult\">\r\n\t\t<include refid=\"selectPostVo\"/>\r\n\t\t where post_name=#{postName} limit 1\r\n\t</select>\r\n\t\r\n\t<select id=\"checkPostCodeUnique\" parameterType=\"String\" resultMap=\"SysPostResult\">\r\n\t\t<include refid=\"selectPostVo\"/>\r\n\t\t where post_code=#{postCode} limit 1\r\n\t</select>\r\n\t\r\n \t<delete id=\"deletePostByIds\" parameterType=\"Long\">\r\n \t\tdelete from sys_post where post_id in\r\n \t\t<foreach collection=\"array\" item=\"postId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{postId}\r\n        </foreach> \r\n \t</delete>\r\n \t\r\n \t<update id=\"updatePost\" parameterType=\"SysPost\">\r\n \t\tupdate sys_post\r\n \t\t<set>\r\n \t\t\t<if test=\"postCode != null and postCode != ''\">post_code = #{postCode},</if>\r\n \t\t\t<if test=\"postName != null and postName != ''\">post_name = #{postName},</if>\r\n \t\t\t<if test=\"postSort != null and postSort != ''\">post_sort = #{postSort},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status = #{status},</if>\r\n \t\t\t<if test=\"remark != null\">remark = #{remark},</if>\r\n \t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\tupdate_time = sysdate()\r\n \t\t</set>\r\n \t\twhere post_id = #{postId}\r\n\t</update>\r\n \t\r\n \t<insert id=\"insertPost\" parameterType=\"SysPost\" useGeneratedKeys=\"true\" keyProperty=\"postId\">\r\n \t\tinsert into sys_post(\r\n \t\t\t<if test=\"postId != null and postId != 0\">post_id,</if>\r\n \t\t\t<if test=\"postCode != null and postCode != ''\">post_code,</if>\r\n \t\t\t<if test=\"postName != null and postName != ''\">post_name,</if>\r\n \t\t\t<if test=\"postSort != null and postSort != ''\">post_sort,</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status,</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t\t<if test=\"postId != null and postId != 0\">#{postId},</if>\r\n \t\t\t<if test=\"postCode != null and postCode != ''\">#{postCode},</if>\r\n \t\t\t<if test=\"postName != null and postName != ''\">#{postName},</if>\r\n \t\t\t<if test=\"postSort != null and postSort != ''\">#{postSort},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">#{status},</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysRoleDeptMapper\">\r\n\r\n\t<resultMap type=\"SysRoleDept\" id=\"SysRoleDeptResult\">\r\n\t\t<result property=\"roleId\"     column=\"role_id\"      />\r\n\t\t<result property=\"deptId\"     column=\"dept_id\"      />\r\n\t</resultMap>\r\n\r\n\t<delete id=\"deleteRoleDeptByRoleId\" parameterType=\"Long\">\r\n\t\tdelete from sys_role_dept where role_id=#{roleId}\r\n\t</delete>\r\n\t\r\n\t<select id=\"selectCountRoleDeptByDeptId\" resultType=\"Integer\">\r\n\t    select count(1) from sys_role_dept where dept_id=#{deptId}\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteRoleDept\" parameterType=\"Long\">\r\n \t\tdelete from sys_role_dept where role_id in\r\n \t\t<foreach collection=\"array\" item=\"roleId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{roleId}\r\n        </foreach> \r\n \t</delete>\r\n\t\r\n\t<insert id=\"batchRoleDept\">\r\n\t\tinsert into sys_role_dept(role_id, dept_id) values\r\n\t\t<foreach item=\"item\" index=\"index\" collection=\"list\" separator=\",\">\r\n\t\t\t(#{item.roleId},#{item.deptId})\r\n\t\t</foreach>\r\n\t</insert>\r\n\t\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysRoleMapper\">\r\n\r\n\t<resultMap type=\"SysRole\" id=\"SysRoleResult\">\r\n\t\t<id     property=\"roleId\"       column=\"role_id\"        />\r\n\t\t<result property=\"roleName\"     column=\"role_name\"      />\r\n\t\t<result property=\"roleKey\"      column=\"role_key\"       />\r\n\t\t<result property=\"roleSort\"     column=\"role_sort\"      />\r\n\t\t<result property=\"dataScope\"    column=\"data_scope\"     />\r\n\t\t<result property=\"status\"       column=\"status\"         />\r\n\t\t<result property=\"delFlag\"      column=\"del_flag\"       />\r\n\t\t<result property=\"createBy\"     column=\"create_by\"      />\r\n\t\t<result property=\"createTime\"   column=\"create_time\"    />\r\n\t\t<result property=\"updateBy\"     column=\"update_by\"      />\r\n\t\t<result property=\"updateTime\"   column=\"update_time\"    />\r\n\t\t<result property=\"remark\"       column=\"remark\"         />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectRoleContactVo\">\r\n        select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope,\r\n            r.status, r.del_flag, r.create_time, r.remark \r\n        from sys_role r\r\n\t        left join sys_user_role ur on ur.role_id = r.role_id\r\n\t        left join sys_user u on u.user_id = ur.user_id\r\n\t        left join sys_dept d on u.dept_id = d.dept_id\r\n    </sql>\r\n    \r\n    <sql id=\"selectRoleVo\">\r\n\t\tselect r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status, r.del_flag, r.create_time, r.create_by, r.update_by, r.update_time, r.remark \r\n        from sys_role r\r\n\t</sql>\r\n\t\r\n\t<select id=\"selectRoleList\" parameterType=\"SysRole\" resultMap=\"SysRoleResult\">\r\n\t\t<include refid=\"selectRoleContactVo\"/>\r\n\t\twhere r.del_flag = '0'\r\n\t\t<if test=\"roleId != null and roleId != 0\">\r\n\t\t\tAND r.role_id = #{roleId}\r\n\t\t</if>\r\n\t\t<if test=\"roleName != null and roleName != ''\">\r\n\t\t\tAND r.role_name like concat('%', #{roleName}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"status != null and status != ''\">\r\n\t\t\tAND r.status = #{status}\r\n\t\t</if>\r\n\t\t<if test=\"roleKey != null and roleKey != ''\">\r\n\t\t\tAND r.role_key like concat('%', #{roleKey}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"dataScope != null and dataScope != ''\">\r\n\t\t\tAND r.data_scope = #{dataScope}\r\n\t\t</if>\r\n\t\t<if test=\"params.beginTime != null and params.beginTime != ''\"><!-- 开始时间检索 -->\r\n\t\t\tand date_format(r.create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')\r\n\t\t</if>\r\n\t\t<if test=\"params.endTime != null and params.endTime != ''\"><!-- 结束时间检索 -->\r\n\t\t\tand date_format(r.create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')\r\n\t\t</if>\r\n\t\t<!-- 数据范围过滤 -->\r\n\t\t${params.dataScope}\r\n\t</select>\r\n\r\n\t<select id=\"selectRolesByUserId\" parameterType=\"Long\" resultMap=\"SysRoleResult\">\r\n\t\t<include refid=\"selectRoleContactVo\"/>\r\n\t\tWHERE r.del_flag = '0' and ur.user_id = #{userId}\r\n\t</select>\r\n\t\r\n\t<select id=\"selectRoleById\" parameterType=\"Long\" resultMap=\"SysRoleResult\">\r\n\t\t<include refid=\"selectRoleVo\"/>\r\n\t\twhere r.del_flag = '0' and r.role_id = #{roleId}\r\n\t</select>\r\n\t\r\n\t<select id=\"checkRoleNameUnique\" parameterType=\"String\" resultMap=\"SysRoleResult\">\r\n\t\t<include refid=\"selectRoleVo\"/>\r\n\t\t where r.role_name=#{roleName} and r.del_flag = '0' limit 1\r\n\t</select>\r\n\t\r\n\t<select id=\"checkRoleKeyUnique\" parameterType=\"String\" resultMap=\"SysRoleResult\">\r\n\t\t<include refid=\"selectRoleVo\"/>\r\n\t\t where r.role_key=#{roleKey} and r.del_flag = '0' limit 1\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteRoleById\" parameterType=\"Long\">\r\n \t\tupdate sys_role set del_flag = '2' where role_id = #{roleId}\r\n \t</delete>\r\n \t\r\n \t<delete id=\"deleteRoleByIds\" parameterType=\"Long\">\r\n \t    update sys_role set del_flag = '2' where role_id in\r\n \t\t<foreach collection=\"array\" item=\"roleId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{roleId}\r\n        </foreach> \r\n \t</delete>\r\n \t\r\n \t<update id=\"updateRole\" parameterType=\"SysRole\">\r\n \t\tupdate sys_role\r\n \t\t<set>\r\n \t\t\t<if test=\"roleName != null and roleName != ''\">role_name = #{roleName},</if>\r\n \t\t\t<if test=\"roleKey != null and roleKey != ''\">role_key = #{roleKey},</if>\r\n \t\t\t<if test=\"roleSort != null and roleSort != ''\">role_sort = #{roleSort},</if>\r\n \t\t\t<if test=\"dataScope != null and dataScope != ''\">data_scope = #{dataScope},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status = #{status},</if>\r\n \t\t\t<if test=\"remark != null\">remark = #{remark},</if>\r\n \t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\tupdate_time = sysdate()\r\n \t\t</set>\r\n \t\twhere role_id = #{roleId}\r\n\t</update>\r\n \t\r\n \t<insert id=\"insertRole\" parameterType=\"SysRole\" useGeneratedKeys=\"true\" keyProperty=\"roleId\">\r\n \t\tinsert into sys_role(\r\n \t\t\t<if test=\"roleId != null and roleId != 0\">role_id,</if>\r\n \t\t\t<if test=\"roleName != null and roleName != ''\">role_name,</if>\r\n \t\t\t<if test=\"roleKey != null and roleKey != ''\">role_key,</if>\r\n \t\t\t<if test=\"roleSort != null and roleSort != ''\">role_sort,</if>\r\n \t\t\t<if test=\"dataScope != null and dataScope != ''\">data_scope,</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status,</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t\t<if test=\"roleId != null and roleId != 0\">#{roleId},</if>\r\n \t\t\t<if test=\"roleName != null and roleName != ''\">#{roleName},</if>\r\n \t\t\t<if test=\"roleKey != null and roleKey != ''\">#{roleKey},</if>\r\n \t\t\t<if test=\"roleSort != null and roleSort != ''\">#{roleSort},</if>\r\n \t\t\t<if test=\"dataScope != null and dataScope != ''\">#{dataScope},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">#{status},</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\t\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysRoleMenuMapper\">\r\n\r\n\t<resultMap type=\"SysRoleMenu\" id=\"SysRoleMenuResult\">\r\n\t\t<result property=\"roleId\"     column=\"role_id\"      />\r\n\t\t<result property=\"menuId\"     column=\"menu_id\"      />\r\n\t</resultMap>\r\n\r\n\t<delete id=\"deleteRoleMenuByRoleId\" parameterType=\"Long\">\r\n\t\tdelete from sys_role_menu where role_id=#{roleId}\r\n\t</delete>\r\n\t\r\n\t<select id=\"selectCountRoleMenuByMenuId\" resultType=\"Integer\">\r\n\t    select count(1) from sys_role_menu where menu_id=#{menuId}  \r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteRoleMenu\" parameterType=\"Long\">\r\n \t\tdelete from sys_role_menu where role_id in\r\n \t\t<foreach collection=\"array\" item=\"roleId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{roleId}\r\n        </foreach> \r\n \t</delete>\r\n\t\r\n\t<insert id=\"batchRoleMenu\">\r\n\t\tinsert into sys_role_menu(role_id, menu_id) values\r\n\t\t<foreach item=\"item\" index=\"index\" collection=\"list\" separator=\",\">\r\n\t\t\t(#{item.roleId},#{item.menuId})\r\n\t\t</foreach>\r\n\t</insert>\r\n\t\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysUserMapper\">\r\n\r\n\t<resultMap type=\"SysUser\" id=\"SysUserResult\">\r\n\t\t<id     property=\"userId\"        column=\"user_id\"         />\r\n\t\t<result property=\"deptId\"        column=\"dept_id\"         />\r\n\t\t<result property=\"loginName\"     column=\"login_name\"      />\r\n\t\t<result property=\"userName\"      column=\"user_name\"       />\r\n\t\t<result property=\"userType\"      column=\"user_type\"       />\r\n\t\t<result property=\"email\"         column=\"email\"           />\r\n\t\t<result property=\"phonenumber\"   column=\"phonenumber\"     />\r\n\t\t<result property=\"sex\"           column=\"sex\"             />\r\n\t\t<result property=\"avatar\"        column=\"avatar\"          />\r\n\t\t<result property=\"password\"      column=\"password\"        />\r\n\t\t<result property=\"salt\"          column=\"salt\"            />\r\n\t\t<result property=\"status\"        column=\"status\"          />\r\n\t\t<result property=\"delFlag\"       column=\"del_flag\"        />\r\n\t\t<result property=\"loginIp\"       column=\"login_ip\"        />\r\n\t\t<result property=\"loginDate\"     column=\"login_date\"      />\r\n\t\t<result property=\"pwdUpdateDate\" column=\"pwd_update_date\" />\r\n\t\t<result property=\"createBy\"      column=\"create_by\"       />\r\n\t\t<result property=\"createTime\"    column=\"create_time\"     />\r\n\t\t<result property=\"updateBy\"      column=\"update_by\"       />\r\n\t\t<result property=\"updateTime\"    column=\"update_time\"     />\r\n\t\t<result property=\"remark\"        column=\"remark\"          />\r\n\t\t<association property=\"dept\"     javaType=\"SysDept\"         resultMap=\"deptResult\" />\r\n\t\t<collection  property=\"roles\"    javaType=\"java.util.List\"  resultMap=\"RoleResult\" />\r\n\t</resultMap>\r\n\t\r\n\t<resultMap id=\"deptResult\" type=\"SysDept\">\r\n\t\t<id     property=\"deptId\"    column=\"dept_id\"     />\r\n\t\t<result property=\"parentId\"  column=\"parent_id\"   />\r\n\t\t<result property=\"deptName\"  column=\"dept_name\"   />\r\n\t\t<result property=\"ancestors\" column=\"ancestors\"   />\r\n\t\t<result property=\"orderNum\"  column=\"order_num\"   />\r\n\t\t<result property=\"leader\"    column=\"leader\"      />\r\n\t\t<result property=\"status\"    column=\"dept_status\" />\r\n\t</resultMap>\r\n\t\r\n\t<resultMap id=\"RoleResult\" type=\"SysRole\">\r\n\t\t<id     property=\"roleId\"       column=\"role_id\"        />\r\n\t\t<result property=\"roleName\"     column=\"role_name\"      />\r\n\t\t<result property=\"roleKey\"      column=\"role_key\"       />\r\n\t\t<result property=\"roleSort\"     column=\"role_sort\"      />\r\n\t\t<result property=\"dataScope\"    column=\"data_scope\"     />\r\n\t\t<result property=\"status\"       column=\"role_status\"    />\r\n\t</resultMap>\r\n\t\r\n\t<sql id=\"selectUserVo\">\r\n        select  u.user_id, u.dept_id, u.login_name, u.user_name, u.user_type, u.email, u.avatar, u.phonenumber, u.sex, u.password, u.salt, u.status, u.del_flag, u.login_ip, u.login_date, u.pwd_update_date, u.create_by, u.create_time, u.update_by, u.update_time, u.remark,\r\n       \t\t    d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,\r\n       \t\t    r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status\r\n\t\tfrom sys_user u\r\n\t\t\t left join sys_dept d on u.dept_id = d.dept_id\r\n\t\t\t left join sys_user_role ur on u.user_id = ur.user_id\r\n\t\t\t left join sys_role r on r.role_id = ur.role_id\r\n    </sql>\r\n\t\r\n\t<select id=\"selectUserList\" parameterType=\"SysUser\" resultMap=\"SysUserResult\">\r\n\t\tselect u.user_id, u.dept_id, u.login_name, u.user_name, u.user_type, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.salt, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u\r\n\t\tleft join sys_dept d on u.dept_id = d.dept_id\r\n\t\twhere u.del_flag = '0'\r\n\t\t<if test=\"userId != null and userId != 0\">\r\n\t\t\tAND u.user_id = #{userId}\r\n\t\t</if>\r\n\t\t<if test=\"loginName != null and loginName != ''\">\r\n\t\t\tAND u.login_name like concat('%', #{loginName}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"status != null and status != ''\">\r\n\t\t\tAND u.status = #{status}\r\n\t\t</if>\r\n\t\t<if test=\"phonenumber != null and phonenumber != ''\">\r\n\t\t\tAND u.phonenumber like concat('%', #{phonenumber}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"params.beginTime != null and params.beginTime != ''\"><!-- 开始时间检索 -->\r\n\t\t\tAND date_format(u.create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')\r\n\t\t</if>\r\n\t\t<if test=\"params.endTime != null and params.endTime != ''\"><!-- 结束时间检索 -->\r\n\t\t\tAND date_format(u.create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')\r\n\t\t</if>\r\n\t\t<if test=\"deptId != null and deptId != 0\">\r\n\t\t\tAND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE FIND_IN_SET (#{deptId},ancestors) ))\r\n\t\t</if>\r\n\t\t<!-- 数据范围过滤 -->\r\n\t\t${params.dataScope}\r\n\t</select>\r\n\t\r\n\t<select id=\"selectAllocatedList\" parameterType=\"SysUser\" resultMap=\"SysUserResult\">\r\n\t    select distinct u.user_id, u.dept_id, u.login_name, u.user_name, u.user_type, u.email, u.avatar, u.phonenumber, u.status, u.create_time\r\n\t    from sys_user u\r\n\t\t\t left join sys_dept d on u.dept_id = d.dept_id\r\n\t\t\t left join sys_user_role ur on u.user_id = ur.user_id\r\n\t\t\t left join sys_role r on r.role_id = ur.role_id\r\n\t    where u.del_flag = '0' and r.role_id = #{roleId}\r\n\t    <if test=\"loginName != null and loginName != ''\">\r\n\t\t\tAND u.login_name like concat('%', #{loginName}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"phonenumber != null and phonenumber != ''\">\r\n\t\t\tAND u.phonenumber like concat('%', #{phonenumber}, '%')\r\n\t\t</if>\r\n\t\t<!-- 数据范围过滤 -->\r\n\t\t${params.dataScope}\r\n\t</select>\r\n\t\r\n\t<select id=\"selectUnallocatedList\" parameterType=\"SysUser\" resultMap=\"SysUserResult\">\r\n\t    select distinct u.user_id, u.dept_id, u.login_name, u.user_name, u.user_type, u.email, u.avatar, u.phonenumber, u.status, u.create_time\r\n\t    from sys_user u\r\n\t\t\t left join sys_dept d on u.dept_id = d.dept_id\r\n\t\t\t left join sys_user_role ur on u.user_id = ur.user_id\r\n\t\t\t left join sys_role r on r.role_id = ur.role_id\r\n\t    where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL)\r\n\t    and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{roleId})\r\n\t    <if test=\"loginName != null and loginName != ''\">\r\n\t\t\tAND u.login_name like concat('%', #{loginName}, '%')\r\n\t\t</if>\r\n\t\t<if test=\"phonenumber != null and phonenumber != ''\">\r\n\t\t\tAND u.phonenumber like concat('%', #{phonenumber}, '%')\r\n\t\t</if>\r\n\t\t<!-- 数据范围过滤 -->\r\n\t\t${params.dataScope}\r\n\t</select>\r\n\t\r\n\t<select id=\"selectUserByLoginName\" parameterType=\"String\" resultMap=\"SysUserResult\">\r\n\t    <include refid=\"selectUserVo\"/>\r\n\t\twhere u.login_name = #{userName} and u.del_flag = '0'\r\n\t</select>\r\n\t\r\n\t<select id=\"selectUserByPhoneNumber\" parameterType=\"String\" resultMap=\"SysUserResult\">\r\n\t\t<include refid=\"selectUserVo\"/>\r\n\t\twhere u.phonenumber = #{phonenumber} and u.del_flag = '0'\r\n\t</select>\r\n\t\r\n\t<select id=\"selectUserByEmail\" parameterType=\"String\" resultMap=\"SysUserResult\">\r\n\t    <include refid=\"selectUserVo\"/>\r\n\t\twhere u.email = #{email} and u.del_flag = '0'\r\n\t</select>\r\n\t\r\n\t<select id=\"checkLoginNameUnique\" parameterType=\"String\" resultMap=\"SysUserResult\">\r\n\t\tselect user_id, login_name from sys_user where login_name=#{loginName} and del_flag = '0' limit 1\r\n\t</select>\r\n\t\r\n\t<select id=\"checkPhoneUnique\" parameterType=\"String\" resultMap=\"SysUserResult\">\r\n\t\tselect user_id, phonenumber from sys_user where phonenumber=#{phonenumber} and del_flag = '0' limit 1\r\n\t</select>\r\n\t\r\n\t<select id=\"checkEmailUnique\" parameterType=\"String\" resultMap=\"SysUserResult\">\r\n\t\tselect user_id, email from sys_user where email=#{email} and del_flag = '0' limit 1\r\n\t</select>\r\n\t\r\n\t<select id=\"selectUserById\" parameterType=\"Long\" resultMap=\"SysUserResult\">\r\n\t\t<include refid=\"selectUserVo\"/>\r\n\t\twhere u.user_id = #{userId}\r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteUserById\" parameterType=\"Long\">\r\n \t\tupdate sys_user set del_flag = '2' where user_id = #{userId}\r\n \t</delete>\r\n \t\r\n \t<delete id=\"deleteUserByIds\" parameterType=\"Long\">\r\n \t\tupdate sys_user set del_flag = '2' where user_id in\r\n \t\t<foreach collection=\"array\" item=\"userId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{userId}\r\n        </foreach> \r\n \t</delete>\r\n \t\r\n  \t<update id=\"updateUserAvatar\" parameterType=\"SysUser\">\r\n \t\tupdate sys_user set avatar = #{avatar} where user_id = #{userId}\r\n\t</update>\r\n\t\r\n\t<update id=\"resetUserPwd\" parameterType=\"SysUser\">\r\n \t\tupdate sys_user SET pwd_update_date = sysdate(), password = #{password}, salt = #{salt}, update_time = sysdate() where user_id = #{userId}\r\n\t</update>\r\n\t\r\n\t<update id=\"updateUserStatus\" parameterType=\"SysUser\">\r\n \t\tupdate sys_user SET status = #{status}, update_time = sysdate() where user_id = #{userId}\r\n\t</update>\r\n\t\r\n  \t<update id=\"updateLoginInfo\" parameterType=\"SysUser\">\r\n \t\tupdate sys_user set login_ip = #{loginIp}, login_date = #{loginDate} where user_id = #{userId}\r\n\t</update>\r\n \t\r\n \t<update id=\"updateUser\" parameterType=\"SysUser\">\r\n \t\tupdate sys_user\r\n \t\t<set>\r\n \t\t\t<if test=\"deptId != 0\">dept_id = #{deptId},</if>\r\n \t\t\t<if test=\"userName != null and userName != ''\">user_name = #{userName},</if>\r\n \t\t\t<if test=\"userType != null and userType != ''\">user_type = #{userType},</if>\r\n \t\t\t<if test=\"email != null and email != ''\">email = #{email},</if>\r\n \t\t\t<if test=\"phonenumber != null and phonenumber != ''\">phonenumber = #{phonenumber},</if>\r\n \t\t\t<if test=\"sex != null and sex != ''\">sex = #{sex},</if>\r\n \t\t\t<if test=\"avatar != null and avatar != ''\">avatar = #{avatar},</if>\r\n \t\t\t<if test=\"password != null and password != ''\">password = #{password},</if>\r\n \t\t\t<if test=\"salt != null and salt != ''\">salt = #{salt},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status = #{status},</if>\r\n \t\t\t<if test=\"loginIp != null and loginIp != ''\">login_ip = #{loginIp},</if>\r\n \t\t\t<if test=\"loginDate != null\">login_date = #{loginDate},</if>\r\n \t\t\t<if test=\"pwdUpdateDate != null\">pwd_update_date = #{pwdUpdateDate},</if>\r\n \t\t\t<if test=\"updateBy != null and updateBy != ''\">update_by = #{updateBy},</if>\r\n \t\t\t<if test=\"remark != null\">remark = #{remark},</if>\r\n \t\t\tupdate_time = sysdate()\r\n \t\t</set>\r\n \t\twhere user_id = #{userId}\r\n\t</update>\r\n \t\r\n \t<insert id=\"insertUser\" parameterType=\"SysUser\" useGeneratedKeys=\"true\" keyProperty=\"userId\">\r\n \t\tinsert into sys_user(\r\n \t\t\t<if test=\"userId != null and userId != 0\">user_id,</if>\r\n \t\t\t<if test=\"deptId != null and deptId != 0\">dept_id,</if>\r\n \t\t\t<if test=\"loginName != null and loginName != ''\">login_name,</if>\r\n \t\t\t<if test=\"userName != null and userName != ''\">user_name,</if>\r\n \t\t\t<if test=\"userType != null and userType != ''\">user_type,</if>\r\n \t\t\t<if test=\"email != null and email != ''\">email,</if>\r\n \t\t\t<if test=\"avatar != null and avatar != ''\">avatar,</if>\r\n \t\t\t<if test=\"phonenumber != null and phonenumber != ''\">phonenumber,</if>\r\n \t\t\t<if test=\"sex != null and sex != ''\">sex,</if>\r\n \t\t\t<if test=\"password != null and password != ''\">password,</if>\r\n \t\t\t<if test=\"salt != null and salt != ''\">salt,</if>\r\n \t\t\t<if test=\"status != null and status != ''\">status,</if>\r\n \t\t\t<if test=\"pwdUpdateDate != null\">pwd_update_date,</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">create_by,</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">remark,</if>\r\n \t\t\tcreate_time\r\n \t\t)values(\r\n \t\t\t<if test=\"userId != null and userId != ''\">#{userId},</if>\r\n \t\t\t<if test=\"deptId != null and deptId != ''\">#{deptId},</if>\r\n \t\t\t<if test=\"loginName != null and loginName != ''\">#{loginName},</if>\r\n \t\t\t<if test=\"userName != null and userName != ''\">#{userName},</if>\r\n \t\t\t<if test=\"userType != null and userType != ''\">#{userType},</if>\r\n \t\t\t<if test=\"email != null and email != ''\">#{email},</if>\r\n \t\t\t<if test=\"avatar != null and avatar != ''\">#{avatar},</if>\r\n \t\t\t<if test=\"phonenumber != null and phonenumber != ''\">#{phonenumber},</if>\r\n \t\t\t<if test=\"sex != null and sex != ''\">#{sex},</if>\r\n \t\t\t<if test=\"password != null and password != ''\">#{password},</if>\r\n \t\t\t<if test=\"salt != null and salt != ''\">#{salt},</if>\r\n \t\t\t<if test=\"status != null and status != ''\">#{status},</if>\r\n \t\t\t<if test=\"pwdUpdateDate != null\">#{pwdUpdateDate},</if>\r\n \t\t\t<if test=\"createBy != null and createBy != ''\">#{createBy},</if>\r\n \t\t\t<if test=\"remark != null and remark != ''\">#{remark},</if>\r\n \t\t\tsysdate()\r\n \t\t)\r\n\t</insert>\r\n\t\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysUserOnlineMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysUserOnlineMapper\">\r\n\r\n\t<resultMap type=\"SysUserOnline\" id=\"SysUserOnlineResult\">\r\n\t\t<id     property=\"sessionId\"         column=\"sessionId\"         />\r\n\t\t<result property=\"loginName\"         column=\"login_name\"        />\r\n\t\t<result property=\"deptName\"          column=\"dept_name\"         />\r\n\t\t<result property=\"ipaddr\"            column=\"ipaddr\"            />\r\n\t\t<result property=\"loginLocation\"     column=\"login_location\"    />\r\n\t\t<result property=\"browser\"           column=\"browser\"           />\r\n\t\t<result property=\"os\"                column=\"os\"                />\r\n\t\t<result property=\"status\"            column=\"status\"            />\r\n\t\t<result property=\"startTimestamp\"    column=\"start_timestamp\"   />\r\n\t\t<result property=\"lastAccessTime\"    column=\"last_access_time\"  />\r\n\t\t<result property=\"expireTime\"        column=\"expire_time\"       />\r\n\t\t<result property=\"sessionData\"       column=\"session_data\"      />\r\n\t</resultMap>\r\n\r\n\t<sql id=\"selectOnlineVo\">\r\n       select sessionId, login_name, dept_name, ipaddr, login_location, browser, os, status, start_timestamp, last_access_time, expire_time, session_data\r\n\t   from sys_user_online\r\n    </sql>\r\n    \r\n\t<select id=\"selectOnlineById\" parameterType=\"String\" resultMap=\"SysUserOnlineResult\">\r\n\t\t<include refid=\"selectOnlineVo\"/>\r\n\t\twhere sessionId = #{sessionId}\r\n\t</select>\r\n\r\n\t<insert id=\"saveOnline\" parameterType=\"SysUserOnline\">\r\n\t\treplace into sys_user_online(sessionId, login_name, dept_name, ipaddr, login_location, browser, os, status, start_timestamp, last_access_time, expire_time, session_data)\r\n        values (#{sessionId}, #{loginName}, #{deptName}, #{ipaddr}, #{loginLocation}, #{browser}, #{os}, #{status}, #{startTimestamp}, #{lastAccessTime}, #{expireTime}, #{sessionData,jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler})\r\n\t</insert>\r\n\t\r\n \t<delete id=\"deleteOnlineById\" parameterType=\"String\">\r\n \t\tdelete from sys_user_online where sessionId = #{sessionId}\r\n \t</delete>\r\n \t\r\n \t<select id=\"selectUserOnlineList\" parameterType=\"SysUserOnline\" resultMap=\"SysUserOnlineResult\">\r\n\t\t<include refid=\"selectOnlineVo\"/>\r\n\t\t<where>\r\n\t\t\t<if test=\"ipaddr != null and ipaddr != ''\">\r\n\t\t\t\tAND ipaddr like concat('%', #{ipaddr}, '%')\r\n\t\t\t</if>\r\n\t\t\t<if test=\"loginName != null and loginName != ''\">\r\n\t\t\t\tAND login_name like concat('%', #{loginName}, '%')\r\n\t\t\t</if>\r\n\t\t</where>\r\n\t</select>\r\n\t\r\n\t<select id=\"selectOnlineByExpired\" parameterType=\"String\" resultMap=\"SysUserOnlineResult\">\r\n\t\t<include refid=\"selectOnlineVo\"/> o \r\n\t\tWHERE o.last_access_time <![CDATA[ <= ]]> #{lastAccessTime} ORDER BY o.last_access_time ASC\r\n\t</select>\r\n\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysUserPostMapper\">\r\n\r\n\t<resultMap type=\"SysUserPost\" id=\"SysUserPostResult\">\r\n\t\t<result property=\"userId\"     column=\"user_id\"      />\r\n\t\t<result property=\"postId\"     column=\"post_id\"      />\r\n\t</resultMap>\r\n\r\n\t<delete id=\"deleteUserPostByUserId\" parameterType=\"Long\">\r\n\t\tdelete from sys_user_post where user_id=#{userId}\r\n\t</delete>\r\n\t\r\n\t<select id=\"countUserPostById\" resultType=\"Integer\">\r\n\t    select count(1) from sys_user_post where post_id=#{postId}  \r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteUserPost\" parameterType=\"Long\">\r\n \t\tdelete from sys_user_post where user_id in\r\n \t\t<foreach collection=\"array\" item=\"userId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{userId}\r\n        </foreach> \r\n \t</delete>\r\n\t\r\n\t<insert id=\"batchUserPost\">\r\n\t\tinsert into sys_user_post(user_id, post_id) values\r\n\t\t<foreach item=\"item\" index=\"index\" collection=\"list\" separator=\",\">\r\n\t\t\t(#{item.userId},#{item.postId})\r\n\t\t</foreach>\r\n\t</insert>\r\n\t\r\n</mapper> "
  },
  {
    "path": "ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<!DOCTYPE mapper\r\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\r\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n<mapper namespace=\"com.ruoyi.system.mapper.SysUserRoleMapper\">\r\n\r\n\t<resultMap type=\"SysUserRole\" id=\"SysUserRoleResult\">\r\n\t\t<result property=\"userId\"     column=\"user_id\"      />\r\n\t\t<result property=\"roleId\"     column=\"role_id\"      />\r\n\t</resultMap>\r\n\t\r\n\t<select id=\"selectUserRoleByUserId\" parameterType=\"Long\" resultMap=\"SysUserRoleResult\">\r\n\t\tselect user_id, role_id from sys_user_role where user_id = #{userId}\r\n\t</select>\r\n\r\n\t<delete id=\"deleteUserRoleByUserId\" parameterType=\"Long\">\r\n\t\tdelete from sys_user_role where user_id = #{userId}\r\n\t</delete>\r\n\t\r\n\t<select id=\"countUserRoleByRoleId\" resultType=\"Integer\">\r\n\t    select count(1) from sys_user_role where role_id = #{roleId}  \r\n\t</select>\r\n\t\r\n\t<delete id=\"deleteUserRole\" parameterType=\"Long\">\r\n \t\tdelete from sys_user_role where user_id in\r\n \t\t<foreach collection=\"array\" item=\"userId\" open=\"(\" separator=\",\" close=\")\">\r\n \t\t\t#{userId}\r\n        </foreach> \r\n \t</delete>\r\n\t\r\n\t<insert id=\"batchUserRole\">\r\n\t\tinsert into sys_user_role(user_id, role_id) values\r\n\t\t<foreach item=\"item\" index=\"index\" collection=\"list\" separator=\",\">\r\n\t\t\t(#{item.userId},#{item.roleId})\r\n\t\t</foreach>\r\n\t</insert>\r\n\t\r\n\t<delete id=\"deleteUserRoleInfo\" parameterType=\"SysUserRole\">\r\n\t\tdelete from sys_user_role where user_id=#{userId} and role_id=#{roleId}\r\n\t</delete>\r\n\t\r\n\t<delete id=\"deleteUserRoleInfos\">\r\n\t    delete from sys_user_role where role_id=#{roleId} and user_id in\r\n \t    <foreach collection=\"userIds\" item=\"userId\" open=\"(\" separator=\",\" close=\")\">\r\n \t        #{userId}\r\n            </foreach> \r\n\t</delete>\r\n</mapper> "
  },
  {
    "path": "ry.bat",
    "content": "@echo off\r\n\r\nrem jarƽĿ¼\r\nset AppName=ruoyi-admin.jar\r\n\r\nrem JVM\r\nset JVM_OPTS=\"-Dname=%AppName%  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC\"\r\n\r\n\r\nECHO.\r\n\tECHO.  [1] %AppName%\r\n\tECHO.  [2] ر%AppName%\r\n\tECHO.  [3] %AppName%\r\n\tECHO.  [4] ״̬ %AppName%\r\n\tECHO.  [5]  \r\nECHO.\r\n\r\nECHO.ѡĿ:\r\nset /p ID=\r\n\tIF \"%id%\"==\"1\" GOTO start\r\n\tIF \"%id%\"==\"2\" GOTO stop\r\n\tIF \"%id%\"==\"3\" GOTO restart\r\n\tIF \"%id%\"==\"4\" GOTO status\r\n\tIF \"%id%\"==\"5\" EXIT\r\nPAUSE\r\n:start\r\n    for /f \"usebackq tokens=1-2\" %%a in (`jps -l ^| findstr %AppName%`) do (\r\n\t\tset pid=%%a\r\n\t\tset image_name=%%b\r\n\t)\r\n\tif  defined pid (\r\n\t\techo %%is running\r\n\t\tPAUSE\r\n\t)\r\n\r\nstart javaw %JVM_OPTS% -jar %AppName%\r\n\r\necho  starting\r\necho  Start %AppName% success...\r\ngoto:eof\r\n\r\nrem stopͨjpspid\r\n:stop\r\n\tfor /f \"usebackq tokens=1-2\" %%a in (`jps -l ^| findstr %AppName%`) do (\r\n\t\tset pid=%%a\r\n\t\tset image_name=%%b\r\n\t)\r\n\tif not defined pid (echo process %AppName% does not exists) else (\r\n\t\techo prepare to kill %image_name%\r\n\t\techo start kill %pid% ...\r\n\t\trem ݽIDkill\r\n\t\ttaskkill /f /pid %pid%\r\n\t)\r\ngoto:eof\r\n:restart\r\n\tcall :stop\r\n    call :start\r\ngoto:eof\r\n:status\r\n\tfor /f \"usebackq tokens=1-2\" %%a in (`jps -l ^| findstr %AppName%`) do (\r\n\t\tset pid=%%a\r\n\t\tset image_name=%%b\r\n\t)\r\n\tif not defined pid (echo process %AppName% is dead ) else (\r\n\t\techo %image_name% is running\r\n\t)\r\ngoto:eof\r\n"
  },
  {
    "path": "ry.sh",
    "content": "#!/bin/sh\n# ./ry.sh start 启动 stop 停止 restart 重启 status 状态\nAppName=ruoyi-admin.jar\n\n# JVM参数\nJVM_OPTS=\"-Dname=$AppName  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC\"\nAPP_HOME=`pwd`\nLOG_PATH=$APP_HOME/logs/$AppName.log\n\nif [ \"$1\" = \"\" ];\nthen\n    echo -e \"\\033[0;31m 未输入操作名 \\033[0m  \\033[0;34m {start|stop|restart|status} \\033[0m\"\n    exit 1\nfi\n\nif [ \"$AppName\" = \"\" ];\nthen\n    echo -e \"\\033[0;31m 未输入应用名 \\033[0m\"\n    exit 1\nfi\n\nfunction start()\n{\n    PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`\n\n\tif [ x\"$PID\" != x\"\" ]; then\n\t    echo \"$AppName is running...\"\n\telse\n\t\tnohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 &\n\t\techo \"Start $AppName success...\"\n\tfi\n}\n\nfunction stop()\n{\n    echo \"Stop $AppName\"\n\n\tPID=\"\"\n\tquery(){\n\t\tPID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`\n\t}\n\n\tquery\n\tif [ x\"$PID\" != x\"\" ]; then\n\t\tkill -TERM $PID\n\t\techo \"$AppName (pid:$PID) exiting...\"\n\t\twhile [ x\"$PID\" != x\"\" ]\n\t\tdo\n\t\t\tsleep 1\n\t\t\tquery\n\t\tdone\n\t\techo \"$AppName exited.\"\n\telse\n\t\techo \"$AppName already stopped.\"\n\tfi\n}\n\nfunction restart()\n{\n    stop\n    sleep 2\n    start\n}\n\nfunction status()\n{\n    PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`\n    if [ $PID != 0 ];then\n        echo \"$AppName is running...\"\n    else\n        echo \"$AppName is not running...\"\n    fi\n}\n\ncase $1 in\n    start)\n    start;;\n    stop)\n    stop;;\n    restart)\n    restart;;\n    status)\n    status;;\n    *)\n\nesac\n"
  },
  {
    "path": "sql/quartz.sql",
    "content": "DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\r\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\r\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\r\nDROP TABLE IF EXISTS QRTZ_LOCKS;\r\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\r\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\r\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\r\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\r\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\r\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\r\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\r\n\r\n-- ----------------------------\r\n-- 1、存储每一个已配置的 jobDetail 的详细信息\r\n-- ----------------------------\r\ncreate table QRTZ_JOB_DETAILS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    job_name             varchar(200)    not null            comment '任务名称',\r\n    job_group            varchar(200)    not null            comment '任务组名',\r\n    description          varchar(250)    null                comment '相关介绍',\r\n    job_class_name       varchar(250)    not null            comment '执行任务类名称',\r\n    is_durable           varchar(1)      not null            comment '是否持久化',\r\n    is_nonconcurrent     varchar(1)      not null            comment '是否并发',\r\n    is_update_data       varchar(1)      not null            comment '是否更新数据',\r\n    requests_recovery    varchar(1)      not null            comment '是否接受恢复执行',\r\n    job_data             blob            null                comment '存放持久化job对象',\r\n    primary key (sched_name, job_name, job_group)\r\n) engine=innodb comment = '任务详细信息表';\r\n\r\n-- ----------------------------\r\n-- 2、 存储已配置的 Trigger 的信息\r\n-- ----------------------------\r\ncreate table QRTZ_TRIGGERS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    trigger_name         varchar(200)    not null            comment '触发器的名字',\r\n    trigger_group        varchar(200)    not null            comment '触发器所属组的名字',\r\n    job_name             varchar(200)    not null            comment 'qrtz_job_details表job_name的外键',\r\n    job_group            varchar(200)    not null            comment 'qrtz_job_details表job_group的外键',\r\n    description          varchar(250)    null                comment '相关介绍',\r\n    next_fire_time       bigint(13)      null                comment '上一次触发时间（毫秒）',\r\n    prev_fire_time       bigint(13)      null                comment '下一次触发时间（默认为-1表示不触发）',\r\n    priority             integer         null                comment '优先级',\r\n    trigger_state        varchar(16)     not null            comment '触发器状态',\r\n    trigger_type         varchar(8)      not null            comment '触发器的类型',\r\n    start_time           bigint(13)      not null            comment '开始时间',\r\n    end_time             bigint(13)      null                comment '结束时间',\r\n    calendar_name        varchar(200)    null                comment '日程表名称',\r\n    misfire_instr        smallint(2)     null                comment '补偿执行的策略',\r\n    job_data             blob            null                comment '存放持久化job对象',\r\n    primary key (sched_name, trigger_name, trigger_group),\r\n    foreign key (sched_name, job_name, job_group) references QRTZ_JOB_DETAILS(sched_name, job_name, job_group)\r\n) engine=innodb comment = '触发器详细信息表';\r\n\r\n-- ----------------------------\r\n-- 3、 存储简单的 Trigger，包括重复次数，间隔，以及已触发的次数\r\n-- ----------------------------\r\ncreate table QRTZ_SIMPLE_TRIGGERS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',\r\n    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',\r\n    repeat_count         bigint(7)       not null            comment '重复的次数统计',\r\n    repeat_interval      bigint(12)      not null            comment '重复的间隔时间',\r\n    times_triggered      bigint(10)      not null            comment '已经触发的次数',\r\n    primary key (sched_name, trigger_name, trigger_group),\r\n    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)\r\n) engine=innodb comment = '简单触发器的信息表';\r\n\r\n-- ----------------------------\r\n-- 4、 存储 Cron Trigger，包括 Cron 表达式和时区信息\r\n-- ---------------------------- \r\ncreate table QRTZ_CRON_TRIGGERS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',\r\n    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',\r\n    cron_expression      varchar(200)    not null            comment 'cron表达式',\r\n    time_zone_id         varchar(80)                         comment '时区',\r\n    primary key (sched_name, trigger_name, trigger_group),\r\n    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)\r\n) engine=innodb comment = 'Cron类型的触发器表';\r\n\r\n-- ----------------------------\r\n-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型，JobStore 并不知道如何存储实例的时候)\r\n-- ---------------------------- \r\ncreate table QRTZ_BLOB_TRIGGERS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',\r\n    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',\r\n    blob_data            blob            null                comment '存放持久化Trigger对象',\r\n    primary key (sched_name, trigger_name, trigger_group),\r\n    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)\r\n) engine=innodb comment = 'Blob类型的触发器表';\r\n\r\n-- ----------------------------\r\n-- 6、 以 Blob 类型存储存放日历信息， quartz可配置一个日历来指定一个时间范围\r\n-- ---------------------------- \r\ncreate table QRTZ_CALENDARS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    calendar_name        varchar(200)    not null            comment '日历名称',\r\n    calendar             blob            not null            comment '存放持久化calendar对象',\r\n    primary key (sched_name, calendar_name)\r\n) engine=innodb comment = '日历信息表';\r\n\r\n-- ----------------------------\r\n-- 7、 存储已暂停的 Trigger 组的信息\r\n-- ---------------------------- \r\ncreate table QRTZ_PAUSED_TRIGGER_GRPS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',\r\n    primary key (sched_name, trigger_group)\r\n) engine=innodb comment = '暂停的触发器表';\r\n\r\n-- ----------------------------\r\n-- 8、 存储与已触发的 Trigger 相关的状态信息，以及相联 Job 的执行信息\r\n-- ---------------------------- \r\ncreate table QRTZ_FIRED_TRIGGERS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    entry_id             varchar(95)     not null            comment '调度器实例id',\r\n    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',\r\n    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',\r\n    instance_name        varchar(200)    not null            comment '调度器实例名',\r\n    fired_time           bigint(13)      not null            comment '触发的时间',\r\n    sched_time           bigint(13)      not null            comment '定时器制定的时间',\r\n    priority             integer         not null            comment '优先级',\r\n    state                varchar(16)     not null            comment '状态',\r\n    job_name             varchar(200)    null                comment '任务名称',\r\n    job_group            varchar(200)    null                comment '任务组名',\r\n    is_nonconcurrent     varchar(1)      null                comment '是否并发',\r\n    requests_recovery    varchar(1)      null                comment '是否接受恢复执行',\r\n    primary key (sched_name, entry_id)\r\n) engine=innodb comment = '已触发的触发器表';\r\n\r\n-- ----------------------------\r\n-- 9、 存储少量的有关 Scheduler 的状态信息，假如是用于集群中，可以看到其他的 Scheduler 实例\r\n-- ---------------------------- \r\ncreate table QRTZ_SCHEDULER_STATE (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    instance_name        varchar(200)    not null            comment '实例名称',\r\n    last_checkin_time    bigint(13)      not null            comment '上次检查时间',\r\n    checkin_interval     bigint(13)      not null            comment '检查间隔时间',\r\n    primary key (sched_name, instance_name)\r\n) engine=innodb comment = '调度器状态表';\r\n\r\n-- ----------------------------\r\n-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁)\r\n-- ---------------------------- \r\ncreate table QRTZ_LOCKS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    lock_name            varchar(40)     not null            comment '悲观锁名称',\r\n    primary key (sched_name, lock_name)\r\n) engine=innodb comment = '存储的悲观锁信息表';\r\n\r\n-- ----------------------------\r\n-- 11、 Quartz集群实现同步机制的行锁表\r\n-- ---------------------------- \r\ncreate table QRTZ_SIMPROP_TRIGGERS (\r\n    sched_name           varchar(120)    not null            comment '调度名称',\r\n    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',\r\n    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',\r\n    str_prop_1           varchar(512)    null                comment 'String类型的trigger的第一个参数',\r\n    str_prop_2           varchar(512)    null                comment 'String类型的trigger的第二个参数',\r\n    str_prop_3           varchar(512)    null                comment 'String类型的trigger的第三个参数',\r\n    int_prop_1           int             null                comment 'int类型的trigger的第一个参数',\r\n    int_prop_2           int             null                comment 'int类型的trigger的第二个参数',\r\n    long_prop_1          bigint          null                comment 'long类型的trigger的第一个参数',\r\n    long_prop_2          bigint          null                comment 'long类型的trigger的第二个参数',\r\n    dec_prop_1           numeric(13,4)   null                comment 'decimal类型的trigger的第一个参数',\r\n    dec_prop_2           numeric(13,4)   null                comment 'decimal类型的trigger的第二个参数',\r\n    bool_prop_1          varchar(1)      null                comment 'Boolean类型的trigger的第一个参数',\r\n    bool_prop_2          varchar(1)      null                comment 'Boolean类型的trigger的第二个参数',\r\n    primary key (sched_name, trigger_name, trigger_group),\r\n    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)\r\n) engine=innodb comment = '同步机制的行锁表';\r\n\r\ncommit;"
  },
  {
    "path": "sql/ruoyi.html",
    "content": "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\r\n<!DOCTYPE html>\r\n<html lang='en' xmlns='http://www.w3.org/1999/xhtml' >\r\n<head>\r\n<title>RuoYi</title>\r\n<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css\" integrity=\"sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ\" crossorigin=\"anonymous\">\r\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js\" integrity=\"sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb\" crossorigin=\"anonymous\"></script>\r\n<!--<script src=\"https://code.jquery.com/jquery-3.1.1.slim.min.js\" integrity=\"sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n\" crossorigin=\"anonymous\"></script>-->\r\n<!--<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js\" integrity=\"sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn\" crossorigin=\"anonymous\"></script>-->\r\n<link rel=\"shortcut icon\" href=\"https://www.dbschema.com/images/favicon.ico\">\r\n<style type='text/css'>\r\nbody {\r\n    font-family: 'Segoe UI', 'Lucida sans', Dialog;\r\n    font-size: 13px;\r\n    background-color:#f5f5f5;\r\n    margin: 10px;\r\n}\r\n</style>\r\n</head>\r\n\r\n<body>\r\n<div class='svg-container'>\r\n<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'   width='1890' height='1100' viewBox='0 0 1890 1100' >\r\n  <script type='text/ecmascript'>\r\n  <![CDATA[\r\n  function hghl(el) { for ( var i in el ){ var elem = document.getElementById(el[i]); if ( elem != null ) elem.setAttribute('class','highlight');  }  }\r\n  function uhghl(el) { for ( var i in el ){ var elem = document.getElementById(el[i]); if ( elem != null ) elem.setAttribute('class','scene'); }  } \r\n  ]]>\r\n  </script> \r\n\r\n<style type='text/css'>\r\n  text                { fill:#000000; font-family: SimSun, 'Trebuchet MS', Dialog; font-size:11px; }\r\n  a text:hover        { fill:#94025f; text-shadow: 0px 0px 6px #d0ce00; font-size:13px; }\r\n  text.highlight      { fill:#94025f; text-shadow: 0px 0px 4px #eac533; font-size:13px; }\r\n  text.colType        { fill:#b3b3b3; }\r\n  text.relName        { fill:#b09c7c; }\r\n  path                { stroke:#5c554f; stroke-width:1.15; fill:none; }\r\n  path                { stroke:#5c554f; stroke-width:1.15; fill:none;}\r\n  path.virtual        { stroke:#b7642d; }\r\n  path.logo           { fill:#fbeac0;fill-opacity:1;stroke-width:0.3;stroke:#222222; }\r\n  path.dotted         { stroke-dasharray:4,2; }\r\n  path.scene          { stroke-width:10; opacity:0;}\r\n  path.highlight      { stroke-width:5; stroke:#c1a662; opacity:0.6;}\r\n  rect.entity         { fill:#ffffff; stroke:#aaa; stroke-width:1;shape-rendering:crispEdges;filter:url(#shadow); }\r\n  line.delim          { stroke-width:1; shape-rendering:crispEdges; }\r\n  text.callout        { fill:#000000; font-family: SimSun, 'Trebuchet MS', Dialog; font-size:12px; }\r\n  rect.callout        { fill:url(#calloutGradient); stroke:#bebdbd; stroke-width:0.5; filter: url(#shadow);}\r\n  rect.grp            { stroke:#b1b1b1; stroke-width:1.7; opacity:0.8; }\r\n  path.st0            { fill:#ececec;fill-opacity:1;stroke-width:0.6;stroke:#aaaaaa; }\r\n</style>\r\n<defs>\r\n  <pattern id='layoutBgA' patternUnits='userSpaceOnUse'  width='10' height='20' x='0' y='0' viewBox='0 0 5 10'>  \r\n     <line x1='-2' y1='1' x2='7' y2='10' stroke='#f3f3f3' stroke-width='.5'/>  \r\n     <line x1='-2' y1='6' x2='7' y2='15' stroke='#f3f3f3' stroke-width='.5'/>  \r\n     <line x1='-2' y1='-4' x2='7' y2='5' stroke='#f3f3f3' stroke-width='.5'/>  \r\n  </pattern>  \r\n  <radialGradient id='layoutBgB' gradientUnits='userSpaceOnUse' cx='50%' cy='50%' r='75%' fx='46%' fy='22%'>\r\n     <stop offset='0%' stop-opacity='.2' stop-color='#f5f5f5' />  \r\n     <stop offset='100%' stop-color='#efefef' />  \r\n  </radialGradient>\r\n  <pattern id='layoutBgTr' patternUnits='userSpaceOnUse'  width='300' height='300' x='0' y='0' viewBox='0 0 300 300'>  \r\n  <path class='st0' d='m 62.011835,91.267143 c 3.536475,3.175214 2.262669,8.705999 -1.637711,11.015197 -3.594697,5.8423 -6.34682,-2.892623 -9.715478,-4.653898 -5.609222,-2.838926 2.050802,-6.680123 4.77004,-8.319046 2.334696,-0.724067 4.935143,0.312302 6.583149,1.957747 z m -2.720492,2.538595 c -2.698397,-3.517732 -9.282815,1.269287 -3.69635,3.568637 2.765331,5.605665 7.052809,-0.56184 3.69635,-3.568637 z' />\r\n  <path class='st0' d='m 72.25864,84.624638 c 4.108046,3.143003 -0.737059,6.895259 -1.994918,8.323564 -3.586718,5.561143 -6.495079,-4.197379 -10.07759,-5.582178 -4.443422,-1.088878 1.349298,-7.249213 2.503526,-2.503449 2.464639,4.517161 2.304019,-3.70697 6.291113,-1.995914 1.280083,0.137865 2.410691,0.864819 3.277869,1.757977 z m -2.646109,2.323242 c -4.797162,-3.078383 -2.810517,6.305507 0.515161,1.990646 0.296432,-0.688582 0.01209,-1.493412 -0.515161,-1.990646 z' />\r\n  <path class='st0' d='m 78.230641,79.436735 c 4.142121,3.027466 -2.020102,10.435276 -3.450543,5.477315 3.306312,-5.248112 -9.186019,-2.220094 -5.805994,-8.77679 -0.544141,-3.93011 6.797826,-2.102227 3.386015,0.245477 -0.181085,2.915838 4.637371,1.019311 5.870522,3.053982 z' />\r\n  <path class='st0' d='m 82.744502,72.597397 c -4.901605,1.926521 1.146497,6.285555 2.559694,2.225783 6.21817,3.539297 -6.640186,8.416664 -7.590325,1.997457 -2.24365,-2.914883 4.026676,-10.148618 5.030631,-4.22324 z' />\r\n  <path class='st0' d='m 90.727458,64.259158 c 1.583987,1.690029 3.321317,3.2696 4.81267,5.026353 -2.535706,6.849794 -6.445583,-5.918773 -8.388458,-0.167017 0.782768,2.03426 5.877405,3.752079 2.670979,5.711199 -3.315119,1.519161 -5.782422,-5.157931 -8.858893,-6.780537 -4.229842,-1.139816 1.510134,-7.074128 2.586227,-2.385939 3.141198,5.495193 1.840537,-5.598295 7.177489,-1.404062 z' />\r\n  <path class='st0' d='m 99.622027,58.374253 c 1.493293,1.9548 -6.281936,7.024659 -0.885258,4.740447 0.386238,-4.434477 6.131941,-1.133173 2.175851,1.618005 -4.421491,6.12739 -13.666659,-3.151506 -7.058299,-7.136537 1.785129,-1.119329 4.348209,-0.743179 5.767706,0.778085 z m -2.900824,1.89746 c -3.608188,-2.208543 -2.280489,5.00803 -0.12563,0.329531 z' />\r\n  <path class='st0' d='m 115.18023,50.570441 c -1.61703,5.201678 -4.6204,-0.364502 -7.01598,-1.749619 -4.40977,2.122562 4.89641,4.913939 1.89606,7.018157 -2.48061,3.877635 -4.11404,-4.060614 -7.01192,-2.6391 -1.76318,3.107252 7.28394,6.252304 0.87346,7.876177 -1.74515,-2.956649 -9.055498,-5.610518 -3.950378,-8.66062 1.696478,1.897023 1.770418,-5.43503 5.347308,-3.072411 -0.44014,-5.474701 6.11995,-4.950882 7.7846,-0.815355 0.69076,0.682329 1.39587,1.351469 2.07685,2.042771 z' />\r\n  <path class='st0' d='m 120.54891,39.417125 c 2.50681,1.334124 4.80466,4.941837 0.75044,5.297362 -0.46414,1.89865 -5.25369,5.602652 -8.01742,1.815475 -3.87345,-2.809139 -0.0676,-7.603869 2.3036,-8.133924 1.6795,-3.853018 3.16703,-1.199465 4.96338,1.021087 z m -2.2464,2.175828 c -4.8049,-2.992167 -3.08987,6.380358 0.42374,2.036159 0.33052,-0.677508 0.12099,-1.525836 -0.42374,-2.036159 z' />\r\n  <path class='st0' d='m 128.50836,24.06821 c -5.10403,3.035506 3.20535,6.383175 5.05938,9.450276 -0.91853,2.95886 -4.06493,3.650723 -5.34691,0.265618 -2.25715,-2.089033 -4.65672,-6.948595 -7.07024,-2.584686 -4.71758,-3.764394 3.81217,-5.812054 5.12382,-9.226328 0.75738,0.677487 1.38637,1.498638 2.23389,2.095175 z' />\r\n  <path class='st0' d='m 137.14366,22.299812 c -3.09615,2.259885 0.71537,4.412454 1.99042,6.435866 -3.08975,5.080354 -5.91384,-2.98648 -8.92144,-4.094939 1.44369,-3.219573 3.3497,-1.335928 4.27156,-4.41058 0.97822,-0.894325 1.75044,1.871047 2.65946,2.069653 z' />\r\n  <path class='st0' d='m 136.85093,14.890174 c 2.31562,5.283511 -7.17975,1.771993 -1.29675,-0.475107 l 0.7108,0.08973 z m 4.867,5.317354 c 2.56912,1.439678 4.26517,4.725219 0.30678,5.233637 -1.56592,-3.098864 -9.51683,-5.749448 -3.64502,-8.633714 1.17746,0.325095 2.15375,2.591149 3.33824,3.400077 z' />\r\n  <path class='st0' d='m 149.95578,11.976423 c 2.50679,1.334142 4.80455,4.94192 0.75041,5.297394 -0.4641,1.898604 -5.25368,5.602645 -8.0174,1.81545 -3.87347,-2.80918 -0.0676,-7.603844 2.30366,-8.133968 1.67949,-3.8530525 3.16695,-1.1993573 4.96333,1.021124 z m -2.24641,2.175828 c -4.80489,-2.992177 -3.08986,6.380343 0.42374,2.036167 0.33055,-0.677518 0.121,-1.52585 -0.42374,-2.036167 z' />\r\n  <path class='st0' d='m 153.26135,7.538431 c 2.60497,1.5799548 6.03999,5.944272 1.08117,6.050232 -2.53319,-3.231828 -7.20316,-6.4304525 -8.84748,-9.4582682 1.89121,-2.8664883 3.78452,-2.247699 5.38514,0.8929426 0.78017,0.8503859 1.57195,1.6911437 2.38118,2.5150667 z' />\r\n  </pattern>  \r\n  <linearGradient id='groupUnderTitleLine' x1='0%' y1='0%' x2='100%' y2='0%' >\r\n          <stop offset='0%' stop-color='#999999' stop-opacity='0.7'/> \r\n          <stop offset='100%' stop-color='#999999' stop-opacity='0' /> \r\n   </linearGradient>\r\n  <radialGradient id='calloutGradient' cx='25%' cy='20%' r='80%' fx='10%' fy='10%'>\r\n\t   <stop offset='0%' stop-color='#ffffff' />\r\n    <stop offset='100%' stop-color='#f8f6d1' />\r\n  </radialGradient>\r\n  <filter id='shadow' width='120%' height='120%'> \r\n      <feOffset result='offOut' in='SourceGraphic' dx='1' dy='1' /> \r\n      <feColorMatrix result='matrixOut' in='offOut' type='matrix' \r\n      values='0.1 0 0 0 0 0 0.4 0 0 0 0 0 0.6 0 0 0 0 0 0.3 0' /> \r\n      <feGaussianBlur result='blurOut' in='matrixOut' stdDeviation='3' /> \r\n      <feBlend in='SourceGraphic' in2='blurOut' mode='normal' /> \r\n    </filter> \r\n  <filter id='fkShadow' height='130%'> \r\n    <feGaussianBlur in='SourceAlpha' stdDeviation='1.5'/> <!-- stdDeviation is how much to blur -->\r\n    <feOffset dx='1.2' dy='1.2' result='offsetblur'/> <!-- how much to offset -->\r\n    <feMerge>\r\n    <feMergeNode/> <!-- this contains the offset blurred image -->\r\n    <feMergeNode in='SourceGraphic'/> <!-- this contains the element that the filter is applied to -->\r\n    </feMerge>\r\n  </filter>\r\n  <radialGradient id='legendGradient' fx='5%' fy='5%' r='75%' spreadMethod='pad'>\r\n          <stop offset='0%' stop-color='#eefbf2' stop-opacity='1'/> \r\n          <stop offset='100%' stop-color='#cff9cb' stop-opacity='1' /> \r\n   </radialGradient>\r\n  <symbol id='calloutArrowDown' overflow='visible' >\r\n      <path d='M 0,0 L 7,11 L 15,0 z' style='fill:#f8f6d1;stroke:none; filter: url(#shadow);' />\r\n      <path d='M 0,0 L 7,11 L 15,0' style='stroke:#bebdbd; stroke-width:0.5;' />\r\n  </symbol>\r\n  <symbol id='calloutArrowUp' overflow='visible' >\r\n      <path d='M 0,15 L 7,3 L 15,15 z' style='fill:#ffffff; stroke:none; filter: url(#shadow);' />\r\n      <path d='M 0,15 L 7,3 L 15,15' style='stroke:#bebdbd; stroke-width:0.5;' />\r\n  </symbol>\r\n  <symbol id='pk' overflow='visible' >\r\n    <g transform='scale(0.99)'>\r\n     <path style='fill:#fffa7d;stroke:#765f03;stroke-width:0.6;stroke-linecap:round;stroke-linejoin:round;'\r\n        d='M 9.3678877,3.5695485 C 9.1030218,3.2729386 9.0796382,2.7628519 9.3396185,2.4517097 9.5449651,2.1956495 9.9040386,2.0980533 10.199638,2.2169415 10.533525,2.3415459 10.775153,2.706942 10.750675,3.0842709 10.737029,3.3980003 10.541153,3.699122 10.258248,3.8066067 9.966649,3.9250429 9.6169668,3.8418805 9.4008073,3.6062324 9.3894892,3.5943518 9.3785264,3.582104 9.3678886,3.5695487 z M 11.226617,6.9916004 C 11.888137,6.3548946 12.293488,5.4172188 12.311087,4.442353 12.378144,2.7379364 11.248678,1.0541269 9.7322318,0.44767357 8.3887112,-0.1280313 6.7865012,0.26822889 5.8918395,1.4007929 5.080823,2.3839145 4.9336815,3.8452096 5.3635544,5.101615 L 4.3670905,5.315913 C 4.0664984,5.3682645 4.0967703,5.6316724 4.2574957,5.8208829 L 4.9124,6.5655244 4.1543436,7.2512357 3.2136002,7.2163506 3.1674775,8.5586827 2.0406832,8.5086512 1.5965306,8.9299953 1.5471661,10.179833 0.75616674,10.195223 0.2112857,10.758575 0.15354288,11.735988 0.07199052,12.765553 c 0.36440953,0.238225 0.79006967,0.195492 1.44938278,-0.02675 L 6.3033562,8.1282037 6.8217102,8.6765688 C 6.9985465,8.8799427 7.3003699,8.7497574 7.358381,8.5016252 L 7.4938877,7.5084164 c 0.8537488,0.3985387 1.8303125,0.4711541 2.6851793,0.1427713 0.393927,-0.1407258 0.746858,-0.3701772 1.04755,-0.6595873 z'/>\r\n     <path d='M 6.8014948,6.3102123 0.15369063,13.024481 0.21560535,12.141962 6.0062342,6.2683782 z'\r\n        style='fill:#ffe5a5;fill-opacity:1;stroke:#854e31;stroke-width:0.06912433;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:3.00300009'/>\r\n    </g>\r\n  </symbol>\r\n  <symbol id='dist' overflow='visible' >\r\n    <g transform='scale(0.99)'>\r\n      <path style='fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;' d='M 0.177,11.431 12.28,11.449'/>\r\n      <path style='fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;' d='m 6.124,3.954 0.066,7.154 v 0'/>\r\n      <rect width='11.78' height='3.40' x='0.40' y='0.44' style='fill:#fffa7d;stroke:#765f03;stroke-width:0.6;' ry='0.83'/>\r\n      <rect width='11.78' height='3.40' x='0.40' y='5.609' style='fill:#fffa7d;stroke:#765f03;stroke-width:0.6;' ry='0.832'/>\r\n    </g>\r\n  </symbol>\r\n  <symbol id='unq' overflow='visible' >\r\n    <g transform='scale(0.99)'>\r\n      <rect style='fill:#fbea8e;stroke:#7e4d31;stroke-width:0.71934468;stroke-linecap:round;stroke-linejoin:round;'\r\n         width='2.29' height='8.43' x='7.48' y='-0.76' ry='1.14' transform='matrix(0.701,0.713,-0.727,0.685,0,0)' />\r\n      <path style='fill:white;stroke:#858585;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;'\r\n         d='m 26.04,8.64 a 4.13,4.13 0 1 1 -8.26,0 4.13,4.13 0 1 1 8.26,0 z'\r\n         transform='matrix(1.025,0,0,0.987,-14.690,-3.862)' />\r\n      <text x='5.8' y='7.4' style='font-size:7px;fill:#8a8a8a;'>1</text>\r\n    </g>\r\n  </symbol>\r\n  <symbol id='idx' overflow='visible' >\r\n    <g transform='scale(0.99)'>\r\n      <rect style='fill:#fbea8e;stroke:#7e4d31;stroke-width:0.71934468;stroke-linecap:round;stroke-linejoin:round;'\r\n         width='2.29' height='8.43' x='7.48' y='-0.76' ry='1.14' transform='matrix(0.701,0.713,-0.727,0.685,0,0)' />\r\n      <path style='fill:white;stroke:#858585;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;'\r\n         d='m 26.04,8.64 a 4.13,4.13 0 1 1 -8.26,0 4.13,4.13 0 1 1 8.26,0 z'\r\n         transform='matrix(1.025,0,0,0.987,-14.690,-3.862)' />\r\n    </g>\r\n  </symbol>\r\n  <symbol id='fk' overflow='visible' >\r\n    <g transform='scale(0.87)'>\r\n      <path style='fill:#f3e1b7;stroke:#7e471f;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;'\r\n      d='M 12.48,0.33 7.07,0.89 9.067,2.974 0.329,11.731 1.073,12.597 9.811,3.841 11.77,5.78 z' />\r\n    </g>\r\n  </symbol>\r\n  <symbol id='ref' overflow='visible' >\r\n    <g transform='scale(0.87)'>\r\n      <path style='fill:#f3e1b7;stroke:#7e471f;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;'\r\n          d='M 0.10,12.70 5.31,12.15 3.40,10.06 11.82,1.32 11.11,0.45 2.68,9.19 0.80,7.24 z'/>\r\n    </g>\r\n  </symbol>\r\n  <symbol id='flag0' overflow='visible' >\r\n    <g transform='scale(0.92)'>\r\n      <path style='fill:#b7d0f6;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;'\r\n          d='M 0.12,12.67 0.16,7.22 C 2.59,7.22 4.13,8.78 9.22,4.22 5.68,4.98 2.53,4.50 0.09,1.80 z'/>\r\n    </g>\r\n  </symbol>\r\n  <symbol id='flag1' overflow='visible' >\r\n    <g transform='scale(0.92)'>\r\n      <path style='fill:#f4a393;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;'\r\n          d='M 0.12,12.67 0.16,7.22 C 2.59,7.22 4.13,8.78 9.22,4.22 5.68,4.98 2.53,4.50 0.09,1.80 z'/>\r\n    </g>\r\n  </symbol>\r\n  <symbol id='flag2' overflow='visible' >\r\n    <g transform='scale(0.92)'>\r\n      <path style='fill:#77ec8b;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;'\r\n          d='M 0.12,12.67 0.16,7.22 C 2.59,7.22 4.13,8.78 9.22,4.22 5.68,4.98 2.53,4.50 0.09,1.80 z'/>\r\n    </g>\r\n  </symbol>\r\n  <symbol id='nn' overflow='visible' >\r\n  <path style='stroke:#9b3e50;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;'\r\n          d='M 0,0 3,3 M 0,3 3,0 z'/>\r\n  </symbol>\r\n  <symbol id='view' overflow='visible' >\r\n    <g transform='scale(0.99)'>\r\n     <line x1='12' y1='6' x2='19' y2='0' stroke='black' stroke-width='0.5' />\r\n     <line x1='0' y1='6' x2='7' y2='0' stroke='black' stroke-width='0.5' />\r\n     <circle cx='3' cy='6' r='3' fill='#f9ebbc' stroke='black' stroke-width='0.5'/>\r\n     <circle cx='10' cy='6' r='3' fill='#f9ebbc' stroke='black' stroke-width='0.5'/>\r\n    </g>\r\n  </symbol>\r\n  <marker id='arrow01' viewBox='0 0 15.00 7.50' refX='7.50' refY='3.75' markerUnits='strokeWidth' markerWidth='15.00' markerHeight='7.50' orient='auto'>\r\n    <path d='M 7.500,3.750 L 15.000,3.750 L 7.500,0.000 L 15.000,3.750 L 7.500,7.500' />\r\n  </marker>\r\n  <marker id='arrow1' viewBox='0 0 15.00 7.50' refX='7.50' refY='3.75' markerUnits='strokeWidth' markerWidth='15.00' markerHeight='7.50' orient='auto'>\r\n    <path d='M 7.500,3.750 L 15.000,3.750 L 7.500,0.000 L 15.000,3.750 L 7.500,7.500' />\r\n  </marker>\r\n  <marker id='foot01' viewBox='0 0 15.00 7.50' refX='7.50' refY='3.75' markerUnits='strokeWidth' markerWidth='15.00' markerHeight='7.50' orient='auto'>\r\n    <path d='M 0.00,3.75 L 15.00,3.75 z' />\r\n    <circle cx='11.25' cy='3.75' r='2.50' style='fill:white;stroke:#5e554d;' />\r\n    <path d='M 3.75,0.00 L 3.75, 7.50 z' />\r\n  </marker>\r\n  <marker id='foot0p' viewBox='0 0 15.00 7.50' refX='7.50' refY='3.75' markerUnits='strokeWidth' markerWidth='15.00' markerHeight='7.50' orient='auto'>\r\n    <path d='M 0.00,3.75 L 15.00,3.75 z' />\r\n    <circle cx='11.25' cy='3.75' r='2.50' style='fill:white;stroke:#5e554d;' />\r\n    <path d='M 0.00,0.00 L 7.50,3.75 L 0.00,7.50' />\r\n  </marker>\r\n  <marker id='foot1' viewBox='0 0 15.00 7.50' refX='7.50' refY='3.75' markerUnits='strokeWidth' markerWidth='15.00' markerHeight='7.50' orient='auto'>\r\n    <path d='M 0.00,3.75 L 15.00,3.75 z' />\r\n    <path d='M 7.50,0.00 L 7.50, 7.50 z' />\r\n    <path d='M 3.75,0.00 L 3.75, 7.50 z' />\r\n  </marker>\r\n  <marker id='foot1p' viewBox='0 0 15.00 7.50' refX='7.50' refY='3.75' markerUnits='strokeWidth' markerWidth='15.00' markerHeight='7.50' orient='auto'>\r\n    <path d='M 0.00,3.75 L 15.00,3.75 z' />\r\n    <path d='M 7.50,0.00 L 7.50, 7.50 z' />\r\n    <path d='M 0.00,0.00 L 7.50,3.75 L 0.00,7.50' />\r\n  </marker>\r\n  <linearGradient id='tbg_bfd4f5' x1='0%' y1='0%' x2='0%' y2='100%' >\r\n     <stop offset='0%' stop-color='#496ba1' /> \r\n     <stop offset='100%' stop-color='#1f4682' /> \r\n  </linearGradient>\r\n  <linearGradient id='tbg_c8f5bf' x1='0%' y1='0%' x2='0%' y2='100%' >\r\n     <stop offset='0%' stop-color='#58a149' /> \r\n     <stop offset='100%' stop-color='#30821f' /> \r\n  </linearGradient>\r\n  <linearGradient id='tbg_f5ddbf' x1='0%' y1='0%' x2='0%' y2='100%' >\r\n     <stop offset='0%' stop-color='#a17a49' /> \r\n     <stop offset='100%' stop-color='#82561f' /> \r\n  </linearGradient>\r\n  <linearGradient id='tbg_bfbff5' x1='0%' y1='0%' x2='0%' y2='100%' >\r\n     <stop offset='0%' stop-color='#4949a1' /> \r\n     <stop offset='100%' stop-color='#1f1f82' /> \r\n  </linearGradient>\r\n</defs>\r\n\r\n<!-- == Desktop == -->\r\n<rect x='1' y='1' width='1888' height='1098' rx='7' ry='7' style='fill:url(#layoutBgB); stroke:#777777; stroke-width:0.5;' />\r\n<rect x='1' y='1' width='1888' height='1098' rx='7' ry='7' style='fill:url(#layoutBgA); stroke:#777777; stroke-width:0.5;' />\r\n\r\n<!-- == Legend == -->\r\n<g transform='translate(10,10)'>\r\n  <rect x='10' y='10' width='330' height='56' rx='6' ry='6' style='fill:url(#legendGradient);filter:url(#shadow);'/> \r\n  <text x='20' y='43'>RuoYi</text> \r\n  <text x='20' y='57' style='fill:#aaaaaa; font-size:11px;'><tspan>Move the mouse over tables &amp; columns to read the comments.</tspan></text> \r\n<a xlink:href='https://www.dbschema.com'> <path class='logo' d='m 32.309685,20.963194 c 0.411708,4.732616 -4.298055,7.925636 -8.723583,6.970196 -6.616967,1.8448 -2.656457,-6.434594 -3.911969,-10.01566 -2.15469,-5.89407 6.06247,-3.508505 9.167655,-2.863689 2.199228,1.054873 3.389343,3.582089 3.467897,5.909153 z m -3.720955,0.01451 c 0.434195,-4.414565 -7.644142,-5.37533 -5.137307,0.107342 -1.812268,5.992146 5.532698,4.379388 5.137307,-0.107342 z' /> <path class='logo' d='m 44.329732,23.050637 c 0.850982,5.097305 -5.250434,4.558924 -7.144836,4.752415 -6.418993,1.64391 -1.872992,-7.49274 -3.541914,-10.942842 -2.499646,-3.817859 5.939283,-4.402698 3.538545,-0.13612 -1.287874,4.989123 4.215411,-1.154796 5.956717,2.809584 0.840273,0.970849 1.168829,2.272413 1.191488,3.516963 z m -3.519477,-0.09299 c -1.398216,-5.518069 -6.361061,2.717467 -0.984368,1.810718 0.686994,-0.30388 1.029454,-1.087638 0.984368,-1.810718 z' /> <path class='logo' d='m 52.234961,23.301163 c 0.954818,5.035675 -8.606408,6.284861 -6.262292,1.674914 6.000358,-1.604717 -5.188764,-7.870044 1.75972,-10.384908 2.288682,-3.253567 6.399287,3.075831 2.304111,2.48058 -2.124941,2.016587 2.688777,3.89858 2.198472,6.229403 z' /> <path class='logo' d='m 60.204336,21.349224 c -4.894917,-1.916474 -3.458707,5.391212 0.347494,3.37231 2.120589,6.821713 -10.599623,1.664746 -6.906229,-3.691132 0.354172,-3.663246 9.875349,-4.711252 6.558735,0.318822 z' /> <path class='logo' d='m 71.730617,20.654299 c 0.0013,2.316285 0.190131,4.655698 0.07825,6.958009 -6.532419,3.303565 -0.660423,-8.722256 -6.009639,-5.821653 -0.818815,2.024533 1.726403,6.746337 -1.95327,6.005484 -3.458346,-1.137537 -0.696275,-7.713407 -1.833252,-10.994208 -2.308916,-3.710131 5.93704,-4.164951 3.518609,0.0063 -1.462376,6.166445 5.169629,-2.857523 6.19931,3.846079 z' /> <path class='logo' d='m 82.245738,22.378957 c -0.24581,2.448954 -9.386766,0.8867 -3.885979,2.877055 3.312576,-2.99157 5.250902,3.334514 0.482647,2.665545 -7.415384,1.492275 -7.823196,-11.597641 -0.275476,-10.032117 2.068161,0.391458 3.682204,2.408824 3.678808,4.489517 z m -3.414436,-0.578473 c -1.124703,-4.072004 -5.087405,2.125488 -0.316922,0.156453 z' /> <path class='logo' d='m 98.936899,27.222794 c -4.73541,2.718339 -3.1239,-3.406557 -3.92611,-6.050494 -4.66985,-1.438471 0.21621,6.932413 -3.41219,6.438039 -4.46096,1.160054 -0.22824,-5.774711 -3.31526,-6.700429 -3.410722,1.082173 1.04451,9.536575 -4.745091,6.372895 0.746632,-3.355214 -2.776394,-10.269232 3.034971,-9.038963 -0.058,2.544602 5.00686,-2.785359 6.00342,1.37844 3.42021,-4.316316 7.851251,0.524966 6.24018,4.690538 0.0379,0.969988 0.0954,1.940046 0.12008,2.909974 z' /> <path class='logo' d='m 110.47859,22.686058 c 0.91826,2.682088 0.13016,6.890551 -3.0725,4.397004 -1.63641,1.077877 -7.664291,0.541832 -7.09365,-4.114836 -0.907891,-4.692933 5.14729,-5.625578 7.24058,-4.40354 3.85932,-1.686263 3.13176,1.271515 2.92557,4.121372 z m -3.12695,0.0704 c -1.46278,-5.460062 -6.61615,2.5826 -1.08221,1.782003 0.70431,-0.272594 1.13111,-1.037444 1.08221,-1.782003 z' /> </a>\r\n</g>\r\n\r\n<g transform='translate(0,110)'>\r\n<!-- == Fk 'qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1' == -->\r\n<path id='qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1'  onmouseover=\"hghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" transform='translate(7,0)' class='scene' d='M 270 525 L 270,480' >\r\n\t<title>Fk qrtz_blob_triggers_ibfk_1\r\nqrtz_blob_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )</title>\r\n</path>\r\n<path transform='translate(7,0)' marker-start='url(#foot1)' marker-end='url(#arrow1)'    d='M 270 525 L 270,480' ></path>\r\n<text x='272' y='520' transform='rotate(270 272,520)' title='Fk qrtz_blob_triggers_ibfk_1\r\nqrtz_blob_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )' class='relName' style='fill:#5f789f'>sched_name,trigger_name,trigger_group</text>\r\n<!-- == Fk 'qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1' == -->\r\n<path id='qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1'  onmouseover=\"hghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" transform='translate(7,0)' class='scene' d='M 420 540 L 397,540 Q 390,540 390,532 L 390,472 Q 390,465 382,465 L 375,465' >\r\n\t<title>Fk qrtz_cron_triggers_ibfk_1\r\nqrtz_cron_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )</title>\r\n</path>\r\n<path transform='translate(7,0)' marker-start='url(#foot1)' marker-end='url(#arrow1)'    d='M 420 540 L 397,540 Q 390,540 390,532 L 390,472 Q 390,465 382,465 L 375,465' ></path>\r\n<text x='205' y='535' transform='rotate(0 205,535)' title='Fk qrtz_cron_triggers_ibfk_1\r\nqrtz_cron_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )' class='relName' style='fill:#5f789f'>sched_name,trigger_name,trigger_group</text>\r\n<!-- == Fk 'qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1' == -->\r\n<path id='qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1'  onmouseover=\"hghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" transform='translate(7,0)' class='scene' d='M 180 525 L 180,502 Q 180,495 187,495 L 277,495 Q 285,495 285,487 L 285,480' >\r\n\t<title>Fk qrtz_simple_triggers_ibfk_1\r\nqrtz_simple_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )</title>\r\n</path>\r\n<path transform='translate(7,0)' marker-start='url(#foot1)' marker-end='url(#arrow1)'    d='M 180 525 L 180,502 Q 180,495 187,495 L 277,495 Q 285,495 285,487 L 285,480' ></path>\r\n<text x='182' y='520' transform='rotate(270 182,520)' title='Fk qrtz_simple_triggers_ibfk_1\r\nqrtz_simple_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )' class='relName' style='fill:#5f789f'>sched_name,trigger_name,trigger_group</text>\r\n<!-- == Fk 'qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1' == -->\r\n<path id='qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1'  onmouseover=\"hghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" transform='translate(7,0)' class='scene' d='M 195 240 L 240,240' >\r\n\t<title>Fk qrtz_simprop_triggers_ibfk_1\r\nqrtz_simprop_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )</title>\r\n</path>\r\n<path transform='translate(7,0)' marker-start='url(#foot1)' marker-end='url(#arrow1)'    d='M 195 240 L 240,240' ></path>\r\n<text x='202' y='235' transform='rotate(0 202,235)' title='Fk qrtz_simprop_triggers_ibfk_1\r\nqrtz_simprop_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group )' class='relName' style='fill:#5f789f'>sched_name,trigger_name,trigger_group</text>\r\n<!-- == Fk 'qrtz_triggers_qrtz_triggers_ibfk_1' == -->\r\n<path id='qrtz_triggers_qrtz_triggers_ibfk_1'  onmouseover=\"hghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group'])\" onmouseout=\"uhghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group'])\" transform='translate(7,0)' class='scene' d='M 375 210 L 420,210' >\r\n\t<title>Fk qrtz_triggers_ibfk_1\r\nqrtz_triggers ref qrtz_job_details ( sched_name, job_name, job_group )</title>\r\n</path>\r\n<path transform='translate(7,0)' marker-start='url(#foot1p)' marker-end='url(#arrow1)'    d='M 375 210 L 420,210' ></path>\r\n<text x='382' y='205' transform='rotate(0 382,205)' title='Fk qrtz_triggers_ibfk_1\r\nqrtz_triggers ref qrtz_job_details ( sched_name, job_name, job_group )' class='relName' style='fill:#5f789f'>sched_name,job_name,job_group</text>\r\n<!-- == Table 'qrtz_blob_triggers' == -->\r\n<rect class='entity' x='255' y='533' width='120' height='105' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 255 559 L 255 540 Q 255 533 262 533 L 368 533 Q 375 533 375 540 L 375 559 L255 559 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='255' y='533' width='120' height='105' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='255' y1='559' x2='375' y2='559' style='stroke:#5f656e'/>\r\n<line class='delim' x1='270' y1='559' x2='270' y2='638' style='stroke:#5f656e'/>\r\n<line class='delim' x1='364' y1='559' x2='364' y2='638' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_blob_triggers'><text x='258' y='551'>qrtz_blob_triggers</text><title>Table ry.qrtz_blob_triggers</title></a>\r\n  <use id='nn' x='257' y='567' xlink:href='#nn'/><a xlink:href='#qrtz_blob_triggers.sched_name'><use id='pk' x='257' y='566' xlink:href='#pk'/><title>Pk pk_qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_blob_triggers.sched_name'><text id='ry.qrtz_blob_triggers.sched_name' x='273' y='576' onmouseover=\"hghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<a xlink:href='#qrtz_blob_triggers.sched_name'><use id='fk' x='364' y='566' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='257' y='582' xlink:href='#nn'/><a xlink:href='#qrtz_blob_triggers.trigger_name'><use id='pk' x='257' y='581' xlink:href='#pk'/><title>Pk pk_qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_blob_triggers.trigger_name'><text id='ry.qrtz_blob_triggers.trigger_name' x='273' y='591' onmouseover=\"hghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_name</text><title>trigger_name\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_blob_triggers.trigger_name'><use id='fk' x='364' y='581' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='257' y='597' xlink:href='#nn'/><a xlink:href='#qrtz_blob_triggers.trigger_group'><use id='pk' x='257' y='596' xlink:href='#pk'/><title>Pk pk_qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_blob_triggers.trigger_group'><text id='ry.qrtz_blob_triggers.trigger_group' x='273' y='606' onmouseover=\"hghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_group</text><title>trigger_group\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_blob_triggers.trigger_group'><use id='fk' x='364' y='596' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <a xlink:href='#qrtz_blob_triggers.blob_data'><text id='ry.qrtz_blob_triggers.blob_data' x='273' y='621'>blob_data</text><title>blob_data\r\nblob</title></a>\r\n<text x='372' y='618' text-anchor='end' class='colType'>~</text>\r\n<!-- == Table 'qrtz_calendars' == -->\r\n<rect class='entity' x='75' y='38' width='120' height='90' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 75 64 L 75 45 Q 75 38 82 38 L 188 38 Q 195 38 195 45 L 195 64 L75 64 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='75' y='38' width='120' height='90' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='75' y1='64' x2='195' y2='64' style='stroke:#5f656e'/>\r\n<line class='delim' x1='90' y1='64' x2='90' y2='128' style='stroke:#5f656e'/>\r\n<line class='delim' x1='184' y1='64' x2='184' y2='128' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_calendars'><text x='90' y='56'>qrtz_calendars</text><title>Table ry.qrtz_calendars</title></a>\r\n  <use id='nn' x='77' y='72' xlink:href='#nn'/><a xlink:href='#qrtz_calendars.sched_name'><use id='pk' x='77' y='71' xlink:href='#pk'/><title>Pk pk_qrtz_calendars ( sched_name, calendar_name ) </title></a>\r\n<a xlink:href='#qrtz_calendars.sched_name'><text id='ry.qrtz_calendars.sched_name' x='93' y='81'>sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<text x='192' y='78' text-anchor='end' class='colType'>t</text>  <use id='nn' x='77' y='87' xlink:href='#nn'/><a xlink:href='#qrtz_calendars.calendar_name'><use id='pk' x='77' y='86' xlink:href='#pk'/><title>Pk pk_qrtz_calendars ( sched_name, calendar_name ) </title></a>\r\n<a xlink:href='#qrtz_calendars.calendar_name'><text id='ry.qrtz_calendars.calendar_name' x='93' y='96'>calendar_name</text><title>calendar_name\r\n* varchar(200)</title></a>\r\n<text x='192' y='93' text-anchor='end' class='colType'>t</text>  <use id='nn' x='77' y='102' xlink:href='#nn'/><a xlink:href='#qrtz_calendars.calendar'><text id='ry.qrtz_calendars.calendar' x='93' y='111'>calendar</text><title>calendar\r\n* blob</title></a>\r\n<text x='192' y='108' text-anchor='end' class='colType'>~</text>\r\n<!-- == Table 'qrtz_cron_triggers' == -->\r\n<rect class='entity' x='435' y='533' width='135' height='120' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 435 559 L 435 540 Q 435 533 442 533 L 563 533 Q 570 533 570 540 L 570 559 L435 559 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='435' y='533' width='135' height='120' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='435' y1='559' x2='570' y2='559' style='stroke:#5f656e'/>\r\n<line class='delim' x1='450' y1='559' x2='450' y2='653' style='stroke:#5f656e'/>\r\n<line class='delim' x1='559' y1='559' x2='559' y2='653' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_cron_triggers'><text x='445' y='551'>qrtz_cron_triggers</text><title>Table ry.qrtz_cron_triggers</title></a>\r\n  <use id='nn' x='437' y='567' xlink:href='#nn'/><a xlink:href='#qrtz_cron_triggers.sched_name'><use id='pk' x='437' y='566' xlink:href='#pk'/><title>Pk pk_qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_cron_triggers.sched_name'><text id='ry.qrtz_cron_triggers.sched_name' x='453' y='576' onmouseover=\"hghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<a xlink:href='#qrtz_cron_triggers.sched_name'><use id='fk' x='559' y='566' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='437' y='582' xlink:href='#nn'/><a xlink:href='#qrtz_cron_triggers.trigger_name'><use id='pk' x='437' y='581' xlink:href='#pk'/><title>Pk pk_qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_cron_triggers.trigger_name'><text id='ry.qrtz_cron_triggers.trigger_name' x='453' y='591' onmouseover=\"hghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_name</text><title>trigger_name\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_cron_triggers.trigger_name'><use id='fk' x='559' y='581' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='437' y='597' xlink:href='#nn'/><a xlink:href='#qrtz_cron_triggers.trigger_group'><use id='pk' x='437' y='596' xlink:href='#pk'/><title>Pk pk_qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_cron_triggers.trigger_group'><text id='ry.qrtz_cron_triggers.trigger_group' x='453' y='606' onmouseover=\"hghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_group</text><title>trigger_group\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_cron_triggers.trigger_group'><use id='fk' x='559' y='596' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='437' y='612' xlink:href='#nn'/><a xlink:href='#qrtz_cron_triggers.cron_expression'><text id='ry.qrtz_cron_triggers.cron_expression' x='453' y='621'>cron_expression</text><title>cron_expression\r\n* varchar(200)</title></a>\r\n<text x='567' y='618' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_cron_triggers.time_zone_id'><text id='ry.qrtz_cron_triggers.time_zone_id' x='453' y='636'>time_zone_id</text><title>time_zone_id\r\nvarchar(80)</title></a>\r\n<text x='567' y='633' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'qrtz_job_details' == -->\r\n<rect class='entity' x='435' y='188' width='135' height='195' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 435 214 L 435 195 Q 435 188 442 188 L 563 188 Q 570 188 570 195 L 570 214 L435 214 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='435' y='188' width='135' height='195' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='435' y1='214' x2='570' y2='214' style='stroke:#5f656e'/>\r\n<line class='delim' x1='450' y1='214' x2='450' y2='383' style='stroke:#5f656e'/>\r\n<line class='delim' x1='559' y1='214' x2='559' y2='383' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_job_details'><text x='451' y='206'>qrtz_job_details</text><title>Table ry.qrtz_job_details</title></a>\r\n  <use id='nn' x='437' y='222' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.sched_name'><use id='pk' x='437' y='221' xlink:href='#pk'/><title>Pk pk_qrtz_job_details ( sched_name, job_name, job_group ) </title></a>\r\n<a xlink:href='#qrtz_job_details.sched_name'><text id='ry.qrtz_job_details.sched_name' x='453' y='231' onmouseover=\"hghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group'])\" onmouseout=\"uhghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group'])\">sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<a xlink:href='#qrtz_job_details.sched_name'><use id='ref' x='559' y='221' xlink:href='#ref'/><title>Referred by qrtz_triggers ( sched_name, job_name, job_group ) </title></a>\r\n  <use id='nn' x='437' y='237' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.job_name'><use id='pk' x='437' y='236' xlink:href='#pk'/><title>Pk pk_qrtz_job_details ( sched_name, job_name, job_group ) </title></a>\r\n<a xlink:href='#qrtz_job_details.job_name'><text id='ry.qrtz_job_details.job_name' x='453' y='246' onmouseover=\"hghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group'])\" onmouseout=\"uhghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group'])\">job_name</text><title>job_name\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_job_details.job_name'><use id='ref' x='559' y='236' xlink:href='#ref'/><title>Referred by qrtz_triggers ( sched_name, job_name, job_group ) </title></a>\r\n  <use id='nn' x='437' y='252' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.job_group'><use id='pk' x='437' y='251' xlink:href='#pk'/><title>Pk pk_qrtz_job_details ( sched_name, job_name, job_group ) </title></a>\r\n<a xlink:href='#qrtz_job_details.job_group'><text id='ry.qrtz_job_details.job_group' x='453' y='261' onmouseover=\"hghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group'])\" onmouseout=\"uhghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.job_name','ry.qrtz_triggers.job_group'])\">job_group</text><title>job_group\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_job_details.job_group'><use id='ref' x='559' y='251' xlink:href='#ref'/><title>Referred by qrtz_triggers ( sched_name, job_name, job_group ) </title></a>\r\n  <a xlink:href='#qrtz_job_details.description'><text id='ry.qrtz_job_details.description' x='453' y='276'>description</text><title>description\r\nvarchar(250)</title></a>\r\n<text x='567' y='273' text-anchor='end' class='colType'>t</text>  <use id='nn' x='437' y='282' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.job_class_name'><text id='ry.qrtz_job_details.job_class_name' x='453' y='291'>job_class_name</text><title>job_class_name\r\n* varchar(250)</title></a>\r\n<text x='567' y='288' text-anchor='end' class='colType'>t</text>  <use id='nn' x='437' y='297' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.is_durable'><text id='ry.qrtz_job_details.is_durable' x='453' y='306'>is_durable</text><title>is_durable\r\n* varchar(1)</title></a>\r\n<text x='567' y='303' text-anchor='end' class='colType'>t</text>  <use id='nn' x='437' y='312' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.is_nonconcurrent'><text id='ry.qrtz_job_details.is_nonconcurrent' x='453' y='321'>is_nonconcurrent</text><title>is_nonconcurrent\r\n* varchar(1)</title></a>\r\n<text x='567' y='318' text-anchor='end' class='colType'>t</text>  <use id='nn' x='437' y='327' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.is_update_data'><text id='ry.qrtz_job_details.is_update_data' x='453' y='336'>is_update_data</text><title>is_update_data\r\n* varchar(1)</title></a>\r\n<text x='567' y='333' text-anchor='end' class='colType'>t</text>  <use id='nn' x='437' y='342' xlink:href='#nn'/><a xlink:href='#qrtz_job_details.requests_recovery'><text id='ry.qrtz_job_details.requests_recovery' x='453' y='351'>requests_recovery</text><title>requests_recovery\r\n* varchar(1)</title></a>\r\n<text x='567' y='348' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_job_details.job_data'><text id='ry.qrtz_job_details.job_data' x='453' y='366'>job_data</text><title>job_data\r\nblob</title></a>\r\n<text x='567' y='363' text-anchor='end' class='colType'>~</text>\r\n<!-- == Table 'qrtz_locks' == -->\r\n<rect class='entity' x='255' y='53' width='105' height='75' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 255 79 L 255 60 Q 255 53 262 53 L 353 53 Q 360 53 360 60 L 360 79 L255 79 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='255' y='53' width='105' height='75' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='255' y1='79' x2='360' y2='79' style='stroke:#5f656e'/>\r\n<line class='delim' x1='270' y1='79' x2='270' y2='128' style='stroke:#5f656e'/>\r\n<line class='delim' x1='349' y1='79' x2='349' y2='128' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_locks'><text x='274' y='71'>qrtz_locks</text><title>Table ry.qrtz_locks</title></a>\r\n  <use id='nn' x='257' y='87' xlink:href='#nn'/><a xlink:href='#qrtz_locks.sched_name'><use id='pk' x='257' y='86' xlink:href='#pk'/><title>Pk pk_qrtz_locks ( sched_name, lock_name ) </title></a>\r\n<a xlink:href='#qrtz_locks.sched_name'><text id='ry.qrtz_locks.sched_name' x='273' y='96'>sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<text x='357' y='93' text-anchor='end' class='colType'>t</text>  <use id='nn' x='257' y='102' xlink:href='#nn'/><a xlink:href='#qrtz_locks.lock_name'><use id='pk' x='257' y='101' xlink:href='#pk'/><title>Pk pk_qrtz_locks ( sched_name, lock_name ) </title></a>\r\n<a xlink:href='#qrtz_locks.lock_name'><text id='ry.qrtz_locks.lock_name' x='273' y='111'>lock_name</text><title>lock_name\r\n* varchar(40)</title></a>\r\n<text x='357' y='108' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'qrtz_scheduler_state' == -->\r\n<rect class='entity' x='255' y='728' width='135' height='105' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 255 754 L 255 735 Q 255 728 262 728 L 383 728 Q 390 728 390 735 L 390 754 L255 754 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='255' y='728' width='135' height='105' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='255' y1='754' x2='390' y2='754' style='stroke:#5f656e'/>\r\n<line class='delim' x1='270' y1='754' x2='270' y2='833' style='stroke:#5f656e'/>\r\n<line class='delim' x1='379' y1='754' x2='379' y2='833' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_scheduler_state'><text x='259' y='746'>qrtz_scheduler_state</text><title>Table ry.qrtz_scheduler_state</title></a>\r\n  <use id='nn' x='257' y='762' xlink:href='#nn'/><a xlink:href='#qrtz_scheduler_state.sched_name'><use id='pk' x='257' y='761' xlink:href='#pk'/><title>Pk pk_qrtz_scheduler_state ( sched_name, instance_name ) </title></a>\r\n<a xlink:href='#qrtz_scheduler_state.sched_name'><text id='ry.qrtz_scheduler_state.sched_name' x='273' y='771'>sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<text x='387' y='768' text-anchor='end' class='colType'>t</text>  <use id='nn' x='257' y='777' xlink:href='#nn'/><a xlink:href='#qrtz_scheduler_state.instance_name'><use id='pk' x='257' y='776' xlink:href='#pk'/><title>Pk pk_qrtz_scheduler_state ( sched_name, instance_name ) </title></a>\r\n<a xlink:href='#qrtz_scheduler_state.instance_name'><text id='ry.qrtz_scheduler_state.instance_name' x='273' y='786'>instance_name</text><title>instance_name\r\n* varchar(200)</title></a>\r\n<text x='387' y='783' text-anchor='end' class='colType'>t</text>  <use id='nn' x='257' y='792' xlink:href='#nn'/><a xlink:href='#qrtz_scheduler_state.last_checkin_time'><text id='ry.qrtz_scheduler_state.last_checkin_time' x='273' y='801'>last_checkin_time</text><title>last_checkin_time\r\n* bigint</title></a>\r\n<text x='387' y='798' text-anchor='end' class='colType'>#</text>  <use id='nn' x='257' y='807' xlink:href='#nn'/><a xlink:href='#qrtz_scheduler_state.checkin_interval'><text id='ry.qrtz_scheduler_state.checkin_interval' x='273' y='816'>checkin_interval</text><title>checkin_interval\r\n* bigint</title></a>\r\n<text x='387' y='813' text-anchor='end' class='colType'>#</text>\r\n<!-- == Table 'qrtz_simple_triggers' == -->\r\n<rect class='entity' x='60' y='533' width='135' height='135' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 60 559 L 60 540 Q 60 533 67 533 L 188 533 Q 195 533 195 540 L 195 559 L60 559 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='60' y='533' width='135' height='135' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='60' y1='559' x2='195' y2='559' style='stroke:#5f656e'/>\r\n<line class='delim' x1='75' y1='559' x2='75' y2='668' style='stroke:#5f656e'/>\r\n<line class='delim' x1='184' y1='559' x2='184' y2='668' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_simple_triggers'><text x='64' y='551'>qrtz_simple_triggers</text><title>Table ry.qrtz_simple_triggers</title></a>\r\n  <use id='nn' x='62' y='567' xlink:href='#nn'/><a xlink:href='#qrtz_simple_triggers.sched_name'><use id='pk' x='62' y='566' xlink:href='#pk'/><title>Pk pk_qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_simple_triggers.sched_name'><text id='ry.qrtz_simple_triggers.sched_name' x='78' y='576' onmouseover=\"hghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<a xlink:href='#qrtz_simple_triggers.sched_name'><use id='fk' x='184' y='566' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='62' y='582' xlink:href='#nn'/><a xlink:href='#qrtz_simple_triggers.trigger_name'><use id='pk' x='62' y='581' xlink:href='#pk'/><title>Pk pk_qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_simple_triggers.trigger_name'><text id='ry.qrtz_simple_triggers.trigger_name' x='78' y='591' onmouseover=\"hghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_name</text><title>trigger_name\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_simple_triggers.trigger_name'><use id='fk' x='184' y='581' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='62' y='597' xlink:href='#nn'/><a xlink:href='#qrtz_simple_triggers.trigger_group'><use id='pk' x='62' y='596' xlink:href='#pk'/><title>Pk pk_qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_simple_triggers.trigger_group'><text id='ry.qrtz_simple_triggers.trigger_group' x='78' y='606' onmouseover=\"hghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_group</text><title>trigger_group\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_simple_triggers.trigger_group'><use id='fk' x='184' y='596' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='62' y='612' xlink:href='#nn'/><a xlink:href='#qrtz_simple_triggers.repeat_count'><text id='ry.qrtz_simple_triggers.repeat_count' x='78' y='621'>repeat_count</text><title>repeat_count\r\n* bigint</title></a>\r\n<text x='192' y='618' text-anchor='end' class='colType'>#</text>  <use id='nn' x='62' y='627' xlink:href='#nn'/><a xlink:href='#qrtz_simple_triggers.repeat_interval'><text id='ry.qrtz_simple_triggers.repeat_interval' x='78' y='636'>repeat_interval</text><title>repeat_interval\r\n* bigint</title></a>\r\n<text x='192' y='633' text-anchor='end' class='colType'>#</text>  <use id='nn' x='62' y='642' xlink:href='#nn'/><a xlink:href='#qrtz_simple_triggers.times_triggered'><text id='ry.qrtz_simple_triggers.times_triggered' x='78' y='651'>times_triggered</text><title>times_triggered\r\n* bigint</title></a>\r\n<text x='192' y='648' text-anchor='end' class='colType'>#</text>\r\n<!-- == Table 'qrtz_simprop_triggers' == -->\r\n<rect class='entity' x='45' y='218' width='150' height='255' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 45 244 L 45 225 Q 45 218 52 218 L 188 218 Q 195 218 195 225 L 195 244 L45 244 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='45' y='218' width='150' height='255' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='45' y1='244' x2='195' y2='244' style='stroke:#5f656e'/>\r\n<line class='delim' x1='60' y1='244' x2='60' y2='473' style='stroke:#5f656e'/>\r\n<line class='delim' x1='184' y1='244' x2='184' y2='473' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_simprop_triggers'><text x='54' y='236'>qrtz_simprop_triggers</text><title>Table ry.qrtz_simprop_triggers</title></a>\r\n  <use id='nn' x='47' y='252' xlink:href='#nn'/><a xlink:href='#qrtz_simprop_triggers.sched_name'><use id='pk' x='47' y='251' xlink:href='#pk'/><title>Pk pk_qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_simprop_triggers.sched_name'><text id='ry.qrtz_simprop_triggers.sched_name' x='63' y='261' onmouseover=\"hghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<a xlink:href='#qrtz_simprop_triggers.sched_name'><use id='fk' x='184' y='251' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='47' y='267' xlink:href='#nn'/><a xlink:href='#qrtz_simprop_triggers.trigger_name'><use id='pk' x='47' y='266' xlink:href='#pk'/><title>Pk pk_qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_simprop_triggers.trigger_name'><text id='ry.qrtz_simprop_triggers.trigger_name' x='63' y='276' onmouseover=\"hghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_name</text><title>trigger_name\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_simprop_triggers.trigger_name'><use id='fk' x='184' y='266' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='47' y='282' xlink:href='#nn'/><a xlink:href='#qrtz_simprop_triggers.trigger_group'><use id='pk' x='47' y='281' xlink:href='#pk'/><title>Pk pk_qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_simprop_triggers.trigger_group'><text id='ry.qrtz_simprop_triggers.trigger_group' x='63' y='291' onmouseover=\"hghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_triggers.sched_name','ry.qrtz_triggers.trigger_name','ry.qrtz_triggers.trigger_group'])\">trigger_group</text><title>trigger_group\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_simprop_triggers.trigger_group'><use id='fk' x='184' y='281' xlink:href='#fk'/><title>References qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <a xlink:href='#qrtz_simprop_triggers.str_prop_1'><text id='ry.qrtz_simprop_triggers.str_prop_1' x='63' y='306'>str_prop_1</text><title>str_prop_1\r\nvarchar(512)</title></a>\r\n<text x='192' y='303' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_simprop_triggers.str_prop_2'><text id='ry.qrtz_simprop_triggers.str_prop_2' x='63' y='321'>str_prop_2</text><title>str_prop_2\r\nvarchar(512)</title></a>\r\n<text x='192' y='318' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_simprop_triggers.str_prop_3'><text id='ry.qrtz_simprop_triggers.str_prop_3' x='63' y='336'>str_prop_3</text><title>str_prop_3\r\nvarchar(512)</title></a>\r\n<text x='192' y='333' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_simprop_triggers.int_prop_1'><text id='ry.qrtz_simprop_triggers.int_prop_1' x='63' y='351'>int_prop_1</text><title>int_prop_1\r\nint</title></a>\r\n<text x='192' y='348' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_simprop_triggers.int_prop_2'><text id='ry.qrtz_simprop_triggers.int_prop_2' x='63' y='366'>int_prop_2</text><title>int_prop_2\r\nint</title></a>\r\n<text x='192' y='363' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_simprop_triggers.long_prop_1'><text id='ry.qrtz_simprop_triggers.long_prop_1' x='63' y='381'>long_prop_1</text><title>long_prop_1\r\nbigint</title></a>\r\n<text x='192' y='378' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_simprop_triggers.long_prop_2'><text id='ry.qrtz_simprop_triggers.long_prop_2' x='63' y='396'>long_prop_2</text><title>long_prop_2\r\nbigint</title></a>\r\n<text x='192' y='393' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_simprop_triggers.dec_prop_1'><text id='ry.qrtz_simprop_triggers.dec_prop_1' x='63' y='411'>dec_prop_1</text><title>dec_prop_1\r\ndecimal(13,4)</title></a>\r\n<text x='192' y='408' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_simprop_triggers.dec_prop_2'><text id='ry.qrtz_simprop_triggers.dec_prop_2' x='63' y='426'>dec_prop_2</text><title>dec_prop_2\r\ndecimal(13,4)</title></a>\r\n<text x='192' y='423' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_simprop_triggers.bool_prop_1'><text id='ry.qrtz_simprop_triggers.bool_prop_1' x='63' y='441'>bool_prop_1</text><title>bool_prop_1\r\nvarchar(1)</title></a>\r\n<text x='192' y='438' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_simprop_triggers.bool_prop_2'><text id='ry.qrtz_simprop_triggers.bool_prop_2' x='63' y='456'>bool_prop_2</text><title>bool_prop_2\r\nvarchar(1)</title></a>\r\n<text x='192' y='453' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'qrtz_triggers' == -->\r\n<rect class='entity' x='255' y='188' width='120' height='285' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 255 214 L 255 195 Q 255 188 262 188 L 368 188 Q 375 188 375 195 L 375 214 L255 214 ' style='fill:url(#tbg_bfd4f5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='255' y='188' width='120' height='285' rx='7' ry='7' style='fill:none;stroke:#5f656e'/>\r\n<line class='delim' x1='255' y1='214' x2='375' y2='214' style='stroke:#5f656e'/>\r\n<line class='delim' x1='270' y1='214' x2='270' y2='473' style='stroke:#5f656e'/>\r\n<line class='delim' x1='364' y1='214' x2='364' y2='473' style='stroke:#5f656e'/>\r\n<a xlink:href='#qrtz_triggers'><text x='273' y='206'>qrtz_triggers</text><title>Table ry.qrtz_triggers</title></a>\r\n  <use id='nn' x='257' y='222' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.sched_name'><use id='pk' x='257' y='221' xlink:href='#pk'/><title>Pk pk_qrtz_triggers ( sched_name, trigger_name, trigger_group ) sched_name ( sched_name, job_name, job_group ) </title></a>\r\n<a xlink:href='#qrtz_triggers.sched_name'><text id='ry.qrtz_triggers.sched_name' x='273' y='231' onmouseover=\"hghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group','qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group','qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group'])\">sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<a xlink:href='#qrtz_triggers.sched_name'><use id='fk' x='364' y='221' xlink:href='#fk'/><title>References qrtz_job_details ( sched_name, job_name, job_group ) \r\nReferred by qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='257' y='237' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.trigger_name'><use id='pk' x='257' y='236' xlink:href='#pk'/><title>Pk pk_qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_triggers.trigger_name'><text id='ry.qrtz_triggers.trigger_name' x='273' y='246' onmouseover=\"hghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group'])\">trigger_name</text><title>trigger_name\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_triggers.trigger_name'><use id='ref' x='364' y='236' xlink:href='#ref'/><title>Referred by qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='257' y='252' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.trigger_group'><use id='pk' x='257' y='251' xlink:href='#pk'/><title>Pk pk_qrtz_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_triggers.trigger_group'><text id='ry.qrtz_triggers.trigger_group' x='273' y='261' onmouseover=\"hghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group'])\" onmouseout=\"uhghl(['qrtz_blob_triggers_qrtz_blob_triggers_ibfk_1','ry.qrtz_blob_triggers.sched_name','ry.qrtz_blob_triggers.trigger_name','ry.qrtz_blob_triggers.trigger_group','qrtz_cron_triggers_qrtz_cron_triggers_ibfk_1','ry.qrtz_cron_triggers.sched_name','ry.qrtz_cron_triggers.trigger_name','ry.qrtz_cron_triggers.trigger_group','qrtz_simple_triggers_qrtz_simple_triggers_ibfk_1','ry.qrtz_simple_triggers.sched_name','ry.qrtz_simple_triggers.trigger_name','ry.qrtz_simple_triggers.trigger_group','qrtz_simprop_triggers_qrtz_simprop_triggers_ibfk_1','ry.qrtz_simprop_triggers.sched_name','ry.qrtz_simprop_triggers.trigger_name','ry.qrtz_simprop_triggers.trigger_group'])\">trigger_group</text><title>trigger_group\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_triggers.trigger_group'><use id='ref' x='364' y='251' xlink:href='#ref'/><title>Referred by qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) \r\nReferred by qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) </title></a>\r\n  <use id='nn' x='257' y='267' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.job_name'><use id='idx' x='257' y='266' xlink:href='#idx'/><title>sched_name ( sched_name, job_name, job_group ) </title></a>\r\n<a xlink:href='#qrtz_triggers.job_name'><text id='ry.qrtz_triggers.job_name' x='273' y='276' onmouseover=\"hghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group'])\" onmouseout=\"uhghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group'])\">job_name</text><title>job_name\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_triggers.job_name'><use id='fk' x='364' y='266' xlink:href='#fk'/><title>References qrtz_job_details ( sched_name, job_name, job_group ) </title></a>\r\n  <use id='nn' x='257' y='282' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.job_group'><use id='idx' x='257' y='281' xlink:href='#idx'/><title>sched_name ( sched_name, job_name, job_group ) </title></a>\r\n<a xlink:href='#qrtz_triggers.job_group'><text id='ry.qrtz_triggers.job_group' x='273' y='291' onmouseover=\"hghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group'])\" onmouseout=\"uhghl(['qrtz_triggers_qrtz_triggers_ibfk_1','ry.qrtz_job_details.sched_name','ry.qrtz_job_details.job_name','ry.qrtz_job_details.job_group'])\">job_group</text><title>job_group\r\n* varchar(200)</title></a>\r\n<a xlink:href='#qrtz_triggers.job_group'><use id='fk' x='364' y='281' xlink:href='#fk'/><title>References qrtz_job_details ( sched_name, job_name, job_group ) </title></a>\r\n  <a xlink:href='#qrtz_triggers.description'><text id='ry.qrtz_triggers.description' x='273' y='306'>description</text><title>description\r\nvarchar(250)</title></a>\r\n<text x='372' y='303' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_triggers.next_fire_time'><text id='ry.qrtz_triggers.next_fire_time' x='273' y='321'>next_fire_time</text><title>next_fire_time\r\nbigint</title></a>\r\n<text x='372' y='318' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_triggers.prev_fire_time'><text id='ry.qrtz_triggers.prev_fire_time' x='273' y='336'>prev_fire_time</text><title>prev_fire_time\r\nbigint</title></a>\r\n<text x='372' y='333' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_triggers.priority'><text id='ry.qrtz_triggers.priority' x='273' y='351'>priority</text><title>priority\r\nint</title></a>\r\n<text x='372' y='348' text-anchor='end' class='colType'>#</text>  <use id='nn' x='257' y='357' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.trigger_state'><text id='ry.qrtz_triggers.trigger_state' x='273' y='366'>trigger_state</text><title>trigger_state\r\n* varchar(16)</title></a>\r\n<text x='372' y='363' text-anchor='end' class='colType'>t</text>  <use id='nn' x='257' y='372' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.trigger_type'><text id='ry.qrtz_triggers.trigger_type' x='273' y='381'>trigger_type</text><title>trigger_type\r\n* varchar(8)</title></a>\r\n<text x='372' y='378' text-anchor='end' class='colType'>t</text>  <use id='nn' x='257' y='387' xlink:href='#nn'/><a xlink:href='#qrtz_triggers.start_time'><text id='ry.qrtz_triggers.start_time' x='273' y='396'>start_time</text><title>start_time\r\n* bigint</title></a>\r\n<text x='372' y='393' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_triggers.end_time'><text id='ry.qrtz_triggers.end_time' x='273' y='411'>end_time</text><title>end_time\r\nbigint</title></a>\r\n<text x='372' y='408' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_triggers.calendar_name'><text id='ry.qrtz_triggers.calendar_name' x='273' y='426'>calendar_name</text><title>calendar_name\r\nvarchar(200)</title></a>\r\n<text x='372' y='423' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_triggers.misfire_instr'><text id='ry.qrtz_triggers.misfire_instr' x='273' y='441'>misfire_instr</text><title>misfire_instr\r\nsmallint</title></a>\r\n<text x='372' y='438' text-anchor='end' class='colType'>#</text>  <a xlink:href='#qrtz_triggers.job_data'><text id='ry.qrtz_triggers.job_data' x='273' y='456'>job_data</text><title>job_data\r\nblob</title></a>\r\n<text x='372' y='453' text-anchor='end' class='colType'>~</text>\r\n<!-- == Table 'sys_dict_data' == -->\r\n<rect class='entity' x='1170' y='38' width='105' height='210' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1170 64 L 1170 45 Q 1170 38 1177 38 L 1268 38 Q 1275 38 1275 45 L 1275 64 L1170 64 ' style='fill:url(#tbg_c8f5bf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1170' y='38' width='105' height='210' rx='7' ry='7' style='fill:none;stroke:#626e5f'/>\r\n<line class='delim' x1='1170' y1='64' x2='1275' y2='64' style='stroke:#626e5f'/>\r\n<line class='delim' x1='1185' y1='64' x2='1185' y2='248' style='stroke:#626e5f'/>\r\n<line class='delim' x1='1264' y1='64' x2='1264' y2='248' style='stroke:#626e5f'/>\r\n<a xlink:href='#sys_dict_data'><text x='1180' y='56'>sys_dict_data</text><title>Table ry.sys_dict_data</title></a>\r\n  <use id='nn' x='1172' y='72' xlink:href='#nn'/><a xlink:href='#sys_dict_data.dict_code'><use id='pk' x='1172' y='71' xlink:href='#pk'/><title>Pk pk_sys_dict_data ( dict_code ) </title></a>\r\n<a xlink:href='#sys_dict_data.dict_code'><text id='ry.sys_dict_data.dict_code' x='1188' y='81'>dict_code</text><title>dict_code\r\n* int\r\n字典编码</title></a>\r\n<text x='1272' y='78' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dict_data.dict_sort'><text id='ry.sys_dict_data.dict_sort' x='1188' y='96'>dict_sort</text><title>dict_sort\r\nint default 0\r\n字典排序</title></a>\r\n<text x='1272' y='93' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dict_data.dict_label'><text id='ry.sys_dict_data.dict_label' x='1188' y='111'>dict_label</text><title>dict_label\r\nvarchar(100) default ''\r\n字典标签</title></a>\r\n<text x='1272' y='108' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dict_data.dict_value'><text id='ry.sys_dict_data.dict_value' x='1188' y='126'>dict_value</text><title>dict_value\r\nvarchar(100) default ''\r\n字典键值</title></a>\r\n<text x='1272' y='123' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dict_data.dict_type'><text id='ry.sys_dict_data.dict_type' x='1188' y='141'>dict_type</text><title>dict_type\r\nvarchar(100) default ''\r\n字典类型</title></a>\r\n<text x='1272' y='138' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dict_data.status'><text id='ry.sys_dict_data.status' x='1188' y='156'>status</text><title>status\r\nint default 0\r\n状态（0正常 1禁用）</title></a>\r\n<text x='1272' y='153' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dict_data.create_by'><text id='ry.sys_dict_data.create_by' x='1188' y='171'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='1272' y='168' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1172' y='177' xlink:href='#nn'/><a xlink:href='#sys_dict_data.create_time'><text id='ry.sys_dict_data.create_time' x='1188' y='186'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='1272' y='183' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_dict_data.update_by'><text id='ry.sys_dict_data.update_by' x='1188' y='201'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='1272' y='198' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1172' y='207' xlink:href='#nn'/><a xlink:href='#sys_dict_data.update_time'><text id='ry.sys_dict_data.update_time' x='1188' y='216'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='1272' y='213' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_dict_data.remark'><text id='ry.sys_dict_data.remark' x='1188' y='231'>remark</text><title>remark\r\nvarchar(500) default ''\r\n备注</title></a>\r\n<text x='1272' y='228' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'sys_dict_type' == -->\r\n<rect class='entity' x='1005' y='38' width='105' height='180' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1005 64 L 1005 45 Q 1005 38 1012 38 L 1103 38 Q 1110 38 1110 45 L 1110 64 L1005 64 ' style='fill:url(#tbg_c8f5bf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1005' y='38' width='105' height='180' rx='7' ry='7' style='fill:none;stroke:#626e5f'/>\r\n<line class='delim' x1='1005' y1='64' x2='1110' y2='64' style='stroke:#626e5f'/>\r\n<line class='delim' x1='1020' y1='64' x2='1020' y2='218' style='stroke:#626e5f'/>\r\n<line class='delim' x1='1099' y1='64' x2='1099' y2='218' style='stroke:#626e5f'/>\r\n<a xlink:href='#sys_dict_type'><text x='1015' y='56'>sys_dict_type</text><title>Table ry.sys_dict_type</title></a>\r\n  <use id='nn' x='1007' y='72' xlink:href='#nn'/><a xlink:href='#sys_dict_type.dict_id'><use id='pk' x='1007' y='71' xlink:href='#pk'/><title>Pk pk_sys_dict_type ( dict_id ) </title></a>\r\n<a xlink:href='#sys_dict_type.dict_id'><text id='ry.sys_dict_type.dict_id' x='1023' y='81'>dict_id</text><title>dict_id\r\n* int\r\n字典主键</title></a>\r\n<text x='1107' y='78' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dict_type.dict_name'><text id='ry.sys_dict_type.dict_name' x='1023' y='96'>dict_name</text><title>dict_name\r\nvarchar(100) default ''\r\n字典名称</title></a>\r\n<text x='1107' y='93' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dict_type.dict_type'><use id='unq' x='1007' y='101' xlink:href='#unq'/><title>Unq dict_type ( dict_type ) </title></a>\r\n<a xlink:href='#sys_dict_type.dict_type'><text id='ry.sys_dict_type.dict_type' x='1023' y='111'>dict_type</text><title>dict_type\r\nvarchar(100) default ''\r\n字典类型</title></a>\r\n<text x='1107' y='108' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dict_type.status'><text id='ry.sys_dict_type.status' x='1023' y='126'>status</text><title>status\r\nint default 0\r\n状态（0正常 1禁用）</title></a>\r\n<text x='1107' y='123' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dict_type.create_by'><text id='ry.sys_dict_type.create_by' x='1023' y='141'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='1107' y='138' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1007' y='147' xlink:href='#nn'/><a xlink:href='#sys_dict_type.create_time'><text id='ry.sys_dict_type.create_time' x='1023' y='156'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='1107' y='153' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_dict_type.update_by'><text id='ry.sys_dict_type.update_by' x='1023' y='171'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='1107' y='168' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1007' y='177' xlink:href='#nn'/><a xlink:href='#sys_dict_type.update_time'><text id='ry.sys_dict_type.update_time' x='1023' y='186'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='1107' y='183' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_dict_type.remark'><text id='ry.sys_dict_type.remark' x='1023' y='201'>remark</text><title>remark\r\nvarchar(500) default ''\r\n备注</title></a>\r\n<text x='1107' y='198' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'sys_job' == -->\r\n<rect class='entity' x='1545' y='38' width='135' height='225' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1545 64 L 1545 45 Q 1545 38 1552 38 L 1673 38 Q 1680 38 1680 45 L 1680 64 L1545 64 ' style='fill:url(#tbg_f5ddbf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1545' y='38' width='135' height='225' rx='7' ry='7' style='fill:none;stroke:#6e675f'/>\r\n<line class='delim' x1='1545' y1='64' x2='1680' y2='64' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1560' y1='64' x2='1560' y2='263' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1669' y1='64' x2='1669' y2='263' style='stroke:#6e675f'/>\r\n<a xlink:href='#sys_job'><text x='1588' y='56'>sys_job</text><title>Table ry.sys_job</title></a>\r\n  <use id='nn' x='1547' y='72' xlink:href='#nn'/><a xlink:href='#sys_job.job_id'><use id='pk' x='1547' y='71' xlink:href='#pk'/><title>Pk pk_sys_job ( job_id, job_name, job_group ) </title></a>\r\n<a xlink:href='#sys_job.job_id'><text id='ry.sys_job.job_id' x='1563' y='81'>job_id</text><title>job_id\r\n* int\r\n任务ID</title></a>\r\n<text x='1677' y='78' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1547' y='87' xlink:href='#nn'/><a xlink:href='#sys_job.job_name'><use id='pk' x='1547' y='86' xlink:href='#pk'/><title>Pk pk_sys_job ( job_id, job_name, job_group ) </title></a>\r\n<a xlink:href='#sys_job.job_name'><text id='ry.sys_job.job_name' x='1563' y='96'>job_name</text><title>job_name\r\n* varchar(64) default ''\r\n任务名称</title></a>\r\n<text x='1677' y='93' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1547' y='102' xlink:href='#nn'/><a xlink:href='#sys_job.job_group'><use id='pk' x='1547' y='101' xlink:href='#pk'/><title>Pk pk_sys_job ( job_id, job_name, job_group ) </title></a>\r\n<a xlink:href='#sys_job.job_group'><text id='ry.sys_job.job_group' x='1563' y='111'>job_group</text><title>job_group\r\n* varchar(64) default ''\r\n任务组名</title></a>\r\n<text x='1677' y='108' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job.method_name'><text id='ry.sys_job.method_name' x='1563' y='126'>method_name</text><title>method_name\r\nvarchar(500) default ''\r\n任务方法</title></a>\r\n<text x='1677' y='123' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job.params'><text id='ry.sys_job.params' x='1563' y='141'>params</text><title>params\r\nvarchar(200) default ''\r\n方法参数</title></a>\r\n<text x='1677' y='138' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job.cron_expression'><text id='ry.sys_job.cron_expression' x='1563' y='156'>cron_expression</text><title>cron_expression\r\nvarchar(255) default ''\r\ncron执行表达式</title></a>\r\n<text x='1677' y='153' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job.status'><text id='ry.sys_job.status' x='1563' y='171'>status</text><title>status\r\nint default 0\r\n状态（0正常 1暂停）</title></a>\r\n<text x='1677' y='168' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_job.create_by'><text id='ry.sys_job.create_by' x='1563' y='186'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='1677' y='183' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1547' y='192' xlink:href='#nn'/><a xlink:href='#sys_job.create_time'><text id='ry.sys_job.create_time' x='1563' y='201'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='1677' y='198' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_job.update_by'><text id='ry.sys_job.update_by' x='1563' y='216'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='1677' y='213' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1547' y='222' xlink:href='#nn'/><a xlink:href='#sys_job.update_time'><text id='ry.sys_job.update_time' x='1563' y='231'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='1677' y='228' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_job.remark'><text id='ry.sys_job.remark' x='1563' y='246'>remark</text><title>remark\r\nvarchar(500) default ''\r\n备注信息</title></a>\r\n<text x='1677' y='243' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'sys_job_log' == -->\r\n<rect class='entity' x='1365' y='38' width='120' height='180' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1365 64 L 1365 45 Q 1365 38 1372 38 L 1478 38 Q 1485 38 1485 45 L 1485 64 L1365 64 ' style='fill:url(#tbg_f5ddbf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1365' y='38' width='120' height='180' rx='7' ry='7' style='fill:none;stroke:#6e675f'/>\r\n<line class='delim' x1='1365' y1='64' x2='1485' y2='64' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1380' y1='64' x2='1380' y2='218' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1474' y1='64' x2='1474' y2='218' style='stroke:#6e675f'/>\r\n<a xlink:href='#sys_job_log'><text x='1389' y='56'>sys_job_log</text><title>Table ry.sys_job_log</title></a>\r\n  <use id='nn' x='1367' y='72' xlink:href='#nn'/><a xlink:href='#sys_job_log.job_log_id'><use id='pk' x='1367' y='71' xlink:href='#pk'/><title>Pk pk_sys_job_log ( job_log_id ) </title></a>\r\n<a xlink:href='#sys_job_log.job_log_id'><text id='ry.sys_job_log.job_log_id' x='1383' y='81'>job_log_id</text><title>job_log_id\r\n* int\r\n任务日志ID</title></a>\r\n<text x='1482' y='78' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1367' y='87' xlink:href='#nn'/><a xlink:href='#sys_job_log.job_name'><text id='ry.sys_job_log.job_name' x='1383' y='96'>job_name</text><title>job_name\r\n* varchar(64)\r\n任务名称</title></a>\r\n<text x='1482' y='93' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1367' y='102' xlink:href='#nn'/><a xlink:href='#sys_job_log.job_group'><text id='ry.sys_job_log.job_group' x='1383' y='111'>job_group</text><title>job_group\r\n* varchar(64)\r\n任务组名</title></a>\r\n<text x='1482' y='108' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job_log.method_name'><text id='ry.sys_job_log.method_name' x='1383' y='126'>method_name</text><title>method_name\r\nvarchar(500)\r\n任务方法</title></a>\r\n<text x='1482' y='123' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job_log.params'><text id='ry.sys_job_log.params' x='1383' y='141'>params</text><title>params\r\nvarchar(200) default ''\r\n方法参数</title></a>\r\n<text x='1482' y='138' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job_log.job_message'><text id='ry.sys_job_log.job_message' x='1383' y='156'>job_message</text><title>job_message\r\nvarchar(500)\r\n日志信息</title></a>\r\n<text x='1482' y='153' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_job_log.is_exception'><text id='ry.sys_job_log.is_exception' x='1383' y='171'>is_exception</text><title>is_exception\r\nint default 0\r\n是否异常</title></a>\r\n<text x='1482' y='168' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_job_log.exception_info'><text id='ry.sys_job_log.exception_info' x='1383' y='186'>exception_info</text><title>exception_info\r\ntext\r\n异常信息</title></a>\r\n<text x='1482' y='183' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1367' y='192' xlink:href='#nn'/><a xlink:href='#sys_job_log.create_time'><text id='ry.sys_job_log.create_time' x='1383' y='201'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='1482' y='198' text-anchor='end' class='colType'>d</text>\r\n<!-- == Table 'sys_logininfor' == -->\r\n<rect class='entity' x='1740' y='323' width='105' height='165' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1740 349 L 1740 330 Q 1740 323 1747 323 L 1838 323 Q 1845 323 1845 330 L 1845 349 L1740 349 ' style='fill:url(#tbg_f5ddbf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1740' y='323' width='105' height='165' rx='7' ry='7' style='fill:none;stroke:#6e675f'/>\r\n<line class='delim' x1='1740' y1='349' x2='1845' y2='349' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1755' y1='349' x2='1755' y2='488' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1834' y1='349' x2='1834' y2='488' style='stroke:#6e675f'/>\r\n<a xlink:href='#sys_logininfor'><text x='1747' y='341'>sys_logininfor</text><title>Table ry.sys_logininfor</title></a>\r\n  <use id='nn' x='1742' y='357' xlink:href='#nn'/><a xlink:href='#sys_logininfor.info_id'><use id='pk' x='1742' y='356' xlink:href='#pk'/><title>Pk pk_sys_logininfor ( info_id ) </title></a>\r\n<a xlink:href='#sys_logininfor.info_id'><text id='ry.sys_logininfor.info_id' x='1758' y='366'>info_id</text><title>info_id\r\n* int\r\n访问ID</title></a>\r\n<text x='1842' y='363' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_logininfor.login_name'><text id='ry.sys_logininfor.login_name' x='1758' y='381'>login_name</text><title>login_name\r\nvarchar(50) default ''\r\n登录账号</title></a>\r\n<text x='1842' y='378' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_logininfor.ipaddr'><text id='ry.sys_logininfor.ipaddr' x='1758' y='396'>ipaddr</text><title>ipaddr\r\nvarchar(50) default ''\r\n登录IP地址</title></a>\r\n<text x='1842' y='393' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_logininfor.browser'><text id='ry.sys_logininfor.browser' x='1758' y='411'>browser</text><title>browser\r\nvarchar(50) default ''\r\n浏览器类型</title></a>\r\n<text x='1842' y='408' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_logininfor.os'><text id='ry.sys_logininfor.os' x='1758' y='426'>os</text><title>os\r\nvarchar(50) default ''\r\n操作系统</title></a>\r\n<text x='1842' y='423' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_logininfor.status'><text id='ry.sys_logininfor.status' x='1758' y='441'>status</text><title>status\r\nint default 0\r\n登录状态 0成功 1失败</title></a>\r\n<text x='1842' y='438' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_logininfor.msg'><text id='ry.sys_logininfor.msg' x='1758' y='456'>msg</text><title>msg\r\nvarchar(255) default ''\r\n提示消息</title></a>\r\n<text x='1842' y='453' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1742' y='462' xlink:href='#nn'/><a xlink:href='#sys_logininfor.login_time'><text id='ry.sys_logininfor.login_time' x='1758' y='471'>login_time</text><title>login_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n访问时间</title></a>\r\n<text x='1842' y='468' text-anchor='end' class='colType'>d</text>\r\n<!-- == Table 'sys_menu' == -->\r\n<rect class='entity' x='1380' y='323' width='105' height='255' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1380 349 L 1380 330 Q 1380 323 1387 323 L 1478 323 Q 1485 323 1485 330 L 1485 349 L1380 349 ' style='fill:url(#tbg_f5ddbf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1380' y='323' width='105' height='255' rx='7' ry='7' style='fill:none;stroke:#6e675f'/>\r\n<line class='delim' x1='1380' y1='349' x2='1485' y2='349' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1395' y1='349' x2='1395' y2='578' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1474' y1='349' x2='1474' y2='578' style='stroke:#6e675f'/>\r\n<a xlink:href='#sys_menu'><text x='1405' y='341'>sys_menu</text><title>Table ry.sys_menu</title></a>\r\n  <use id='nn' x='1382' y='357' xlink:href='#nn'/><a xlink:href='#sys_menu.menu_id'><use id='pk' x='1382' y='356' xlink:href='#pk'/><title>Pk pk_sys_menu ( menu_id ) </title></a>\r\n<a xlink:href='#sys_menu.menu_id'><text id='ry.sys_menu.menu_id' x='1398' y='366'>menu_id</text><title>menu_id\r\n* int\r\n菜单ID</title></a>\r\n<text x='1482' y='363' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1382' y='372' xlink:href='#nn'/><a xlink:href='#sys_menu.menu_name'><text id='ry.sys_menu.menu_name' x='1398' y='381'>menu_name</text><title>menu_name\r\n* varchar(50)\r\n菜单名称</title></a>\r\n<text x='1482' y='378' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_menu.parent_id'><text id='ry.sys_menu.parent_id' x='1398' y='396'>parent_id</text><title>parent_id\r\nint default 0\r\n父菜单ID</title></a>\r\n<text x='1482' y='393' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_menu.order_num'><text id='ry.sys_menu.order_num' x='1398' y='411'>order_num</text><title>order_num\r\nint\r\n显示顺序</title></a>\r\n<text x='1482' y='408' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_menu.url'><text id='ry.sys_menu.url' x='1398' y='426'>url</text><title>url\r\nvarchar(200) default ''\r\n请求地址</title></a>\r\n<text x='1482' y='423' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_menu.menu_type'><text id='ry.sys_menu.menu_type' x='1398' y='441'>menu_type</text><title>menu_type\r\nchar(1) default ''\r\n类型:M目录,C菜单,F按钮</title></a>\r\n<text x='1482' y='438' text-anchor='end' class='colType'>c</text>  <a xlink:href='#sys_menu.visible'><text id='ry.sys_menu.visible' x='1398' y='456'>visible</text><title>visible\r\nint default 0\r\n菜单状态:0显示,1隐藏</title></a>\r\n<text x='1482' y='453' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_menu.perms'><text id='ry.sys_menu.perms' x='1398' y='471'>perms</text><title>perms\r\nvarchar(100) default ''\r\n权限标识</title></a>\r\n<text x='1482' y='468' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_menu.icon'><text id='ry.sys_menu.icon' x='1398' y='486'>icon</text><title>icon\r\nvarchar(100) default ''\r\n菜单图标</title></a>\r\n<text x='1482' y='483' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_menu.create_by'><text id='ry.sys_menu.create_by' x='1398' y='501'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='1482' y='498' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1382' y='507' xlink:href='#nn'/><a xlink:href='#sys_menu.create_time'><text id='ry.sys_menu.create_time' x='1398' y='516'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='1482' y='513' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_menu.update_by'><text id='ry.sys_menu.update_by' x='1398' y='531'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='1482' y='528' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1382' y='537' xlink:href='#nn'/><a xlink:href='#sys_menu.update_time'><text id='ry.sys_menu.update_time' x='1398' y='546'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='1482' y='543' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_menu.remark'><text id='ry.sys_menu.remark' x='1398' y='561'>remark</text><title>remark\r\nvarchar(500) default ''\r\n备注</title></a>\r\n<text x='1482' y='558' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'sys_oper_log' == -->\r\n<rect class='entity' x='1005' y='278' width='105' height='240' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1005 304 L 1005 285 Q 1005 278 1012 278 L 1103 278 Q 1110 278 1110 285 L 1110 304 L1005 304 ' style='fill:url(#tbg_c8f5bf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1005' y='278' width='105' height='240' rx='7' ry='7' style='fill:none;stroke:#626e5f'/>\r\n<line class='delim' x1='1005' y1='304' x2='1110' y2='304' style='stroke:#626e5f'/>\r\n<line class='delim' x1='1020' y1='304' x2='1020' y2='518' style='stroke:#626e5f'/>\r\n<line class='delim' x1='1099' y1='304' x2='1099' y2='518' style='stroke:#626e5f'/>\r\n<a xlink:href='#sys_oper_log'><text x='1018' y='296'>sys_oper_log</text><title>Table ry.sys_oper_log</title></a>\r\n  <use id='nn' x='1007' y='312' xlink:href='#nn'/><a xlink:href='#sys_oper_log.oper_id'><use id='pk' x='1007' y='311' xlink:href='#pk'/><title>Pk pk_sys_oper_log ( oper_id ) </title></a>\r\n<a xlink:href='#sys_oper_log.oper_id'><text id='ry.sys_oper_log.oper_id' x='1023' y='321'>oper_id</text><title>oper_id\r\n* int\r\n日志主键</title></a>\r\n<text x='1107' y='318' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_oper_log.title'><text id='ry.sys_oper_log.title' x='1023' y='336'>title</text><title>title\r\nvarchar(50) default ''\r\n模块标题</title></a>\r\n<text x='1107' y='333' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.action'><text id='ry.sys_oper_log.action' x='1023' y='351'>action</text><title>action\r\nvarchar(100) default ''\r\n功能请求</title></a>\r\n<text x='1107' y='348' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.method'><text id='ry.sys_oper_log.method' x='1023' y='366'>method</text><title>method\r\nvarchar(100) default ''\r\n方法名称</title></a>\r\n<text x='1107' y='363' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.channel'><text id='ry.sys_oper_log.channel' x='1023' y='381'>channel</text><title>channel\r\nvarchar(20) default ''\r\n来源渠道</title></a>\r\n<text x='1107' y='378' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.login_name'><text id='ry.sys_oper_log.login_name' x='1023' y='396'>login_name</text><title>login_name\r\nvarchar(50) default ''\r\n登录账号</title></a>\r\n<text x='1107' y='393' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.dept_name'><text id='ry.sys_oper_log.dept_name' x='1023' y='411'>dept_name</text><title>dept_name\r\nvarchar(50) default ''\r\n部门名称</title></a>\r\n<text x='1107' y='408' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.oper_url'><text id='ry.sys_oper_log.oper_url' x='1023' y='426'>oper_url</text><title>oper_url\r\nvarchar(255) default ''\r\n请求URL</title></a>\r\n<text x='1107' y='423' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.oper_ip'><text id='ry.sys_oper_log.oper_ip' x='1023' y='441'>oper_ip</text><title>oper_ip\r\nvarchar(30) default ''\r\n主机地址</title></a>\r\n<text x='1107' y='438' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.oper_param'><text id='ry.sys_oper_log.oper_param' x='1023' y='456'>oper_param</text><title>oper_param\r\nvarchar(255) default ''\r\n请求参数</title></a>\r\n<text x='1107' y='453' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_oper_log.status'><text id='ry.sys_oper_log.status' x='1023' y='471'>status</text><title>status\r\nint default 0\r\n操作状态 0正常 1异常</title></a>\r\n<text x='1107' y='468' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_oper_log.error_msg'><text id='ry.sys_oper_log.error_msg' x='1023' y='486'>error_msg</text><title>error_msg\r\nvarchar(2000) default ''\r\n错误消息</title></a>\r\n<text x='1107' y='483' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1007' y='492' xlink:href='#nn'/><a xlink:href='#sys_oper_log.oper_time'><text id='ry.sys_oper_log.oper_time' x='1023' y='501'>oper_time</text><title>oper_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n操作时间</title></a>\r\n<text x='1107' y='498' text-anchor='end' class='colType'>d</text>\r\n<!-- == Table 'sys_post' == -->\r\n<rect class='entity' x='1740' y='38' width='105' height='195' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1740 64 L 1740 45 Q 1740 38 1747 38 L 1838 38 Q 1845 38 1845 45 L 1845 64 L1740 64 ' style='fill:url(#tbg_f5ddbf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1740' y='38' width='105' height='195' rx='7' ry='7' style='fill:none;stroke:#6e675f'/>\r\n<line class='delim' x1='1740' y1='64' x2='1845' y2='64' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1755' y1='64' x2='1755' y2='233' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1834' y1='64' x2='1834' y2='233' style='stroke:#6e675f'/>\r\n<a xlink:href='#sys_post'><text x='1765' y='56'>sys_post</text><title>Table ry.sys_post</title></a>\r\n  <use id='nn' x='1742' y='72' xlink:href='#nn'/><a xlink:href='#sys_post.post_id'><use id='pk' x='1742' y='71' xlink:href='#pk'/><title>Pk pk_sys_post ( post_id ) </title></a>\r\n<a xlink:href='#sys_post.post_id'><text id='ry.sys_post.post_id' x='1758' y='81'>post_id</text><title>post_id\r\n* int\r\n岗位ID</title></a>\r\n<text x='1842' y='78' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1742' y='87' xlink:href='#nn'/><a xlink:href='#sys_post.post_code'><text id='ry.sys_post.post_code' x='1758' y='96'>post_code</text><title>post_code\r\n* varchar(64)\r\n岗位编码</title></a>\r\n<text x='1842' y='93' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1742' y='102' xlink:href='#nn'/><a xlink:href='#sys_post.post_name'><text id='ry.sys_post.post_name' x='1758' y='111'>post_name</text><title>post_name\r\n* varchar(100)\r\n岗位名称</title></a>\r\n<text x='1842' y='108' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1742' y='117' xlink:href='#nn'/><a xlink:href='#sys_post.post_sort'><text id='ry.sys_post.post_sort' x='1758' y='126'>post_sort</text><title>post_sort\r\n* int\r\n显示顺序</title></a>\r\n<text x='1842' y='123' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1742' y='132' xlink:href='#nn'/><a xlink:href='#sys_post.status'><text id='ry.sys_post.status' x='1758' y='141'>status</text><title>status\r\n* int\r\n状态（0正常 1停用）</title></a>\r\n<text x='1842' y='138' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_post.create_by'><text id='ry.sys_post.create_by' x='1758' y='156'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='1842' y='153' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1742' y='162' xlink:href='#nn'/><a xlink:href='#sys_post.create_time'><text id='ry.sys_post.create_time' x='1758' y='171'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='1842' y='168' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_post.update_by'><text id='ry.sys_post.update_by' x='1758' y='186'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='1842' y='183' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1742' y='192' xlink:href='#nn'/><a xlink:href='#sys_post.update_time'><text id='ry.sys_post.update_time' x='1758' y='201'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='1842' y='198' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_post.remark'><text id='ry.sys_post.remark' x='1758' y='216'>remark</text><title>remark\r\nvarchar(500) default ''\r\n备注</title></a>\r\n<text x='1842' y='213' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'sys_role' == -->\r\n<rect class='entity' x='1545' y='458' width='105' height='195' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1545 484 L 1545 465 Q 1545 458 1552 458 L 1643 458 Q 1650 458 1650 465 L 1650 484 L1545 484 ' style='fill:url(#tbg_f5ddbf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1545' y='458' width='105' height='195' rx='7' ry='7' style='fill:none;stroke:#6e675f'/>\r\n<line class='delim' x1='1545' y1='484' x2='1650' y2='484' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1560' y1='484' x2='1560' y2='653' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1639' y1='484' x2='1639' y2='653' style='stroke:#6e675f'/>\r\n<a xlink:href='#sys_role'><text x='1570' y='476'>sys_role</text><title>Table ry.sys_role</title></a>\r\n  <use id='nn' x='1547' y='492' xlink:href='#nn'/><a xlink:href='#sys_role.role_id'><use id='pk' x='1547' y='491' xlink:href='#pk'/><title>Pk pk_sys_role ( role_id ) </title></a>\r\n<a xlink:href='#sys_role.role_id'><text id='ry.sys_role.role_id' x='1563' y='501'>role_id</text><title>role_id\r\n* int\r\n角色ID</title></a>\r\n<text x='1647' y='498' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1547' y='507' xlink:href='#nn'/><a xlink:href='#sys_role.role_name'><text id='ry.sys_role.role_name' x='1563' y='516'>role_name</text><title>role_name\r\n* varchar(30)\r\n角色名称</title></a>\r\n<text x='1647' y='513' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1547' y='522' xlink:href='#nn'/><a xlink:href='#sys_role.role_key'><text id='ry.sys_role.role_key' x='1563' y='531'>role_key</text><title>role_key\r\n* varchar(100)\r\n角色权限字符串</title></a>\r\n<text x='1647' y='528' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1547' y='537' xlink:href='#nn'/><a xlink:href='#sys_role.role_sort'><text id='ry.sys_role.role_sort' x='1563' y='546'>role_sort</text><title>role_sort\r\n* int\r\n显示顺序</title></a>\r\n<text x='1647' y='543' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_role.status'><text id='ry.sys_role.status' x='1563' y='561'>status</text><title>status\r\nint default 0\r\n角色状态:0正常,1禁用</title></a>\r\n<text x='1647' y='558' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_role.create_by'><text id='ry.sys_role.create_by' x='1563' y='576'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='1647' y='573' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1547' y='582' xlink:href='#nn'/><a xlink:href='#sys_role.create_time'><text id='ry.sys_role.create_time' x='1563' y='591'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='1647' y='588' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_role.update_by'><text id='ry.sys_role.update_by' x='1563' y='606'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='1647' y='603' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1547' y='612' xlink:href='#nn'/><a xlink:href='#sys_role.update_time'><text id='ry.sys_role.update_time' x='1563' y='621'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='1647' y='618' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_role.remark'><text id='ry.sys_role.remark' x='1563' y='636'>remark</text><title>remark\r\nvarchar(500) default ''\r\n备注</title></a>\r\n<text x='1647' y='633' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'sys_role_menu' == -->\r\n<rect class='entity' x='1545' y='323' width='90' height='75' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1545 349 L 1545 330 Q 1545 323 1552 323 L 1628 323 Q 1635 323 1635 330 L 1635 349 L1545 349 ' style='fill:url(#tbg_f5ddbf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1545' y='323' width='90' height='75' rx='7' ry='7' style='fill:none;stroke:#6e675f'/>\r\n<line class='delim' x1='1545' y1='349' x2='1635' y2='349' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1560' y1='349' x2='1560' y2='398' style='stroke:#6e675f'/>\r\n<line class='delim' x1='1624' y1='349' x2='1624' y2='398' style='stroke:#6e675f'/>\r\n<a xlink:href='#sys_role_menu'><text x='1548' y='341'>sys_role_menu</text><title>Table ry.sys_role_menu</title></a>\r\n  <use id='nn' x='1547' y='357' xlink:href='#nn'/><a xlink:href='#sys_role_menu.role_id'><use id='pk' x='1547' y='356' xlink:href='#pk'/><title>Pk pk_sys_role_menu ( role_id, menu_id ) </title></a>\r\n<a xlink:href='#sys_role_menu.role_id'><text id='ry.sys_role_menu.role_id' x='1563' y='366'>role_id</text><title>role_id\r\n* int\r\n角色ID</title></a>\r\n<text x='1632' y='363' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1547' y='372' xlink:href='#nn'/><a xlink:href='#sys_role_menu.menu_id'><use id='pk' x='1547' y='371' xlink:href='#pk'/><title>Pk pk_sys_role_menu ( role_id, menu_id ) </title></a>\r\n<a xlink:href='#sys_role_menu.menu_id'><text id='ry.sys_role_menu.menu_id' x='1563' y='381'>menu_id</text><title>menu_id\r\n* int\r\n菜单ID</title></a>\r\n<text x='1632' y='378' text-anchor='end' class='colType'>#</text>\r\n<!-- == Table 'sys_user' == -->\r\n<rect class='entity' x='690' y='83' width='105' height='270' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 690 109 L 690 90 Q 690 83 697 83 L 788 83 Q 795 83 795 90 L 795 109 L690 109 ' style='fill:url(#tbg_c8f5bf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='690' y='83' width='105' height='270' rx='7' ry='7' style='fill:none;stroke:#626e5f'/>\r\n<line class='delim' x1='690' y1='109' x2='795' y2='109' style='stroke:#626e5f'/>\r\n<line class='delim' x1='705' y1='109' x2='705' y2='353' style='stroke:#626e5f'/>\r\n<line class='delim' x1='784' y1='109' x2='784' y2='353' style='stroke:#626e5f'/>\r\n<a xlink:href='#sys_user'><text x='715' y='101'>sys_user</text><title>Table ry.sys_user</title></a>\r\n  <use id='nn' x='692' y='117' xlink:href='#nn'/><a xlink:href='#sys_user.user_id'><use id='pk' x='692' y='116' xlink:href='#pk'/><title>Pk pk_sys_user ( user_id ) </title></a>\r\n<a xlink:href='#sys_user.user_id'><text id='ry.sys_user.user_id' x='708' y='126'>user_id</text><title>user_id\r\n* int\r\n用户ID</title></a>\r\n<text x='792' y='123' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_user.dept_id'><text id='ry.sys_user.dept_id' x='708' y='141'>dept_id</text><title>dept_id\r\nint\r\n部门ID</title></a>\r\n<text x='792' y='138' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_user.login_name'><text id='ry.sys_user.login_name' x='708' y='156'>login_name</text><title>login_name\r\nvarchar(30) default ''\r\n登录账号</title></a>\r\n<text x='792' y='153' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user.user_name'><text id='ry.sys_user.user_name' x='708' y='171'>user_name</text><title>user_name\r\nvarchar(30) default ''\r\n用户昵称</title></a>\r\n<text x='792' y='168' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user.email'><text id='ry.sys_user.email' x='708' y='186'>email</text><title>email\r\nvarchar(100) default ''\r\n用户邮箱</title></a>\r\n<text x='792' y='183' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user.phonenumber'><text id='ry.sys_user.phonenumber' x='708' y='201'>phonenumber</text><title>phonenumber\r\nvarchar(20) default ''\r\n手机号码</title></a>\r\n<text x='792' y='198' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user.password'><text id='ry.sys_user.password' x='708' y='216'>password</text><title>password\r\nvarchar(100) default ''\r\n密码</title></a>\r\n<text x='792' y='213' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user.salt'><text id='ry.sys_user.salt' x='708' y='231'>salt</text><title>salt\r\nvarchar(100) default ''\r\n盐加密</title></a>\r\n<text x='792' y='228' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user.user_type'><text id='ry.sys_user.user_type' x='708' y='246'>user_type</text><title>user_type\r\nchar(1) default 'N'\r\n类型:Y默认用户,N非默认用户</title></a>\r\n<text x='792' y='243' text-anchor='end' class='colType'>c</text>  <a xlink:href='#sys_user.status'><text id='ry.sys_user.status' x='708' y='261'>status</text><title>status\r\nint default 0\r\n账号状态:0正常,1禁用</title></a>\r\n<text x='792' y='258' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_user.refuse_des'><text id='ry.sys_user.refuse_des' x='708' y='276'>refuse_des</text><title>refuse_des\r\nvarchar(500) default ''\r\n拒绝登录描述</title></a>\r\n<text x='792' y='273' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user.create_by'><text id='ry.sys_user.create_by' x='708' y='291'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='792' y='288' text-anchor='end' class='colType'>t</text>  <use id='nn' x='692' y='297' xlink:href='#nn'/><a xlink:href='#sys_user.create_time'><text id='ry.sys_user.create_time' x='708' y='306'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='792' y='303' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_user.update_by'><text id='ry.sys_user.update_by' x='708' y='321'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='792' y='318' text-anchor='end' class='colType'>t</text>  <use id='nn' x='692' y='327' xlink:href='#nn'/><a xlink:href='#sys_user.update_time'><text id='ry.sys_user.update_time' x='708' y='336'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='792' y='333' text-anchor='end' class='colType'>d</text>\r\n<!-- == Table 'sys_user_online' == -->\r\n<rect class='entity' x='660' y='413' width='135' height='195' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 660 439 L 660 420 Q 660 413 667 413 L 788 413 Q 795 413 795 420 L 795 439 L660 439 ' style='fill:url(#tbg_c8f5bf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='660' y='413' width='135' height='195' rx='7' ry='7' style='fill:none;stroke:#626e5f'/>\r\n<line class='delim' x1='660' y1='439' x2='795' y2='439' style='stroke:#626e5f'/>\r\n<line class='delim' x1='675' y1='439' x2='675' y2='608' style='stroke:#626e5f'/>\r\n<line class='delim' x1='784' y1='439' x2='784' y2='608' style='stroke:#626e5f'/>\r\n<a xlink:href='#sys_user_online'><text x='679' y='431'>sys_user_online</text><title>Table ry.sys_user_online</title></a>\r\n  <use id='nn' x='662' y='447' xlink:href='#nn'/><a xlink:href='#sys_user_online.sessionId'><use id='pk' x='662' y='446' xlink:href='#pk'/><title>Pk pk_sys_user_online ( sessionId ) </title></a>\r\n<a xlink:href='#sys_user_online.sessionId'><text id='ry.sys_user_online.sessionId' x='678' y='456'>sessionId</text><title>sessionId\r\n* varchar(50) default ''\r\n用户会话id</title></a>\r\n<text x='792' y='453' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user_online.login_name'><text id='ry.sys_user_online.login_name' x='678' y='471'>login_name</text><title>login_name\r\nvarchar(50) default ''\r\n登录账号</title></a>\r\n<text x='792' y='468' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user_online.dept_name'><text id='ry.sys_user_online.dept_name' x='678' y='486'>dept_name</text><title>dept_name\r\nvarchar(50) default ''\r\n部门名称</title></a>\r\n<text x='792' y='483' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user_online.ipaddr'><text id='ry.sys_user_online.ipaddr' x='678' y='501'>ipaddr</text><title>ipaddr\r\nvarchar(50) default ''\r\n登录IP地址</title></a>\r\n<text x='792' y='498' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user_online.browser'><text id='ry.sys_user_online.browser' x='678' y='516'>browser</text><title>browser\r\nvarchar(50) default ''\r\n浏览器类型</title></a>\r\n<text x='792' y='513' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user_online.os'><text id='ry.sys_user_online.os' x='678' y='531'>os</text><title>os\r\nvarchar(50) default ''\r\n操作系统</title></a>\r\n<text x='792' y='528' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_user_online.status'><text id='ry.sys_user_online.status' x='678' y='546'>status</text><title>status\r\nvarchar(10) default ''\r\n在线状态on_line在线off_line离线</title></a>\r\n<text x='792' y='543' text-anchor='end' class='colType'>t</text>  <use id='nn' x='662' y='552' xlink:href='#nn'/><a xlink:href='#sys_user_online.start_timestamp'><text id='ry.sys_user_online.start_timestamp' x='678' y='561'>start_timestamp</text><title>start_timestamp\r\n* timestamp default CURRENT_TIMESTAMP\r\nsession创建时间</title></a>\r\n<text x='792' y='558' text-anchor='end' class='colType'>d</text>  <use id='nn' x='662' y='567' xlink:href='#nn'/><a xlink:href='#sys_user_online.last_access_time'><text id='ry.sys_user_online.last_access_time' x='678' y='576'>last_access_time</text><title>last_access_time\r\n* timestamp default '0000-00-00 00:00:00'\r\nsession最后访问时间</title></a>\r\n<text x='792' y='573' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_user_online.expire_time'><text id='ry.sys_user_online.expire_time' x='678' y='591'>expire_time</text><title>expire_time\r\nint default 0\r\n超时时间，单位为分钟</title></a>\r\n<text x='792' y='588' text-anchor='end' class='colType'>#</text>\r\n<!-- == Table 'sys_user_post' == -->\r\n<rect class='entity' x='855' y='413' width='90' height='75' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 855 439 L 855 420 Q 855 413 862 413 L 938 413 Q 945 413 945 420 L 945 439 L855 439 ' style='fill:url(#tbg_c8f5bf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='855' y='413' width='90' height='75' rx='7' ry='7' style='fill:none;stroke:#626e5f'/>\r\n<line class='delim' x1='855' y1='439' x2='945' y2='439' style='stroke:#626e5f'/>\r\n<line class='delim' x1='870' y1='439' x2='870' y2='488' style='stroke:#626e5f'/>\r\n<line class='delim' x1='934' y1='439' x2='934' y2='488' style='stroke:#626e5f'/>\r\n<a xlink:href='#sys_user_post'><text x='858' y='431'>sys_user_post</text><title>Table ry.sys_user_post</title></a>\r\n  <use id='nn' x='857' y='447' xlink:href='#nn'/><a xlink:href='#sys_user_post.user_id'><use id='pk' x='857' y='446' xlink:href='#pk'/><title>Pk pk_sys_user_post ( user_id, post_id ) </title></a>\r\n<a xlink:href='#sys_user_post.user_id'><text id='ry.sys_user_post.user_id' x='873' y='456'>user_id</text><title>user_id\r\n* varchar(64)\r\n用户ID</title></a>\r\n<text x='942' y='453' text-anchor='end' class='colType'>t</text>  <use id='nn' x='857' y='462' xlink:href='#nn'/><a xlink:href='#sys_user_post.post_id'><use id='pk' x='857' y='461' xlink:href='#pk'/><title>Pk pk_sys_user_post ( user_id, post_id ) </title></a>\r\n<a xlink:href='#sys_user_post.post_id'><text id='ry.sys_user_post.post_id' x='873' y='471'>post_id</text><title>post_id\r\n* varchar(64)\r\n岗位ID</title></a>\r\n<text x='942' y='468' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'sys_user_role' == -->\r\n<rect class='entity' x='855' y='278' width='90' height='75' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 855 304 L 855 285 Q 855 278 862 278 L 938 278 Q 945 278 945 285 L 945 304 L855 304 ' style='fill:url(#tbg_c8f5bf);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='855' y='278' width='90' height='75' rx='7' ry='7' style='fill:none;stroke:#626e5f'/>\r\n<line class='delim' x1='855' y1='304' x2='945' y2='304' style='stroke:#626e5f'/>\r\n<line class='delim' x1='870' y1='304' x2='870' y2='353' style='stroke:#626e5f'/>\r\n<line class='delim' x1='934' y1='304' x2='934' y2='353' style='stroke:#626e5f'/>\r\n<a xlink:href='#sys_user_role'><text x='858' y='296'>sys_user_role</text><title>Table ry.sys_user_role</title></a>\r\n  <use id='nn' x='857' y='312' xlink:href='#nn'/><a xlink:href='#sys_user_role.user_id'><use id='pk' x='857' y='311' xlink:href='#pk'/><title>Pk pk_sys_user_role ( user_id, role_id ) </title></a>\r\n<a xlink:href='#sys_user_role.user_id'><text id='ry.sys_user_role.user_id' x='873' y='321'>user_id</text><title>user_id\r\n* int\r\n用户ID</title></a>\r\n<text x='942' y='318' text-anchor='end' class='colType'>#</text>  <use id='nn' x='857' y='327' xlink:href='#nn'/><a xlink:href='#sys_user_role.role_id'><use id='pk' x='857' y='326' xlink:href='#pk'/><title>Pk pk_sys_user_role ( user_id, role_id ) </title></a>\r\n<a xlink:href='#sys_user_role.role_id'><text id='ry.sys_user_role.role_id' x='873' y='336'>role_id</text><title>role_id\r\n* int\r\n角色ID</title></a>\r\n<text x='942' y='333' text-anchor='end' class='colType'>#</text>\r\n<!-- == Table 'sys_dept' == -->\r\n<rect class='entity' x='645' y='713' width='105' height='225' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 645 739 L 645 720 Q 645 713 652 713 L 743 713 Q 750 713 750 720 L 750 739 L645 739 ' style='fill:url(#tbg_bfbff5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='645' y='713' width='105' height='225' rx='7' ry='7' style='fill:none;stroke:#5f5f6e'/>\r\n<line class='delim' x1='645' y1='739' x2='750' y2='739' style='stroke:#5f5f6e'/>\r\n<line class='delim' x1='660' y1='739' x2='660' y2='938' style='stroke:#5f5f6e'/>\r\n<line class='delim' x1='739' y1='739' x2='739' y2='938' style='stroke:#5f5f6e'/>\r\n<a xlink:href='#sys_dept'><text x='670' y='731'>sys_dept</text><title>Table ry.sys_dept</title></a>\r\n  <use id='nn' x='647' y='747' xlink:href='#nn'/><a xlink:href='#sys_dept.dept_id'><use id='pk' x='647' y='746' xlink:href='#pk'/><title>Pk pk_sys_dept ( dept_id ) </title></a>\r\n<a xlink:href='#sys_dept.dept_id'><text id='ry.sys_dept.dept_id' x='663' y='756'>dept_id</text><title>dept_id\r\n* int\r\n部门id</title></a>\r\n<text x='747' y='753' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dept.parent_id'><text id='ry.sys_dept.parent_id' x='663' y='771'>parent_id</text><title>parent_id\r\nint default 0\r\n父部门id</title></a>\r\n<text x='747' y='768' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dept.dept_name'><text id='ry.sys_dept.dept_name' x='663' y='786'>dept_name</text><title>dept_name\r\nvarchar(30) default ''\r\n部门名称</title></a>\r\n<text x='747' y='783' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dept.order_num'><text id='ry.sys_dept.order_num' x='663' y='801'>order_num</text><title>order_num\r\nint default 0\r\n显示顺序</title></a>\r\n<text x='747' y='798' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dept.leader'><text id='ry.sys_dept.leader' x='663' y='816'>leader</text><title>leader\r\nvarchar(20) default ''\r\n负责人</title></a>\r\n<text x='747' y='813' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dept.phone'><text id='ry.sys_dept.phone' x='663' y='831'>phone</text><title>phone\r\nvarchar(20) default ''\r\n联系电话</title></a>\r\n<text x='747' y='828' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dept.email'><text id='ry.sys_dept.email' x='663' y='846'>email</text><title>email\r\nvarchar(20) default ''\r\n邮箱</title></a>\r\n<text x='747' y='843' text-anchor='end' class='colType'>t</text>  <a xlink:href='#sys_dept.status'><text id='ry.sys_dept.status' x='663' y='861'>status</text><title>status\r\nint default 0\r\n部门状态:0正常,1停用</title></a>\r\n<text x='747' y='858' text-anchor='end' class='colType'>#</text>  <a xlink:href='#sys_dept.create_by'><text id='ry.sys_dept.create_by' x='663' y='876'>create_by</text><title>create_by\r\nvarchar(64) default ''\r\n创建者</title></a>\r\n<text x='747' y='873' text-anchor='end' class='colType'>t</text>  <use id='nn' x='647' y='882' xlink:href='#nn'/><a xlink:href='#sys_dept.create_time'><text id='ry.sys_dept.create_time' x='663' y='891'>create_time</text><title>create_time\r\n* timestamp default CURRENT_TIMESTAMP\r\n创建时间</title></a>\r\n<text x='747' y='888' text-anchor='end' class='colType'>d</text>  <a xlink:href='#sys_dept.update_by'><text id='ry.sys_dept.update_by' x='663' y='906'>update_by</text><title>update_by\r\nvarchar(64) default ''\r\n更新者</title></a>\r\n<text x='747' y='903' text-anchor='end' class='colType'>t</text>  <use id='nn' x='647' y='912' xlink:href='#nn'/><a xlink:href='#sys_dept.update_time'><text id='ry.sys_dept.update_time' x='663' y='921'>update_time</text><title>update_time\r\n* timestamp default '0000-00-00 00:00:00'\r\n更新时间</title></a>\r\n<text x='747' y='918' text-anchor='end' class='colType'>d</text>\r\n<!-- == Table 'qrtz_paused_trigger_grps' == -->\r\n<rect class='entity' x='1260' y='683' width='165' height='75' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1260 709 L 1260 690 Q 1260 683 1267 683 L 1418 683 Q 1425 683 1425 690 L 1425 709 L1260 709 ' style='fill:url(#tbg_bfbff5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1260' y='683' width='165' height='75' rx='7' ry='7' style='fill:none;stroke:#5f5f6e'/>\r\n<line class='delim' x1='1260' y1='709' x2='1425' y2='709' style='stroke:#5f5f6e'/>\r\n<line class='delim' x1='1275' y1='709' x2='1275' y2='758' style='stroke:#5f5f6e'/>\r\n<line class='delim' x1='1414' y1='709' x2='1414' y2='758' style='stroke:#5f5f6e'/>\r\n<a xlink:href='#qrtz_paused_trigger_grps'><text x='1267' y='701'>qrtz_paused_trigger_grps</text><title>Table ry.qrtz_paused_trigger_grps</title></a>\r\n  <use id='nn' x='1262' y='717' xlink:href='#nn'/><a xlink:href='#qrtz_paused_trigger_grps.sched_name'><use id='pk' x='1262' y='716' xlink:href='#pk'/><title>Pk pk_qrtz_paused_trigger_grps ( sched_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_paused_trigger_grps.sched_name'><text id='ry.qrtz_paused_trigger_grps.sched_name' x='1278' y='726'>sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<text x='1422' y='723' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1262' y='732' xlink:href='#nn'/><a xlink:href='#qrtz_paused_trigger_grps.trigger_group'><use id='pk' x='1262' y='731' xlink:href='#pk'/><title>Pk pk_qrtz_paused_trigger_grps ( sched_name, trigger_group ) </title></a>\r\n<a xlink:href='#qrtz_paused_trigger_grps.trigger_group'><text id='ry.qrtz_paused_trigger_grps.trigger_group' x='1278' y='741'>trigger_group</text><title>trigger_group\r\n* varchar(200)</title></a>\r\n<text x='1422' y='738' text-anchor='end' class='colType'>t</text>\r\n<!-- == Table 'qrtz_fired_triggers' == -->\r\n<rect class='entity' x='1035' y='668' width='135' height='240' rx='7' ry='7' style='stroke:none'/>\r\n<path d='M 1035 694 L 1035 675 Q 1035 668 1042 668 L 1163 668 Q 1170 668 1170 675 L 1170 694 L1035 694 ' style='fill:url(#tbg_bfbff5);stroke:1;stroke-opacity:0.1;' />\r\n<rect class='entity' x='1035' y='668' width='135' height='240' rx='7' ry='7' style='fill:none;stroke:#5f5f6e'/>\r\n<line class='delim' x1='1035' y1='694' x2='1170' y2='694' style='stroke:#5f5f6e'/>\r\n<line class='delim' x1='1050' y1='694' x2='1050' y2='908' style='stroke:#5f5f6e'/>\r\n<line class='delim' x1='1159' y1='694' x2='1159' y2='908' style='stroke:#5f5f6e'/>\r\n<a xlink:href='#qrtz_fired_triggers'><text x='1042' y='686'>qrtz_fired_triggers</text><title>Table ry.qrtz_fired_triggers</title></a>\r\n  <use id='nn' x='1037' y='702' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.sched_name'><use id='pk' x='1037' y='701' xlink:href='#pk'/><title>Pk pk_qrtz_fired_triggers ( sched_name, entry_id ) </title></a>\r\n<a xlink:href='#qrtz_fired_triggers.sched_name'><text id='ry.qrtz_fired_triggers.sched_name' x='1053' y='711'>sched_name</text><title>sched_name\r\n* varchar(120)</title></a>\r\n<text x='1167' y='708' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1037' y='717' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.entry_id'><use id='pk' x='1037' y='716' xlink:href='#pk'/><title>Pk pk_qrtz_fired_triggers ( sched_name, entry_id ) </title></a>\r\n<a xlink:href='#qrtz_fired_triggers.entry_id'><text id='ry.qrtz_fired_triggers.entry_id' x='1053' y='726'>entry_id</text><title>entry_id\r\n* varchar(95)</title></a>\r\n<text x='1167' y='723' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1037' y='732' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.trigger_name'><text id='ry.qrtz_fired_triggers.trigger_name' x='1053' y='741'>trigger_name</text><title>trigger_name\r\n* varchar(200)</title></a>\r\n<text x='1167' y='738' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1037' y='747' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.trigger_group'><text id='ry.qrtz_fired_triggers.trigger_group' x='1053' y='756'>trigger_group</text><title>trigger_group\r\n* varchar(200)</title></a>\r\n<text x='1167' y='753' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1037' y='762' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.instance_name'><text id='ry.qrtz_fired_triggers.instance_name' x='1053' y='771'>instance_name</text><title>instance_name\r\n* varchar(200)</title></a>\r\n<text x='1167' y='768' text-anchor='end' class='colType'>t</text>  <use id='nn' x='1037' y='777' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.fired_time'><text id='ry.qrtz_fired_triggers.fired_time' x='1053' y='786'>fired_time</text><title>fired_time\r\n* bigint</title></a>\r\n<text x='1167' y='783' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1037' y='792' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.sched_time'><text id='ry.qrtz_fired_triggers.sched_time' x='1053' y='801'>sched_time</text><title>sched_time\r\n* bigint</title></a>\r\n<text x='1167' y='798' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1037' y='807' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.priority'><text id='ry.qrtz_fired_triggers.priority' x='1053' y='816'>priority</text><title>priority\r\n* int</title></a>\r\n<text x='1167' y='813' text-anchor='end' class='colType'>#</text>  <use id='nn' x='1037' y='822' xlink:href='#nn'/><a xlink:href='#qrtz_fired_triggers.state'><text id='ry.qrtz_fired_triggers.state' x='1053' y='831'>state</text><title>state\r\n* varchar(16)</title></a>\r\n<text x='1167' y='828' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_fired_triggers.job_name'><text id='ry.qrtz_fired_triggers.job_name' x='1053' y='846'>job_name</text><title>job_name\r\nvarchar(200)</title></a>\r\n<text x='1167' y='843' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_fired_triggers.job_group'><text id='ry.qrtz_fired_triggers.job_group' x='1053' y='861'>job_group</text><title>job_group\r\nvarchar(200)</title></a>\r\n<text x='1167' y='858' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_fired_triggers.is_nonconcurrent'><text id='ry.qrtz_fired_triggers.is_nonconcurrent' x='1053' y='876'>is_nonconcurrent</text><title>is_nonconcurrent\r\nvarchar(1)</title></a>\r\n<text x='1167' y='873' text-anchor='end' class='colType'>t</text>  <a xlink:href='#qrtz_fired_triggers.requests_recovery'><text id='ry.qrtz_fired_triggers.requests_recovery' x='1053' y='891'>requests_recovery</text><title>requests_recovery\r\nvarchar(1)</title></a>\r\n<text x='1167' y='888' text-anchor='end' class='colType'>t</text>\r\n</g></svg></div>\r\n\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_blob_triggers' onclick='window.scrollTo(60, 540);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_blob_triggers</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_blob_triggers.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_blob_triggers.trigger_name'>trigger&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_blob_triggers.trigger_group'>trigger&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_blob_triggers.blob_data'>blob&#95;data</a></td>\r\n\t\t<td> blob   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;blob&#95;triggers</td>\r\n\t\t<td> ON sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Foreign Keys</th></tr>\r\n\t<tr>\r\n\t\t<td><svg width='14' height='14'><use xlink:href='#fk'/></svg></td><td>qrtz_blob_triggers_ibfk_1</td>\r\n\t\t<td > ( sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group ) ref <a href='#qrtz&#95;triggers'>qrtz&#95;triggers</a> (sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group) </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_calendars' onclick='window.scrollTo(60, 45);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_calendars</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_calendars.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_calendars.calendar_name'>calendar&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_calendars.calendar'>calendar</a></td>\r\n\t\t<td> blob   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;calendars</td>\r\n\t\t<td> ON sched&#95;name&#44; calendar&#95;name</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_cron_triggers' onclick='window.scrollTo(235, 540);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_cron_triggers</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_cron_triggers.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_cron_triggers.trigger_name'>trigger&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_cron_triggers.trigger_group'>trigger&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_cron_triggers.cron_expression'>cron&#95;expression</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_cron_triggers.time_zone_id'>time&#95;zone&#95;id</a></td>\r\n\t\t<td> varchar&#40; 80 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;cron&#95;triggers</td>\r\n\t\t<td> ON sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Foreign Keys</th></tr>\r\n\t<tr>\r\n\t\t<td><svg width='14' height='14'><use xlink:href='#fk'/></svg></td><td>qrtz_cron_triggers_ibfk_1</td>\r\n\t\t<td > ( sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group ) ref <a href='#qrtz&#95;triggers'>qrtz&#95;triggers</a> (sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group) </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_fired_triggers' onclick='window.scrollTo(835, 675);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_fired_triggers</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_fired_triggers.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_fired_triggers.entry_id'>entry&#95;id</a></td>\r\n\t\t<td> varchar&#40; 95 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_fired_triggers.trigger_name'>trigger&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_fired_triggers.trigger_group'>trigger&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_fired_triggers.instance_name'>instance&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_fired_triggers.fired_time'>fired&#95;time</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_fired_triggers.sched_time'>sched&#95;time</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_fired_triggers.priority'>priority</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_fired_triggers.state'>state</a></td>\r\n\t\t<td> varchar&#40; 16 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_fired_triggers.job_name'>job&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_fired_triggers.job_group'>job&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_fired_triggers.is_nonconcurrent'>is&#95;nonconcurrent</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_fired_triggers.requests_recovery'>requests&#95;recovery</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;fired&#95;triggers</td>\r\n\t\t<td> ON sched&#95;name&#44; entry&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_job_details' onclick='window.scrollTo(235, 195);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_job_details</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#ref'/></svg></td>\r\n\t\t<td><a name='qrtz_job_details.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#ref'/></svg></td>\r\n\t\t<td><a name='qrtz_job_details.job_name'>job&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#ref'/></svg></td>\r\n\t\t<td><a name='qrtz_job_details.job_group'>job&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_job_details.description'>description</a></td>\r\n\t\t<td> varchar&#40; 250 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_job_details.job_class_name'>job&#95;class&#95;name</a></td>\r\n\t\t<td> varchar&#40; 250 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_job_details.is_durable'>is&#95;durable</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_job_details.is_nonconcurrent'>is&#95;nonconcurrent</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_job_details.is_update_data'>is&#95;update&#95;data</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_job_details.requests_recovery'>requests&#95;recovery</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_job_details.job_data'>job&#95;data</a></td>\r\n\t\t<td> blob   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;job&#95;details</td>\r\n\t\t<td> ON sched&#95;name&#44; job&#95;name&#44; job&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_locks' onclick='window.scrollTo(60, 60);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_locks</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_locks.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_locks.lock_name'>lock&#95;name</a></td>\r\n\t\t<td> varchar&#40; 40 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;locks</td>\r\n\t\t<td> ON sched&#95;name&#44; lock&#95;name</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_paused_trigger_grps' onclick='window.scrollTo(1060, 690);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_paused_trigger_grps</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_paused_trigger_grps.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_paused_trigger_grps.trigger_group'>trigger&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;paused&#95;trigger&#95;grps</td>\r\n\t\t<td> ON sched&#95;name&#44; trigger&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_scheduler_state' onclick='window.scrollTo(60, 735);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_scheduler_state</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_scheduler_state.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='qrtz_scheduler_state.instance_name'>instance&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_scheduler_state.last_checkin_time'>last&#95;checkin&#95;time</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_scheduler_state.checkin_interval'>checkin&#95;interval</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;scheduler&#95;state</td>\r\n\t\t<td> ON sched&#95;name&#44; instance&#95;name</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_simple_triggers' onclick='window.scrollTo(60, 540);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_simple_triggers</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_simple_triggers.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_simple_triggers.trigger_name'>trigger&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_simple_triggers.trigger_group'>trigger&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_simple_triggers.repeat_count'>repeat&#95;count</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_simple_triggers.repeat_interval'>repeat&#95;interval</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_simple_triggers.times_triggered'>times&#95;triggered</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;simple&#95;triggers</td>\r\n\t\t<td> ON sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Foreign Keys</th></tr>\r\n\t<tr>\r\n\t\t<td><svg width='14' height='14'><use xlink:href='#fk'/></svg></td><td>qrtz_simple_triggers_ibfk_1</td>\r\n\t\t<td > ( sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group ) ref <a href='#qrtz&#95;triggers'>qrtz&#95;triggers</a> (sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group) </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_simprop_triggers' onclick='window.scrollTo(60, 225);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_simprop_triggers</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_simprop_triggers.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_simprop_triggers.trigger_name'>trigger&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_simprop_triggers.trigger_group'>trigger&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.str_prop_1'>str&#95;prop&#95;1</a></td>\r\n\t\t<td> varchar&#40; 512 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.str_prop_2'>str&#95;prop&#95;2</a></td>\r\n\t\t<td> varchar&#40; 512 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.str_prop_3'>str&#95;prop&#95;3</a></td>\r\n\t\t<td> varchar&#40; 512 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.int_prop_1'>int&#95;prop&#95;1</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.int_prop_2'>int&#95;prop&#95;2</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.long_prop_1'>long&#95;prop&#95;1</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.long_prop_2'>long&#95;prop&#95;2</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.dec_prop_1'>dec&#95;prop&#95;1</a></td>\r\n\t\t<td> decimal&#40; 13&#44; 4 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.dec_prop_2'>dec&#95;prop&#95;2</a></td>\r\n\t\t<td> decimal&#40; 13&#44; 4 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.bool_prop_1'>bool&#95;prop&#95;1</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_simprop_triggers.bool_prop_2'>bool&#95;prop&#95;2</a></td>\r\n\t\t<td> varchar&#40; 1 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;simprop&#95;triggers</td>\r\n\t\t<td> ON sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Foreign Keys</th></tr>\r\n\t<tr>\r\n\t\t<td><svg width='14' height='14'><use xlink:href='#fk'/></svg></td><td>qrtz_simprop_triggers_ibfk_1</td>\r\n\t\t<td > ( sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group ) ref <a href='#qrtz&#95;triggers'>qrtz&#95;triggers</a> (sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group) </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='qrtz_triggers' onclick='window.scrollTo(60, 195);return false;' style='cursor:pointer;'><h4 class='card-title'>Table qrtz_triggers</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_triggers.sched_name'>sched&#95;name</a></td>\r\n\t\t<td> varchar&#40; 120 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#ref'/></svg></td>\r\n\t\t<td><a name='qrtz_triggers.trigger_name'>trigger&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg><svg width='14' height='14'><use xlink:href='#ref'/></svg></td>\r\n\t\t<td><a name='qrtz_triggers.trigger_group'>trigger&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#idx'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_triggers.job_name'>job&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#idx'/></svg><svg width='14' height='14'><use xlink:href='#fk'/></svg></td>\r\n\t\t<td><a name='qrtz_triggers.job_group'>job&#95;group</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.description'>description</a></td>\r\n\t\t<td> varchar&#40; 250 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.next_fire_time'>next&#95;fire&#95;time</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.prev_fire_time'>prev&#95;fire&#95;time</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.priority'>priority</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_triggers.trigger_state'>trigger&#95;state</a></td>\r\n\t\t<td> varchar&#40; 16 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_triggers.trigger_type'>trigger&#95;type</a></td>\r\n\t\t<td> varchar&#40; 8 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='qrtz_triggers.start_time'>start&#95;time</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.end_time'>end&#95;time</a></td>\r\n\t\t<td> bigint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.calendar_name'>calendar&#95;name</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.misfire_instr'>misfire&#95;instr</a></td>\r\n\t\t<td> smallint   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='qrtz_triggers.job_data'>job&#95;data</a></td>\r\n\t\t<td> blob   </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;qrtz&#95;triggers</td>\r\n\t\t<td> ON sched&#95;name&#44; trigger&#95;name&#44; trigger&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#idx'/></svg></td><td>sched&#95;name</td>\r\n\t\t<td> ON sched&#95;name&#44; job&#95;name&#44; job&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Foreign Keys</th></tr>\r\n\t<tr>\r\n\t\t<td><svg width='14' height='14'><use xlink:href='#fk'/></svg></td><td>qrtz_triggers_ibfk_1</td>\r\n\t\t<td > ( sched&#95;name&#44; job&#95;name&#44; job&#95;group ) ref <a href='#qrtz&#95;job&#95;details'>qrtz&#95;job&#95;details</a> (sched&#95;name&#44; job&#95;name&#44; job&#95;group) </td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_dept' onclick='window.scrollTo(445, 720);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_dept</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_dept.dept_id'>dept&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 部门id </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.parent_id'>parent&#95;id</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 父部门id </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.dept_name'>dept&#95;name</a></td>\r\n\t\t<td> varchar&#40; 30 &#41;   DEFAULT '' </td>\r\n\t\t<td> 部门名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.order_num'>order&#95;num</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 显示顺序 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.leader'>leader</a></td>\r\n\t\t<td> varchar&#40; 20 &#41;   DEFAULT '' </td>\r\n\t\t<td> 负责人 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.phone'>phone</a></td>\r\n\t\t<td> varchar&#40; 20 &#41;   DEFAULT '' </td>\r\n\t\t<td> 联系电话 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.email'>email</a></td>\r\n\t\t<td> varchar&#40; 20 &#41;   DEFAULT '' </td>\r\n\t\t<td> 邮箱 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 部门状态&#58;0正常&#44;1停用 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_dept.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dept.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_dept.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;dept</td>\r\n\t\t<td> ON dept&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_dict_data' onclick='window.scrollTo(970, 45);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_dict_data</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_dict_data.dict_code'>dict&#95;code</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 字典编码 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.dict_sort'>dict&#95;sort</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 字典排序 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.dict_label'>dict&#95;label</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 字典标签 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.dict_value'>dict&#95;value</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 字典键值 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.dict_type'>dict&#95;type</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 字典类型 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 状态（0正常 1禁用） </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_dict_data.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_dict_data.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_data.remark'>remark</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 备注 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;dict&#95;data</td>\r\n\t\t<td> ON dict&#95;code</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_dict_type' onclick='window.scrollTo(805, 45);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_dict_type</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_dict_type.dict_id'>dict&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 字典主键 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_type.dict_name'>dict&#95;name</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 字典名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td><svg width='14' height='14'><use xlink:href='#unq'/></svg></td>\r\n\t\t<td><a name='sys_dict_type.dict_type'>dict&#95;type</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 字典类型 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_type.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 状态（0正常 1禁用） </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_type.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_dict_type.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_type.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_dict_type.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_dict_type.remark'>remark</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 备注 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;dict&#95;type</td>\r\n\t\t<td> ON dict&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#unq'/></svg></td><td>dict&#95;type</td>\r\n\t\t<td> ON dict&#95;type</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_job' onclick='window.scrollTo(1345, 45);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_job</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_job.job_id'>job&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 任务ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_job.job_name'>job&#95;name</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 任务名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_job.job_group'>job&#95;group</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 任务组名 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job.method_name'>method&#95;name</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 任务方法 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job.params'>params</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   DEFAULT '' </td>\r\n\t\t<td> 方法参数 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job.cron_expression'>cron&#95;expression</a></td>\r\n\t\t<td> varchar&#40; 255 &#41;   DEFAULT '' </td>\r\n\t\t<td> cron执行表达式 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 状态（0正常 1暂停） </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_job.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_job.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job.remark'>remark</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 备注信息 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;job</td>\r\n\t\t<td> ON job&#95;id&#44; job&#95;name&#44; job&#95;group</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_job_log' onclick='window.scrollTo(1165, 45);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_job_log</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_job_log.job_log_id'>job&#95;log&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 任务日志ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_job_log.job_name'>job&#95;name</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   </td>\r\n\t\t<td> 任务名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_job_log.job_group'>job&#95;group</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   </td>\r\n\t\t<td> 任务组名 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job_log.method_name'>method&#95;name</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   </td>\r\n\t\t<td> 任务方法 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job_log.params'>params</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   DEFAULT '' </td>\r\n\t\t<td> 方法参数 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job_log.job_message'>job&#95;message</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   </td>\r\n\t\t<td> 日志信息 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job_log.is_exception'>is&#95;exception</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 是否异常 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_job_log.exception_info'>exception&#95;info</a></td>\r\n\t\t<td> text   </td>\r\n\t\t<td> 异常信息 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_job_log.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;job&#95;log</td>\r\n\t\t<td> ON job&#95;log&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_logininfor' onclick='window.scrollTo(1540, 330);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_logininfor</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_logininfor.info_id'>info&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 访问ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_logininfor.login_name'>login&#95;name</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 登录账号 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_logininfor.ipaddr'>ipaddr</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 登录IP地址 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_logininfor.browser'>browser</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 浏览器类型 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_logininfor.os'>os</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 操作系统 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_logininfor.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 登录状态 0成功 1失败 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_logininfor.msg'>msg</a></td>\r\n\t\t<td> varchar&#40; 255 &#41;   DEFAULT '' </td>\r\n\t\t<td> 提示消息 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_logininfor.login_time'>login&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 访问时间 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;logininfor</td>\r\n\t\t<td> ON info&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_menu' onclick='window.scrollTo(1180, 330);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_menu</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_menu.menu_id'>menu&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 菜单ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_menu.menu_name'>menu&#95;name</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   </td>\r\n\t\t<td> 菜单名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.parent_id'>parent&#95;id</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 父菜单ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.order_num'>order&#95;num</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 显示顺序 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.url'>url</a></td>\r\n\t\t<td> varchar&#40; 200 &#41;   DEFAULT '' </td>\r\n\t\t<td> 请求地址 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.menu_type'>menu&#95;type</a></td>\r\n\t\t<td> char&#40; 1 &#41;   DEFAULT '' </td>\r\n\t\t<td> 类型&#58;M目录&#44;C菜单&#44;F按钮 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.visible'>visible</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 菜单状态&#58;0显示&#44;1隐藏 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.perms'>perms</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 权限标识 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.icon'>icon</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 菜单图标 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_menu.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_menu.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_menu.remark'>remark</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 备注 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;menu</td>\r\n\t\t<td> ON menu&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_oper_log' onclick='window.scrollTo(805, 285);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_oper_log</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_oper_log.oper_id'>oper&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 日志主键 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.title'>title</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 模块标题 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.action'>action</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 功能请求 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.method'>method</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 方法名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.channel'>channel</a></td>\r\n\t\t<td> varchar&#40; 20 &#41;   DEFAULT '' </td>\r\n\t\t<td> 来源渠道 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.login_name'>login&#95;name</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 登录账号 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.dept_name'>dept&#95;name</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 部门名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.oper_url'>oper&#95;url</a></td>\r\n\t\t<td> varchar&#40; 255 &#41;   DEFAULT '' </td>\r\n\t\t<td> 请求URL </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.oper_ip'>oper&#95;ip</a></td>\r\n\t\t<td> varchar&#40; 30 &#41;   DEFAULT '' </td>\r\n\t\t<td> 主机地址 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.oper_param'>oper&#95;param</a></td>\r\n\t\t<td> varchar&#40; 255 &#41;   DEFAULT '' </td>\r\n\t\t<td> 请求参数 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 操作状态 0正常 1异常 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_oper_log.error_msg'>error&#95;msg</a></td>\r\n\t\t<td> varchar&#40; 2000 &#41;   DEFAULT '' </td>\r\n\t\t<td> 错误消息 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_oper_log.oper_time'>oper&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 操作时间 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;oper&#95;log</td>\r\n\t\t<td> ON oper&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_post' onclick='window.scrollTo(1540, 45);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_post</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_post.post_id'>post&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 岗位ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_post.post_code'>post&#95;code</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   </td>\r\n\t\t<td> 岗位编码 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_post.post_name'>post&#95;name</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   </td>\r\n\t\t<td> 岗位名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_post.post_sort'>post&#95;sort</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 显示顺序 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_post.status'>status</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 状态（0正常 1停用） </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_post.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_post.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_post.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_post.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_post.remark'>remark</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 备注 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;post</td>\r\n\t\t<td> ON post&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_role' onclick='window.scrollTo(1345, 465);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_role</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_role.role_id'>role&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 角色ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_role.role_name'>role&#95;name</a></td>\r\n\t\t<td> varchar&#40; 30 &#41;   </td>\r\n\t\t<td> 角色名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_role.role_key'>role&#95;key</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   </td>\r\n\t\t<td> 角色权限字符串 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_role.role_sort'>role&#95;sort</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 显示顺序 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_role.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 角色状态&#58;0正常&#44;1禁用 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_role.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_role.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_role.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_role.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_role.remark'>remark</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 备注 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;role</td>\r\n\t\t<td> ON role&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_role_menu' onclick='window.scrollTo(1345, 330);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_role_menu</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_role_menu.role_id'>role&#95;id</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 角色ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_role_menu.menu_id'>menu&#95;id</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 菜单ID </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;role&#95;menu</td>\r\n\t\t<td> ON role&#95;id&#44; menu&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_user' onclick='window.scrollTo(490, 90);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_user</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_user.user_id'>user&#95;id</a></td>\r\n\t\t<td> int  AUTOINCREMENT  </td>\r\n\t\t<td> 用户ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.dept_id'>dept&#95;id</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 部门ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.login_name'>login&#95;name</a></td>\r\n\t\t<td> varchar&#40; 30 &#41;   DEFAULT '' </td>\r\n\t\t<td> 登录账号 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.user_name'>user&#95;name</a></td>\r\n\t\t<td> varchar&#40; 30 &#41;   DEFAULT '' </td>\r\n\t\t<td> 用户昵称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.email'>email</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 用户邮箱 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.phonenumber'>phonenumber</a></td>\r\n\t\t<td> varchar&#40; 20 &#41;   DEFAULT '' </td>\r\n\t\t<td> 手机号码 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.password'>password</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 密码 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.salt'>salt</a></td>\r\n\t\t<td> varchar&#40; 100 &#41;   DEFAULT '' </td>\r\n\t\t<td> 盐加密 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.user_type'>user&#95;type</a></td>\r\n\t\t<td> char&#40; 1 &#41;   DEFAULT 'N' </td>\r\n\t\t<td> 类型&#58;Y默认用户&#44;N非默认用户 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.status'>status</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 账号状态&#58;0正常&#44;1禁用 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.refuse_des'>refuse&#95;des</a></td>\r\n\t\t<td> varchar&#40; 500 &#41;   DEFAULT '' </td>\r\n\t\t<td> 拒绝登录描述 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.create_by'>create&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 创建者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_user.create_time'>create&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> 创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user.update_by'>update&#95;by</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   DEFAULT '' </td>\r\n\t\t<td> 更新者 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_user.update_time'>update&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> 更新时间 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;user</td>\r\n\t\t<td> ON user&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_user_online' onclick='window.scrollTo(460, 420);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_user_online</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_user_online.sessionId'>sessionId</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 用户会话id </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user_online.login_name'>login&#95;name</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 登录账号 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user_online.dept_name'>dept&#95;name</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 部门名称 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user_online.ipaddr'>ipaddr</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 登录IP地址 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user_online.browser'>browser</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 浏览器类型 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user_online.os'>os</a></td>\r\n\t\t<td> varchar&#40; 50 &#41;   DEFAULT '' </td>\r\n\t\t<td> 操作系统 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user_online.status'>status</a></td>\r\n\t\t<td> varchar&#40; 10 &#41;   DEFAULT '' </td>\r\n\t\t<td> 在线状态on&#95;line在线off&#95;line离线 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_user_online.start_timestamp'>start&#95;timestsamp</a></td>\r\n\t\t<td> timestamp   DEFAULT CURRENT_TIMESTAMP </td>\r\n\t\t<td> session创建时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*</td>\r\n\t\t<td><a name='sys_user_online.last_access_time'>last&#95;access&#95;time</a></td>\r\n\t\t<td> timestamp   DEFAULT '0000-00-00 00:00:00' </td>\r\n\t\t<td> session最后访问时间 </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>&nbsp;</td>\r\n\t\t<td><a name='sys_user_online.expire_time'>expire&#95;time</a></td>\r\n\t\t<td> int   DEFAULT 0 </td>\r\n\t\t<td> 超时时间，单位为分钟 </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;user&#95;online</td>\r\n\t\t<td> ON sessionId</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_user_post' onclick='window.scrollTo(655, 420);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_user_post</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_user_post.user_id'>user&#95;id</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   </td>\r\n\t\t<td> 用户ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_user_post.post_id'>post&#95;id</a></td>\r\n\t\t<td> varchar&#40; 64 &#41;   </td>\r\n\t\t<td> 岗位ID </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;user&#95;post</td>\r\n\t\t<td> ON user&#95;id&#44; post&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<br/><br/>\r\n<div class='card'><div class='card-block'><a name='sys_user_role' onclick='window.scrollTo(655, 285);return false;' style='cursor:pointer;'><h4 class='card-title'>Table sys_user_role</h4></a>\r\n<table class='table-sm table-bordered'>\r\n<thead>\r\n<tr><th>Indexes</th><th>Field Name</th><th>Data Type</th><th>Description</th></tr></thead>\r\n<tbody>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_user_role.user_id'>user&#95;id</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 用户ID </td>\r\n\t</tr>\r\n\t<tr>\r\n\t\t<td>*<svg width='14' height='14'><use xlink:href='#pk'/></svg></td>\r\n\t\t<td><a name='sys_user_role.role_id'>role&#95;id</a></td>\r\n\t\t<td> int   </td>\r\n\t\t<td> 角色ID </td>\r\n\t</tr>\r\n<tr><th colspan='4'>Indexes</th></tr>\r\n\t<tr>\t\t<td><svg width='14' height='14'><use xlink:href='#pk'/></svg></td><td>pk&#95;sys&#95;user&#95;role</td>\r\n\t\t<td> ON user&#95;id&#44; role&#95;id</td>\r\n\t\t<td>  </td>\r\n\t</tr>\r\n</tbody>\r\n</table></div></div>\r\n\r\n<p align='right'><a href='https://www.dbschema.com' style='color:#aaa'>Powered by DbSchema</a></p></body></html>"
  },
  {
    "path": "sql/ruoyi.pdm",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<?PowerDesigner AppLocale=\"UTF16\" ID=\"{21C20947-ED50-4632-B638-DC1A02BD948A}\" Label=\"\" LastModificationDate=\"1538297772\" Name=\"ruoyi\" Objects=\"216\" Symbols=\"20\" Target=\"MySQL 5.0\" Type=\"{CDE44E21-9669-11D1-9914-006097355D9B}\" signature=\"PDM_DATA_MODEL_XML\" version=\"15.1.0.2850\"?>\r\n<!-- do not edit this file -->\r\n\r\n<Model xmlns:a=\"attribute\" xmlns:c=\"collection\" xmlns:o=\"object\">\r\n\r\n<o:RootObject Id=\"o1\">\r\n<c:Children>\r\n<o:Model Id=\"o2\">\r\n<a:ObjectID>21C20947-ED50-4632-B638-DC1A02BD948A</a:ObjectID>\r\n<a:Name>ruoyi</a:Name>\r\n<a:Code>ruoyi</a:Code>\r\n<a:CreationDate>1524449337</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297587</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:PackageOptionsText>[FolderOptions]\r\n\r\n[FolderOptions\\Physical Objects]\r\nGenerationCheckModel=Yes\r\nGenerationPath=\r\nGenerationOptions=\r\nGenerationTasks=\r\nGenerationTargets=\r\nGenerationSelections=\r\nRevPkey=Yes\r\nRevFkey=Yes\r\nRevAkey=Yes\r\nRevCheck=Yes\r\nRevIndx=Yes\r\nRevOpts=Yes\r\nRevViewAsTabl=No\r\nRevViewOpts=Yes\r\nRevSystAsTabl=Yes\r\nRevTablPerm=No\r\nRevViewPerm=No\r\nRevProcPerm=No\r\nRevDbpkPerm=No\r\nRevSqncPerm=No\r\nRevAdtPerm=No\r\nRevUserPriv=No\r\nRevUserOpts=No\r\nRevGrpePriv=No\r\nRevRolePriv=No\r\nRevDtbsOpts=Yes\r\nRevDtbsPerm=No\r\nRevViewIndx=Yes\r\nRevJidxOpts=Yes\r\nRevStats=No\r\nRevTspcPerm=No\r\nRevCaseSensitive=No\r\nGenTrgrStdMsg=Yes\r\nGenTrgrMsgTab=\r\nGenTrgrMsgNo=\r\nGenTrgrMsgTxt=\r\nTrgrPreserve=No\r\nTrgrIns=Yes\r\nTrgrUpd=Yes\r\nTrgrDel=Yes\r\nTrgrC2Ins=Yes\r\nTrgrC2Upd=Yes\r\nTrgrC3=Yes\r\nTrgrC4=Yes\r\nTrgrC5=Yes\r\nTrgrC6=Yes\r\nTrgrC7=Yes\r\nTrgrC8=Yes\r\nTrgrC9=Yes\r\nTrgrC10=Yes\r\nTrgrC11=Yes\r\nTrgrC1=Yes\r\nTrgrC12Ins=Yes\r\nTrgrC12Upd=Yes\r\nTrgrC13=Yes\r\nUpdateTableStatistics=Yes\r\nUpdateColumnStatistics=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation]\r\nGenScriptName=orders.sql\r\nGenScriptName0=orders.sql\r\nGenScriptName1=studentsystem.sql\r\nGenScriptName2=NetCTOSS.sql\r\nGenScriptName3=product.sql\r\nGenScriptName4=voteSystem.sql\r\nGenScriptName5=.sql\r\nGenScriptName6=enterpriseManagement.sql\r\nGenScriptName7=crebas.sql\r\nGenScriptName8=\r\nGenScriptName9=\r\nGenPathName=C:\\Users\\Administrator\\Desktop\\\r\nGenSingleFile=Yes\r\nGenODBC=No\r\nGenCheckModel=Yes\r\nGenScriptPrev=Yes\r\nGenArchiveModel=No\r\nGenUseSync=No\r\nGenSyncChoice=0\r\nGenSyncArch=\r\nGenSyncRmg=0\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Format]\r\nGenScriptTitle=Yes\r\nGenScriptNamLabl=No\r\nGenScriptQDtbs=No\r\nGenScriptQOwnr=Yes\r\nGenScriptCase=0\r\nGenScriptEncoding=ANSI\r\nGenScriptNAcct=No\r\nIdentifierDelimiter=&quot;\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Database]\r\nCreate=Yes\r\nOpen=Yes\r\nClose=Yes\r\nDrop=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Database\\Create]\r\nPhysical Options=Yes\r\nHeader=Yes\r\nFooter=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Tablespace]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Tablespace\\Create]\r\nHeader=Yes\r\nFooter=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Storage]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\User]\r\nCreate=Yes\r\nGrant=Yes\r\nDrop=Yes\r\nComment=Yes\r\nPrivilege=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\User\\Create]\r\nPhysical Options=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Group]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\nPrivilege=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Role]\r\nCreate=Yes\r\nDrop=Yes\r\nPrivilege=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\UserDefinedDataType]\r\nCreate=Yes\r\nComment=Yes\r\nDrop=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\UserDefinedDataType\\Create]\r\nDefault value=Yes\r\nCheck=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\AbstractDataType]\r\nCreate=Yes\r\nHeader=Yes\r\nFooter=Yes\r\nDrop=Yes\r\nComment=Yes\r\nInstall JAVA class=Yes\r\nRemove JAVA class=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Rule]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Default]\r\nCreate=Yes\r\nComment=Yes\r\nDrop=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Sequence]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column]\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Table]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Table\\Create]\r\nCheck=Yes\r\nPhysical Options=Yes\r\nHeader=Yes\r\nFooter=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Table\\Create\\Check]\r\nConstraint declaration=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Column]\r\nUser datatype=No\r\nDefault value=Yes\r\nCheck=Yes\r\nPhysical Options=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Column\\Check]\r\nConstraint declaration=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Key]\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Key\\Primary key]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Key\\Primary key\\Create]\r\nConstraint declaration=No\r\nPhysical Options=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Key\\Alternate key]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Key\\Alternate key\\Create]\r\nConstraint declaration=No\r\nPhysical Options=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Foreign key]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Foreign key\\Create]\r\nConstraint declaration=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Index]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Index\\Create]\r\nConstraint declaration=Yes\r\nPhysical Options=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Index\\Filter]\r\nPrimary key=No\r\nForeign key=No\r\nAlternate key=No\r\nCluster=Yes\r\nOther=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Trigger]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Table&amp;&amp;Column\\Trigger\\Filter]\r\nFor insert=Yes\r\nFor update=Yes\r\nFor delete=Yes\r\nFor other=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View\\Create]\r\nForce Column list=No\r\nPhysical Options=Yes\r\nHeader=Yes\r\nFooter=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View\\ViewColumn]\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View\\ViewIndex]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View\\ViewIndex\\Create]\r\nPhysical Options=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View\\ViewIndex\\Filter]\r\nCluster=Yes\r\nOther=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View\\Trigger]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\View\\Trigger\\Filter]\r\nFor insert=Yes\r\nFor update=Yes\r\nFor delete=Yes\r\nFor other=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\DBMSTrigger]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Synonym]\r\nCreate=Yes\r\nDrop=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Synonym\\Filter]\r\nTable=Yes\r\nView=Yes\r\nProc=Yes\r\nSynonym=Yes\r\nDatabase Package=Yes\r\nSequence=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\JoinIndex]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\JoinIndex\\Create]\r\nPhysical Options=Yes\r\nHeader=Yes\r\nFooter=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Procedure]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Procedure\\Create]\r\nHeader=Yes\r\nFooter=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\DatabasePackage]\r\nCreate=Yes\r\nDrop=Yes\r\nPermission=No\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\WebService]\r\nCreate=Yes\r\nDrop=Yes\r\nComment=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Dimension]\r\nCreate=Yes\r\nDrop=Yes\r\n\r\n[FolderOptions\\Physical Objects\\Database Generation\\Synchronization]\r\nGenBackupTabl=1\r\nGenKeepBackTabl=1\r\nGenTmpTablDrop=No\r\nGenKeepTablOpts=No\r\n\r\n[FolderOptions\\Physical Objects\\Test Data]\r\nGenDataPathName=\r\nGenDataSinglefile=Yes\r\nGenDataScriptName=testdata\r\nGenDataScriptName0=\r\nGenDataScriptName1=\r\nGenDataScriptName2=\r\nGenDataScriptName3=\r\nGenDataScriptName4=\r\nGenDataScriptName5=\r\nGenDataScriptName6=\r\nGenDataScriptName7=\r\nGenDataScriptName8=\r\nGenDataScriptName9=\r\nGenDataOdbc=0\r\nGenDataDelOld=No\r\nGenDataTitle=No\r\nGenDataDefNumRows=20\r\nGenDataCommit=0\r\nGenDataPacket=0\r\nGenDataOwner=No\r\nGenDataProfNumb=\r\nGenDataProfChar=\r\nGenDataProfDate=\r\nGenDataCSVSeparator=,\r\nGenDataFileFormat=CSV\r\nGenDataUseWizard=No\r\n\r\n[FolderOptions\\Pdm]\r\nIndxIQName=%COLUMN%_%INDEXTYPE%\r\nIndxPK=Yes\r\nIndxFK=Yes\r\nIndxAK=Yes\r\nIndxPKName=%TABLE%_PK\r\nIndxFKName=%REFR%_FK\r\nIndxAKName=%AKEY%_AK\r\nIndxPreserve=No\r\nIndxThreshold=0\r\nIndxStats=No\r\nRefrPreserve=No\r\nJidxPreserve=No\r\nRbldMultiFact=Yes\r\nRbldMultiDim=Yes\r\nRbldMultiJidx=Yes\r\nCubePreserve=No\r\nTablStProcPreserve=No\r\nProcDepPreserve=Yes\r\nTrgrDepPreserve=Yes\r\nCubeScriptPath=\r\nCubeScriptCase=0\r\nCubeScriptEncoding=ANSI\r\nCubeScriptNacct=No\r\nCubeScriptHeader=No\r\nCubeScriptExt=csv\r\nCubeScriptExt0=txt\r\nCubeScriptExt1=\r\nCubeScriptExt2=\r\nCubeScriptSep=,\r\nCubeScriptDeli=&quot;\r\nDfltDomnName=D_%.U:VALUE%\r\nDfltColnName=D_%.U:VALUE%\r\nDfltReuse=Yes\r\nDfltDrop=Yes</a:PackageOptionsText>\r\n<a:ModelOptionsText>[ModelOptions]\r\n\r\n[ModelOptions\\Physical Objects]\r\nCaseSensitive=No\r\nDisplayName=Yes\r\nEnableTrans=No\r\nEnableRequirements=No\r\nDefaultDttp=\r\nIgnoreOwner=No\r\nRebuildTrigger=Yes\r\nRefrUnique=No\r\nRefrAutoMigrate=Yes\r\nRefrMigrateReuse=Yes\r\nRefrMigrateDomain=Yes\r\nRefrMigrateCheck=Yes\r\nRefrMigrateRule=Yes\r\nRefrMigrateExtd=No\r\nRefrMigrDefaultLink=No\r\nRefrDfltImpl=D\r\nRefrPrgtColn=No\r\nRefrMigrateToEnd=No\r\nRebuildTriggerDep=No\r\nColnFKName=%.3:PARENT%_%COLUMN%\r\nColnFKNameUse=No\r\nDomnCopyDttp=Yes\r\nDomnCopyChck=No\r\nDomnCopyRule=No\r\nDomnCopyMand=No\r\nDomnCopyExtd=No\r\nDomnCopyProf=No\r\nNotation=0\r\nDomnDefaultMandatory=No\r\nColnDefaultMandatory=No\r\nTablDefaultOwner=\r\nViewDefaultOwner=\r\nTrgrDefaultOwnerTabl=\r\nTrgrDefaultOwnerView=\r\nIdxDefaultOwnerTabl=\r\nIdxDefaultOwnerView=\r\nJdxDefaultOwner=\r\nDBPackDefaultOwner=\r\nSeqDefaultOwner=\r\nProcDefaultOwner=\r\nDBMSTrgrDefaultOwner=\r\nCurrency=USD\r\nRefrDeleteConstraint=1\r\nRefrUpdateConstraint=1\r\nRefrParentMandatory=No\r\nRefrParentChangeAllow=Yes\r\nRefrCheckOnCommit=No\r\n\r\n[ModelOptions\\Physical Objects\\NamingOptionsTemplates]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\PDMPCKG]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\PDMPCKG\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\PDMPCKG\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\PDMDOMN]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\PDMDOMN\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\PDMDOMN\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\TABL]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\TABL\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\TABL\\Code]\r\nTemplate=\r\nMaxLen=64\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\COLN]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\COLN\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\COLN\\Code]\r\nTemplate=\r\nMaxLen=64\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\INDX]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\INDX\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\INDX\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\REFR]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\REFR\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\REFR\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VREF]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VREF\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VREF\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VIEW]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VIEW\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VIEW\\Code]\r\nTemplate=\r\nMaxLen=64\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VIEWC]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VIEWC\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\VIEWC\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WEBSERV]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WEBSERV\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WEBSERV\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=&#39;a&#39;-&#39;z&#39;,&#39;A&#39;-&#39;Z&#39;,&#39;0&#39;-&#39;9&#39;,&quot;/-_.!~*&#39;()&quot;\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WEBOP]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WEBOP\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WEBOP\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=&#39;a&#39;-&#39;z&#39;,&#39;A&#39;-&#39;Z&#39;,&#39;0&#39;-&#39;9&#39;,&quot;/-_.!~*&#39;()&quot;\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WPARAM]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WPARAM\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\WPARAM\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FACT]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FACT\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FACT\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DIMN]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DIMN\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DIMN\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\CUBE]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\CUBE\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\CUBE\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\MEAS]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\MEAS\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\MEAS\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DATTR]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DATTR\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DATTR\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FILO]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FILO\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FILO\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FRMEOBJ]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FRMEOBJ\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FRMEOBJ\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FRMELNK]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FRMELNK\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\FRMELNK\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DefaultClass]\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DefaultClass\\Name]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Physical Objects\\ClssNamingOptions\\DefaultClass\\Code]\r\nTemplate=\r\nMaxLen=254\r\nCase=M\r\nValidChar=\r\nInvldChar=\r\nAllValid=Yes\r\nNoAccent=No\r\nDefaultChar=\r\nScript=\r\nConvTable=\r\nConvTablePath=%_HOME%\\Resource Files\\Conversion Tables\r\n\r\n[ModelOptions\\Connection]\r\n\r\n[ModelOptions\\Pdm]\r\n\r\n[ModelOptions\\Generate]\r\n\r\n[ModelOptions\\Generate\\Pdm]\r\nRRMapping=No\r\n\r\n[ModelOptions\\Generate\\Cdm]\r\nCheckModel=Yes\r\nSaveLinks=Yes\r\nNameToCode=No\r\nNotation=2\r\n\r\n[ModelOptions\\Generate\\Oom]\r\nCheckModel=Yes\r\nSaveLinks=Yes\r\nORMapping=No\r\nNameToCode=Yes\r\nClassPrefix=\r\n\r\n[ModelOptions\\Generate\\Xsm]\r\nCheckModel=Yes\r\nSaveLinks=Yes\r\nORMapping=No\r\nNameToCode=No\r\n\r\n[ModelOptions\\Generate\\Ldm]\r\nCheckModel=Yes\r\nSaveLinks=Yes\r\nNameToCode=No\r\n\r\n[ModelOptions\\Default Opts]\r\n\r\n[ModelOptions\\Default Opts\\TABL]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\COLN]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\INDX]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\AKEY]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\PKEY]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\STOR]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\TSPC]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\SQNC]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\DTBS]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\USER]\r\nPhysOpts=\r\n\r\n[ModelOptions\\Default Opts\\JIDX]\r\nPhysOpts=</a:ModelOptionsText>\r\n<c:DBMS>\r\n<o:Shortcut Id=\"o3\">\r\n<a:ObjectID>AFAD9ECF-F417-4FCE-BEA4-884857D4C1A9</a:ObjectID>\r\n<a:Name>MySQL 5.0</a:Name>\r\n<a:Code>MYSQL50</a:Code>\r\n<a:CreationDate>1524449337</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449337</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:TargetStereotype/>\r\n<a:TargetID>F4F16ECD-F2F1-4006-AF6F-638D5C65F35E</a:TargetID>\r\n<a:TargetClassID>4BA9F647-DAB1-11D1-9944-006097355D9B</a:TargetClassID>\r\n</o:Shortcut>\r\n</c:DBMS>\r\n<c:PhysicalDiagrams>\r\n<o:PhysicalDiagram Id=\"o4\">\r\n<a:ObjectID>B6C2C4A4-6A8A-41F3-909D-C7B514E1EAE2</a:ObjectID>\r\n<a:Name>PhysicalDiagram_1</a:Name>\r\n<a:Code>PhysicalDiagram_1</a:Code>\r\n<a:CreationDate>1524449325</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297386</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DisplayPreferences>[DisplayPreferences]\r\n\r\n[DisplayPreferences\\PDM]\r\n\r\n[DisplayPreferences\\General]\r\nAdjust to text=Yes\r\nSnap Grid=No\r\nConstrain Labels=Yes\r\nDisplay Grid=No\r\nShow Page Delimiter=Yes\r\nGrid size=0\r\nGraphic unit=2\r\nWindow color=255, 255, 255\r\nBackground image=\r\nBackground mode=8\r\nWatermark image=\r\nWatermark mode=8\r\nShow watermark on screen=No\r\nGradient mode=0\r\nGradient end color=255, 255, 255\r\nShow Swimlane=No\r\nSwimlaneVert=Yes\r\nTreeVert=No\r\nCompDark=0\r\n\r\n[DisplayPreferences\\Object]\r\nMode=0\r\nTrunc Length=80\r\nWord Length=80\r\nWord Text=!&quot;&quot;#$%&amp;&#39;()*+,-./:;&lt;=&gt;?@[\\]^_`{|}~\r\nShortcut IntIcon=Yes\r\nShortcut IntLoct=Yes\r\nShortcut IntFullPath=No\r\nShortcut IntLastPackage=Yes\r\nShortcut ExtIcon=Yes\r\nShortcut ExtLoct=No\r\nShortcut ExtFullPath=No\r\nShortcut ExtLastPackage=Yes\r\nShortcut ExtIncludeModl=Yes\r\nEObjShowStrn=Yes\r\nExtendedObject.Comment=No\r\nExtendedObject.IconPicture=No\r\nExtendedObject_SymbolLayout=&lt;Form&gt;[CRLF] &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Object Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;Yes&quot; /&gt;[CRLF] &lt;Separator Name=&quot;Separator&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Comment&quot; Attribute=&quot;Comment&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;LEFT&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Icon&quot; Attribute=&quot;IconPicture&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;Yes&quot; /&gt;[CRLF]&lt;/Form&gt;\r\nELnkShowStrn=Yes\r\nELnkShowName=Yes\r\nExtendedLink_SymbolLayout=&lt;Form&gt;[CRLF] &lt;Form Name=&quot;Center&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/Form&gt;[CRLF] &lt;Form Name=&quot;Source&quot; &gt;[CRLF] &lt;/Form&gt;[CRLF] &lt;Form Name=&quot;Destination&quot; &gt;[CRLF] &lt;/Form&gt;[CRLF]&lt;/Form&gt;\r\nFileObject.Stereotype=No\r\nFileObject.DisplayName=Yes\r\nFileObject.LocationOrName=No\r\nFileObject.IconPicture=No\r\nFileObject.IconMode=Yes\r\nFileObject_SymbolLayout=&lt;Form&gt;[CRLF] &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;ExclusiveChoice Name=&quot;Exclusive Choice&quot; Mandatory=&quot;Yes&quot; Display=&quot;HorizontalRadios&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Location&quot; Attribute=&quot;LocationOrName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/ExclusiveChoice&gt;[CRLF] &lt;StandardAttribute Name=&quot;Icon&quot; Attribute=&quot;IconPicture&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;Yes&quot; /&gt;[CRLF]&lt;/Form&gt;\r\nPckgShowStrn=Yes\r\nPackage.Comment=No\r\nPackage.IconPicture=No\r\nPackage_SymbolLayout=\r\nDisplay Model Version=Yes\r\nTable.Stereotype=Yes\r\nTable.DisplayName=Yes\r\nTable.OwnerDisplayName=No\r\nTable.Columns=Yes\r\nTable.Columns._Filter=&quot;&quot;PDMCOLNALL\r\nTable.Columns._Columns=Stereotype DataType KeyIndicator\r\nTable.Columns._Limit=-5\r\nTable.Keys=No\r\nTable.Keys._Columns=Stereotype Indicator\r\nTable.Indexes=No\r\nTable.Indexes._Columns=Stereotype\r\nTable.Triggers=No\r\nTable.Triggers._Columns=Stereotype\r\nTable.Comment=No\r\nTable.IconPicture=No\r\nTable_SymbolLayout=&lt;Form&gt;[CRLF] &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;ExclusiveChoice Name=&quot;Exclusive Choice&quot; Mandatory=&quot;Yes&quot; Display=&quot;HorizontalRadios&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Owner and Name&quot; Attribute=&quot;OwnerDisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/ExclusiveChoice&gt;[CRLF] &lt;Separator Name=&quot;Separator&quot; /&gt;[CRLF] &lt;StandardCollection Name=&quot;Columns&quot; Collection=&quot;Columns&quot; Columns=&quot;Stereotype No\\r\\nDisplayName Yes\\r\\nDataType No\\r\\nSymbolDataType No &amp;quot;Domain or Data type&amp;quot;\\r\\nDomain No\\r\\nKeyIndicator No\\r\\nIndexIndicator No\\r\\nNullStatus No&quot; Filters=&quot;&amp;quot;All Columns&amp;quot;  PDMCOLNALL &amp;quot;&amp;quot;\\r\\n&amp;quot;PK Columns&amp;quot;  PDMCOLNPK &amp;quot;PRIM \\&amp;quot;TRUE\\&amp;quot; TRUE&amp;quot;\\r\\n&amp;quot;Key Columns&amp;quot;  PDMCOLNKEY &amp;quot;KEYS \\&amp;quot;TRUE\\&amp;quot; TRUE&amp;quot;&quot; HasLimit=&quot;Yes&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardCollection Name=&quot;Keys&quot; Collection=&quot;Keys&quot; Columns=&quot;Stereotype No\\r\\nDisplayName Yes\\r\\nIndicator No&quot; HasLimit=&quot;No&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardCollection Name=&quot;Indexes&quot; Collection=&quot;Indexes&quot; Columns=&quot;Stereotype No\\r\\nDisplayName Yes\\r\\nIndicator No&quot; HasLimit=&quot;No&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardCollection Name=&quot;Triggers&quot; Collection=&quot;Triggers&quot; Columns=&quot;Stereotype No\\r\\nDisplayName Yes&quot; HasLimit=&quot;No&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Comment&quot; Attribute=&quot;Comment&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;LEFT&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Icon&quot; Attribute=&quot;IconPicture&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;Yes&quot; /&gt;[CRLF]&lt;/Form&gt;\r\nView.Stereotype=Yes\r\nView.DisplayName=Yes\r\nView.OwnerDisplayName=No\r\nView.Columns=Yes\r\nView.Columns._Columns=DisplayName\r\nView.Columns._Limit=-5\r\nView.TemporaryVTables=Yes\r\nView.Indexes=No\r\nView.Comment=No\r\nView.IconPicture=No\r\nView_SymbolLayout=&lt;Form&gt;[CRLF] &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;ExclusiveChoice Name=&quot;Exclusive Choice&quot; Mandatory=&quot;Yes&quot; Display=&quot;HorizontalRadios&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Owner and Name&quot; Attribute=&quot;OwnerDisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/ExclusiveChoice&gt;[CRLF] &lt;Separator Name=&quot;Separator&quot; /&gt;[CRLF] &lt;StandardCollection Name=&quot;Columns&quot; Collection=&quot;Columns&quot; Columns=&quot;DisplayName No\\r\\nExpression No\\r\\nDataType No\\r\\nSymbolDataType No &amp;quot;Domain or Data type&amp;quot;\\r\\nIndexIndicator No&quot; HasLimit=&quot;Yes&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardCollection Name=&quot;Tables&quot; Collection=&quot;TemporaryVTables&quot; Columns=&quot;Name Yes&quot; HasLimit=&quot;No&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardCollection Name=&quot;Indexes&quot; Collection=&quot;Indexes&quot; Columns=&quot;DisplayName Yes&quot; HasLimit=&quot;No&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Comment&quot; Attribute=&quot;Comment&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;LEFT&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Icon&quot; Attribute=&quot;IconPicture&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;Yes&quot; /&gt;[CRLF]&lt;/Form&gt;\r\nProcedure.Stereotype=No\r\nProcedure.DisplayName=Yes\r\nProcedure.OwnerDisplayName=No\r\nProcedure.Comment=No\r\nProcedure.IconPicture=No\r\nProcedure_SymbolLayout=&lt;Form&gt;[CRLF] &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;ExclusiveChoice Name=&quot;Exclusive Choice&quot; Mandatory=&quot;Yes&quot; Display=&quot;HorizontalRadios&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Owner and Name&quot; Attribute=&quot;OwnerDisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/ExclusiveChoice&gt;[CRLF] &lt;Separator Name=&quot;Separator&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Comment&quot; Attribute=&quot;Comment&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;LEFT&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;StandardAttribute Name=&quot;Icon&quot; Attribute=&quot;IconPicture&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Alignment=&quot;CNTR&quot; Caption=&quot;&quot; Mandatory=&quot;Yes&quot; /&gt;[CRLF]&lt;/Form&gt;\r\nReference.Cardinality=No\r\nReference.ImplementationType=No\r\nReference.ChildRole=Yes\r\nReference.Stereotype=Yes\r\nReference.DisplayName=No\r\nReference.ForeignKeyConstraintName=Yes\r\nReference.JoinExpression=No\r\nReference.Integrity=No\r\nReference.ParentRole=Yes\r\nReference_SymbolLayout=&lt;Form&gt;[CRLF] &lt;Form Name=&quot;Source&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Cardinality&quot; Attribute=&quot;Cardinality&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Implementation&quot; Attribute=&quot;ImplementationType&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Child Role&quot; Attribute=&quot;ChildRole&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/Form&gt;[CRLF] &lt;Form Name=&quot;Center&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;ExclusiveChoice Name=&quot;Exclusive Choice&quot; Mandatory=&quot;No&quot; Display=&quot;HorizontalRadios&quot; &gt;[CRLF]   &lt;StandardAttribute Name=&quot;Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]   &lt;StandardAttribute Name=&quot;Cons&amp;amp;traint Name&quot; Attribute=&quot;ForeignKeyConstraintName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;Cons&amp;amp;traint Name&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]   &lt;StandardAttribute Name=&quot;Join&quot; Attribute=&quot;JoinExpression&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;Join&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;/ExclusiveChoice&gt;[CRLF]  &lt;StandardAttribute Name=&quot;Referential integrity&quot; Attribute=&quot;Integrity&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;Referential integrity&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/Form&gt;[CRLF] &lt;Form Name=&quot;Destination&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Parent Role&quot; Attribute=&quot;ParentRole&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/Form&gt;[CRLF]&lt;/Form&gt;\r\nViewReference.ChildRole=Yes\r\nViewReference.Stereotype=Yes\r\nViewReference.DisplayName=No\r\nViewReference.JoinExpression=No\r\nViewReference.ParentRole=Yes\r\nViewReference_SymbolLayout=&lt;Form&gt;[CRLF] &lt;Form Name=&quot;Source&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Child Role&quot; Attribute=&quot;ChildRole&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/Form&gt;[CRLF] &lt;Form Name=&quot;Center&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Stereotype&quot; Attribute=&quot;Stereotype&quot; Prefix=&quot;&amp;lt;&amp;lt;&quot; Suffix=&quot;&amp;gt;&amp;gt;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;ExclusiveChoice Name=&quot;Exclusive Choice&quot; Mandatory=&quot;No&quot; Display=&quot;HorizontalRadios&quot; &gt;[CRLF]   &lt;StandardAttribute Name=&quot;Name&quot; Attribute=&quot;DisplayName&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]   &lt;StandardAttribute Name=&quot;Join Expression&quot; Attribute=&quot;JoinExpression&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF]  &lt;/ExclusiveChoice&gt;[CRLF] &lt;/Form&gt;[CRLF] &lt;Form Name=&quot;Destination&quot; &gt;[CRLF]  &lt;StandardAttribute Name=&quot;Parent Role&quot; Attribute=&quot;ParentRole&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Caption=&quot;&quot; Mandatory=&quot;No&quot; /&gt;[CRLF] &lt;/Form&gt;[CRLF]&lt;/Form&gt;\r\nFile Location=No\r\nPckgStrn=Yes\r\nColnMode=0\r\nColnMax=5\r\nTablOwnr=No\r\nColnDttp=Yes\r\nColnDomn=No\r\nColnShowDomn=No\r\nColnKey=Yes\r\nColnIndx=No\r\nColnMand=No\r\nColnStrn=Yes\r\nVColName=Yes\r\nVColExpr=No\r\nVColDttp=No\r\nVColIndx=No\r\nVColCMod=0\r\nVColCMax=5\r\nProcOwnr=No\r\nKeyStrn=Yes\r\nIndxStrn=Yes\r\nTrgrStrn=Yes\r\n\r\n[DisplayPreferences\\Symbol]\r\n\r\n[DisplayPreferences\\Symbol\\FRMEOBJ]\r\nSTRNFont=新宋体,8,N\r\nSTRNFont color=0, 0, 0\r\nDISPNAMEFont=新宋体,8,N\r\nDISPNAMEFont color=0, 0, 0\r\nLABLFont=新宋体,8,N\r\nLABLFont color=0, 0, 0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nWidth=6000\r\nHeight=2000\r\nBrush color=255 255 255\r\nFill Color=Yes\r\nBrush style=6\r\nBrush bitmap mode=12\r\nBrush gradient mode=64\r\nBrush gradient color=192 192 192\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 255 128 128\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\FRMELNK]\r\nCENTERFont=新宋体,8,N\r\nCENTERFont color=0, 0, 0\r\nLine style=0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nBrush color=255 255 255\r\nFill Color=Yes\r\nBrush style=1\r\nBrush bitmap mode=12\r\nBrush gradient mode=0\r\nBrush gradient color=118 118 118\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 128 128 255\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\FILO]\r\nOBJSTRNFont=新宋体,8,N\r\nOBJSTRNFont color=0, 0, 0\r\nDISPNAMEFont=新宋体,8,N\r\nDISPNAMEFont color=0, 0, 0\r\nLCNMFont=新宋体,8,N\r\nLCNMFont color=0, 0, 0\r\nAutoAdjustToText=Yes\r\nKeep aspect=Yes\r\nKeep center=Yes\r\nKeep size=No\r\nWidth=2400\r\nHeight=2400\r\nBrush color=255 255 255\r\nFill Color=No\r\nBrush style=1\r\nBrush bitmap mode=12\r\nBrush gradient mode=0\r\nBrush gradient color=118 118 118\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 0 0 255\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\PDMPCKG]\r\nSTRNFont=新宋体,8,N\r\nSTRNFont color=0, 0, 0\r\nDISPNAMEFont=新宋体,8,N\r\nDISPNAMEFont color=0, 0, 0\r\nLABLFont=新宋体,8,N\r\nLABLFont color=0, 0, 0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nWidth=4800\r\nHeight=3600\r\nBrush color=255 255 192\r\nFill Color=Yes\r\nBrush style=6\r\nBrush bitmap mode=12\r\nBrush gradient mode=65\r\nBrush gradient color=255 255 255\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 178 178 178\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\TABL]\r\nSTRNFont=新宋体,8,N\r\nSTRNFont color=0, 0, 0\r\nDISPNAMEFont=新宋体,8,N\r\nDISPNAMEFont color=0, 0, 0\r\nOWNRDISPNAMEFont=新宋体,8,N\r\nOWNRDISPNAMEFont color=0, 0, 0\r\nColumnsFont=新宋体,8,N\r\nColumnsFont color=0, 0, 0\r\nTablePkColumnsFont=新宋体,8,U\r\nTablePkColumnsFont color=0, 0, 0\r\nTableFkColumnsFont=新宋体,8,N\r\nTableFkColumnsFont color=0, 0, 0\r\nKeysFont=新宋体,8,N\r\nKeysFont color=0, 0, 0\r\nIndexesFont=新宋体,8,N\r\nIndexesFont color=0, 0, 0\r\nTriggersFont=新宋体,8,N\r\nTriggersFont color=0, 0, 0\r\nLABLFont=新宋体,8,N\r\nLABLFont color=0, 0, 0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nWidth=4800\r\nHeight=4000\r\nBrush color=178 214 252\r\nFill Color=Yes\r\nBrush style=6\r\nBrush bitmap mode=12\r\nBrush gradient mode=65\r\nBrush gradient color=255 255 255\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 0 128 192\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\VIEW]\r\nSTRNFont=新宋体,8,N\r\nSTRNFont color=0, 0, 0\r\nDISPNAMEFont=新宋体,8,N\r\nDISPNAMEFont color=0, 0, 0\r\nOWNRDISPNAMEFont=新宋体,8,N\r\nOWNRDISPNAMEFont color=0, 0, 0\r\nColumnsFont=新宋体,8,N\r\nColumnsFont color=0, 0, 0\r\nTablePkColumnsFont=新宋体,8,U\r\nTablePkColumnsFont color=0, 0, 0\r\nTableFkColumnsFont=新宋体,8,N\r\nTableFkColumnsFont color=0, 0, 0\r\nTemporaryVTablesFont=新宋体,8,N\r\nTemporaryVTablesFont color=0, 0, 0\r\nIndexesFont=新宋体,8,N\r\nIndexesFont color=0, 0, 0\r\nLABLFont=新宋体,8,N\r\nLABLFont color=0, 0, 0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nWidth=4800\r\nHeight=4000\r\nBrush color=208 208 255\r\nFill Color=Yes\r\nBrush style=6\r\nBrush bitmap mode=12\r\nBrush gradient mode=65\r\nBrush gradient color=255 255 255\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 128 128 192\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\PROC]\r\nSTRNFont=新宋体,8,N\r\nSTRNFont color=0, 0, 0\r\nDISPNAMEFont=新宋体,8,N\r\nDISPNAMEFont color=0, 0, 0\r\nOWNRDISPNAMEFont=新宋体,8,N\r\nOWNRDISPNAMEFont color=0, 0, 0\r\nLABLFont=新宋体,8,N\r\nLABLFont color=0, 0, 0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nWidth=4000\r\nHeight=1000\r\nBrush color=255 255 192\r\nFill Color=Yes\r\nBrush style=6\r\nBrush bitmap mode=12\r\nBrush gradient mode=65\r\nBrush gradient color=255 255 255\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 128 108 0\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\REFR]\r\nSOURCEFont=新宋体,8,N\r\nSOURCEFont color=0, 0, 0\r\nCENTERFont=新宋体,8,N\r\nCENTERFont color=0, 0, 0\r\nDESTINATIONFont=新宋体,8,N\r\nDESTINATIONFont color=0, 0, 0\r\nLine style=0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nBrush color=255 255 255\r\nFill Color=Yes\r\nBrush style=1\r\nBrush bitmap mode=12\r\nBrush gradient mode=0\r\nBrush gradient color=118 118 118\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 0 128 192\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\VREF]\r\nSOURCEFont=新宋体,8,N\r\nSOURCEFont color=0, 0, 0\r\nCENTERFont=新宋体,8,N\r\nCENTERFont color=0, 0, 0\r\nDESTINATIONFont=新宋体,8,N\r\nDESTINATIONFont color=0, 0, 0\r\nLine style=0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nBrush color=255 255 255\r\nFill Color=Yes\r\nBrush style=1\r\nBrush bitmap mode=12\r\nBrush gradient mode=0\r\nBrush gradient color=118 118 118\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 128 128 192\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\USRDEPD]\r\nOBJXSTRFont=新宋体,8,N\r\nOBJXSTRFont color=0, 0, 0\r\nLine style=0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nBrush color=255 255 255\r\nFill Color=Yes\r\nBrush style=1\r\nBrush bitmap mode=12\r\nBrush gradient mode=0\r\nBrush gradient color=118 118 118\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=2 0 128 128 255\r\nShadow color=192 192 192\r\nShadow=0\r\n\r\n[DisplayPreferences\\Symbol\\Free Symbol]\r\nFree TextFont=新宋体,8,N\r\nFree TextFont color=0, 0, 0\r\nLine style=0\r\nAutoAdjustToText=Yes\r\nKeep aspect=No\r\nKeep center=No\r\nKeep size=No\r\nBrush color=255 255 255\r\nFill Color=Yes\r\nBrush style=1\r\nBrush bitmap mode=12\r\nBrush gradient mode=0\r\nBrush gradient color=118 118 118\r\nBrush background image=\r\nCustom shape=\r\nCustom text mode=0\r\nPen=1 0 0 0 255\r\nShadow color=192 192 192\r\nShadow=0</a:DisplayPreferences>\r\n<a:PaperSize>(8268, 11693)</a:PaperSize>\r\n<a:PageMargins>((315,354), (433,354))</a:PageMargins>\r\n<a:PageOrientation>1</a:PageOrientation>\r\n<a:PaperSource>15</a:PaperSource>\r\n<c:Symbols>\r\n<o:TableSymbol Id=\"o5\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296407</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-38123,15297), (-26435,28269))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o6\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o7\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1524449886</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-23935,12010), (-11861,28282))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o8\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o9\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296409</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-9361,18172), (2713,27845))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o10\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o11\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1524449886</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((5214,16547), (17288,27869))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o12\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o13\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296412</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((19788,14872), (31862,27845))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o14\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o15\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296204</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-37598,8498), (-29000,12497))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o16\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o17\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296205</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-37674,3548), (-29076,7547))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o18\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o19\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296308</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-37528,-6452), (-28929,-2453))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o20\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o21\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296401</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-24280,-1775), (-11048,10373))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o22\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o23\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296599</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-9182,625), (2892,10298))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o24\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o25\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538296612</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((5017,-2538), (17091,10434))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o26\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o27\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538297772</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-39520,-17440), (-26288,-8592))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o28\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o29\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538297770</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-24744,-19106), (-10738,-8608))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o30\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o31\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538297380</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-9749,-20696), (3870,-8548))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o32\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o33\">\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:ModificationDate>1538297383</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((5261,-17623), (18494,-8774))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o34\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o35\">\r\n<a:CreationDate>1538296083</a:CreationDate>\r\n<a:ModificationDate>1538296211</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((-37675,-1349), (-29076,2650))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o36\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TableSymbol Id=\"o37\">\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:ModificationDate>1538296608</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((19570,-987), (32030,8687))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o38\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n<o:TextSymbol Id=\"o39\">\r\n<a:Text>config_id</a:Text>\r\n<a:CreationDate>1538296632</a:CreationDate>\r\n<a:ModificationDate>1538297253</a:ModificationDate>\r\n<a:Rect>((-13950,-17175), (73200,19575))</a:Rect>\r\n<a:TextStyle>4130</a:TextStyle>\r\n<a:BaseSymbol.Flags>1</a:BaseSymbol.Flags>\r\n<a:LineColor>0</a:LineColor>\r\n<a:DashStyle>7</a:DashStyle>\r\n<a:FillColor>16777215</a:FillColor>\r\n<a:ShadowColor>16777215</a:ShadowColor>\r\n<a:FontName>新宋体,8,N</a:FontName>\r\n</o:TextSymbol>\r\n<o:TableSymbol Id=\"o40\">\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:ModificationDate>1538297498</a:ModificationDate>\r\n<a:IconMode>-1</a:IconMode>\r\n<a:Rect>((19859,-18262), (33092,-8589))</a:Rect>\r\n<a:LineColor>12615680</a:LineColor>\r\n<a:FillColor>16570034</a:FillColor>\r\n<a:ShadowColor>12632256</a:ShadowColor>\r\n<a:FontList>STRN 0 新宋体,8,N\r\nDISPNAME 0 新宋体,8,N\r\nOWNRDISPNAME 0 新宋体,8,N\r\nColumns 0 新宋体,8,N\r\nTablePkColumns 0 新宋体,8,U\r\nTableFkColumns 0 新宋体,8,N\r\nKeys 0 新宋体,8,N\r\nIndexes 0 新宋体,8,N\r\nTriggers 0 新宋体,8,N\r\nLABL 0 新宋体,8,N</a:FontList>\r\n<a:BrushStyle>6</a:BrushStyle>\r\n<a:GradientFillMode>65</a:GradientFillMode>\r\n<a:GradientEndColor>16777215</a:GradientEndColor>\r\n<c:Object>\r\n<o:Table Ref=\"o41\"/>\r\n</c:Object>\r\n</o:TableSymbol>\r\n</c:Symbols>\r\n</o:PhysicalDiagram>\r\n</c:PhysicalDiagrams>\r\n<c:DefaultDiagram>\r\n<o:PhysicalDiagram Ref=\"o4\"/>\r\n</c:DefaultDiagram>\r\n<c:Tables>\r\n<o:Table Id=\"o6\">\r\n<a:ObjectID>BB11FFF9-9DBB-4648-87AA-9A50E1214549</a:ObjectID>\r\n<a:Name>sys_dept</a:Name>\r\n<a:Code>sys_dept</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297518</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>部门表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o42\">\r\n<a:ObjectID>00C66282-419A-4915-8509-DFFFE6352DE8</a:ObjectID>\r\n<a:Name>dept_id</a:Name>\r\n<a:Code>dept_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>部门id</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o43\">\r\n<a:ObjectID>5B6FB0B1-5B1E-4E86-AF2A-72C49EBB315E</a:ObjectID>\r\n<a:Name>parent_id</a:Name>\r\n<a:Code>parent_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>父部门id</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o44\">\r\n<a:ObjectID>065E33A5-6AB5-44F1-8FEC-A72311EECD66</a:ObjectID>\r\n<a:Name>ancestors</a:Name>\r\n<a:Code>ancestors</a:Code>\r\n<a:CreationDate>1538295690</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538295792</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o45\">\r\n<a:ObjectID>EBB59EC8-AFD4-40E3-B811-DD5040728D91</a:ObjectID>\r\n<a:Name>dept_name</a:Name>\r\n<a:Code>dept_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>部门名称</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(30)</a:DataType>\r\n<a:Length>30</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o46\">\r\n<a:ObjectID>2F26C025-82B0-4AC5-AEE0-32BA07B7B529</a:ObjectID>\r\n<a:Name>order_num</a:Name>\r\n<a:Code>order_num</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>显示顺序</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(4)</a:DataType>\r\n<a:Length>4</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o47\">\r\n<a:ObjectID>CA504E09-528C-482E-A0C7-F86C559AA3A6</a:ObjectID>\r\n<a:Name>leader</a:Name>\r\n<a:Code>leader</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>负责人</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(20)</a:DataType>\r\n<a:Length>20</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o48\">\r\n<a:ObjectID>9CFC55C4-DF2B-4A90-A789-C3839FAA43A8</a:ObjectID>\r\n<a:Name>phone</a:Name>\r\n<a:Code>phone</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>联系电话</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(20)</a:DataType>\r\n<a:Length>20</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o49\">\r\n<a:ObjectID>1A9407E5-D74E-4CE9-9078-C4EC25393F7B</a:ObjectID>\r\n<a:Name>email</a:Name>\r\n<a:Code>email</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>邮箱</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(20)</a:DataType>\r\n<a:Length>20</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o50\">\r\n<a:ObjectID>B6772812-4B69-4248-871D-FA1B4BA0E5F7</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538295792</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>部门状态:0正常,1停用</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o51\">\r\n<a:ObjectID>6EBD2BFF-861E-4247-BAAB-B37CCBAF6F8D</a:ObjectID>\r\n<a:Name>del_flag</a:Name>\r\n<a:Code>del_flag</a:Code>\r\n<a:CreationDate>1538295690</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538295792</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o52\">\r\n<a:ObjectID>2504A090-F6D6-493F-855E-5154E01AF0CA</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o53\">\r\n<a:ObjectID>D866AE9E-E7FF-47B2-BF3D-9BC1605A2F39</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o54\">\r\n<a:ObjectID>7C6C9836-FC23-4492-8CF1-A4439E01B57C</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o55\">\r\n<a:ObjectID>FCED770D-005C-4531-A9D7-D1FD0A054719</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o56\">\r\n<a:ObjectID>15C1774B-9F17-48B6-A61F-728A25220B30</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o42\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o56\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o8\">\r\n<a:ObjectID>AA56FD91-4450-4282-8F31-AE302DF6AFEC</a:ObjectID>\r\n<a:Name>sys_user</a:Name>\r\n<a:Code>sys_user</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297540</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>用户信息表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o57\">\r\n<a:ObjectID>4A920BCE-4040-4F12-89D2-7DF345B90321</a:ObjectID>\r\n<a:Name>user_id</a:Name>\r\n<a:Code>user_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>用户ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o58\">\r\n<a:ObjectID>174E10B2-4A4D-40FF-80B8-B4D285561E42</a:ObjectID>\r\n<a:Name>dept_id</a:Name>\r\n<a:Code>dept_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297552</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>部门ID</a:Comment>\r\n<a:DefaultValue>NULL</a:DefaultValue>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o59\">\r\n<a:ObjectID>1D4908A9-5416-4252-BA09-FA122D0194C3</a:ObjectID>\r\n<a:Name>login_name</a:Name>\r\n<a:Code>login_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>登录账号</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(30)</a:DataType>\r\n<a:Length>30</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o60\">\r\n<a:ObjectID>2EF63346-9E82-4746-81B7-AB67D727446D</a:ObjectID>\r\n<a:Name>user_name</a:Name>\r\n<a:Code>user_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>用户昵称</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(30)</a:DataType>\r\n<a:Length>30</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o61\">\r\n<a:ObjectID>477EA57C-0E0B-4596-9A85-EC91E72F5160</a:ObjectID>\r\n<a:Name>user_type</a:Name>\r\n<a:Code>user_type</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>类型:Y默认用户,N非默认用户</a:Comment>\r\n<a:DefaultValue>N</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o62\">\r\n<a:ObjectID>CD16FFF4-F214-473B-A9A8-FA30A3E357D1</a:ObjectID>\r\n<a:Name>email</a:Name>\r\n<a:Code>email</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>用户邮箱</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o63\">\r\n<a:ObjectID>61603FA5-3EBC-4389-AED7-1B54D238A563</a:ObjectID>\r\n<a:Name>phonenumber</a:Name>\r\n<a:Code>phonenumber</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>手机号码</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(20)</a:DataType>\r\n<a:Length>20</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o64\">\r\n<a:ObjectID>65E9DE55-ED58-4BD9-B96C-7C081D1119B2</a:ObjectID>\r\n<a:Name>sex</a:Name>\r\n<a:Code>sex</a:Code>\r\n<a:CreationDate>1538295815</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538295948</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o65\">\r\n<a:ObjectID>E5E35061-221A-4BB9-AA22-3CF20F1FCCF6</a:ObjectID>\r\n<a:Name>avatar</a:Name>\r\n<a:Code>avatar</a:Code>\r\n<a:CreationDate>1538295815</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538295948</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o66\">\r\n<a:ObjectID>4ED1C2BF-B826-4A82-9464-EEBF271F4054</a:ObjectID>\r\n<a:Name>password</a:Name>\r\n<a:Code>password</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>密码</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o67\">\r\n<a:ObjectID>53E6BB49-3435-46E0-832F-BCAFE1A021CB</a:ObjectID>\r\n<a:Name>salt</a:Name>\r\n<a:Code>salt</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>盐加密</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o68\">\r\n<a:ObjectID>245CAD53-B33B-4EED-8CFA-7AA10ED943B8</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297540</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>账号状态:0正常,1禁用</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o69\">\r\n<a:ObjectID>7F851464-6CC5-445B-9413-2A89B9CE90CB</a:ObjectID>\r\n<a:Name>del_flag</a:Name>\r\n<a:Code>del_flag</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538295948</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>拒绝登录描述</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o70\">\r\n<a:ObjectID>3DC8EC79-D75A-4BF8-8FBC-152E938AC14F</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o71\">\r\n<a:ObjectID>48C8C936-7A34-4A97-AACA-A6F07751FFAD</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o72\">\r\n<a:ObjectID>6050B4F3-9B26-4B40-AB4C-BA483F179958</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o73\">\r\n<a:ObjectID>CD1E7E11-8EB6-4C9C-A69C-39CBCF10573E</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o74\">\r\n<a:ObjectID>F9F55D4C-13E6-49A0-BFDB-E0AFE0FA5501</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1538295815</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538295948</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o75\">\r\n<a:ObjectID>2E35FD67-A7A7-4B10-85E4-85115AD0E143</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o57\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o75\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o10\">\r\n<a:ObjectID>2711A520-532C-4F14-A034-BFF047C9CD6B</a:ObjectID>\r\n<a:Name>sys_post</a:Name>\r\n<a:Code>sys_post</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297571</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>岗位信息表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o76\">\r\n<a:ObjectID>FB04D29E-41F0-49A3-BFDB-58E222843F21</a:ObjectID>\r\n<a:Name>post_id</a:Name>\r\n<a:Code>post_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>岗位ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o77\">\r\n<a:ObjectID>50010C4E-4F59-47B9-8F08-05E8E071E8B1</a:ObjectID>\r\n<a:Name>post_code</a:Name>\r\n<a:Code>post_code</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>岗位编码</a:Comment>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o78\">\r\n<a:ObjectID>0F929250-051E-4344-B22A-C30E071A543B</a:ObjectID>\r\n<a:Name>post_name</a:Name>\r\n<a:Code>post_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>岗位名称</a:Comment>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o79\">\r\n<a:ObjectID>2BC9005E-350F-46BE-98D6-9B13060F1B20</a:ObjectID>\r\n<a:Name>post_sort</a:Name>\r\n<a:Code>post_sort</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>显示顺序</a:Comment>\r\n<a:DataType>int(4)</a:DataType>\r\n<a:Length>4</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o80\">\r\n<a:ObjectID>F6D7AD3E-5EA0-4759-B6BF-6334B7105B78</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297565</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>状态（0正常 1停用）</a:Comment>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o81\">\r\n<a:ObjectID>CED01369-5063-479D-A444-32936369A486</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o82\">\r\n<a:ObjectID>A29528FF-A2B9-4149-B997-1B0204D42E40</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o83\">\r\n<a:ObjectID>6026A05D-0C1E-497E-8EAF-FDB704BE6A52</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o84\">\r\n<a:ObjectID>DF516F5F-CD82-4347-AC57-BDCB4E5DD75E</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o85\">\r\n<a:ObjectID>539CEC34-49F0-49A0-9B7C-B84655FD2233</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>备注</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o86\">\r\n<a:ObjectID>14E893B1-D0BA-46A7-A905-F0FFA089B65A</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o76\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o86\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o12\">\r\n<a:ObjectID>11337551-BA45-43CD-9148-92BE60E2F8F5</a:ObjectID>\r\n<a:Name>sys_role</a:Name>\r\n<a:Code>sys_role</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297608</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>角色信息表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o87\">\r\n<a:ObjectID>A420E2C9-8FE3-452A-9047-C7BEACE8490C</a:ObjectID>\r\n<a:Name>role_id</a:Name>\r\n<a:Code>role_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>角色ID</a:Comment>\r\n<a:DataType>int(10)</a:DataType>\r\n<a:Length>10</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o88\">\r\n<a:ObjectID>9342763D-5B89-4440-965B-2B55DB4ACD86</a:ObjectID>\r\n<a:Name>role_name</a:Name>\r\n<a:Code>role_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>角色名称</a:Comment>\r\n<a:DataType>varchar(30)</a:DataType>\r\n<a:Length>30</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o89\">\r\n<a:ObjectID>54480009-0C7E-40F2-AA76-CD914A6D66C5</a:ObjectID>\r\n<a:Name>role_key</a:Name>\r\n<a:Code>role_key</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>角色权限字符串</a:Comment>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o90\">\r\n<a:ObjectID>E73F4D0E-12A0-42B5-B3CE-B573D499DD6C</a:ObjectID>\r\n<a:Name>role_sort</a:Name>\r\n<a:Code>role_sort</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538296031</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>显示顺序</a:Comment>\r\n<a:DataType>int(10)</a:DataType>\r\n<a:Length>10</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o91\">\r\n<a:ObjectID>5F836F54-9EBD-4768-AA3C-F268F5FAFE8D</a:ObjectID>\r\n<a:Name>data_scope</a:Name>\r\n<a:Code>data_scope</a:Code>\r\n<a:CreationDate>1538295973</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296031</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o92\">\r\n<a:ObjectID>424ED799-E4C1-44AD-A172-C2B3C405E9C5</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297608</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>角色状态:0正常,1禁用</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o93\">\r\n<a:ObjectID>8E034C76-5966-4246-B81B-7B12F37D96A7</a:ObjectID>\r\n<a:Name>del_flag</a:Name>\r\n<a:Code>del_flag</a:Code>\r\n<a:CreationDate>1538295973</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296031</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o94\">\r\n<a:ObjectID>214F6E1F-28B1-454B-ABF0-D1C43220129D</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o95\">\r\n<a:ObjectID>1A6D5791-0353-4ABC-8BC2-921BB87A2E5A</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o96\">\r\n<a:ObjectID>D6394880-A49C-4B83-B43A-5FDBAA918AA3</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o97\">\r\n<a:ObjectID>34285DF5-8E36-452B-A3AA-9F4290C20F7E</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o98\">\r\n<a:ObjectID>2FAB98F7-68A2-460B-8A20-5D5DA73F5103</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>备注</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o99\">\r\n<a:ObjectID>4342E67F-D33C-435F-9865-973E053B6075</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o87\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o99\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o14\">\r\n<a:ObjectID>FBC2A590-443B-43C9-82D5-687B850C8B3D</a:ObjectID>\r\n<a:Name>sys_menu</a:Name>\r\n<a:Code>sys_menu</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297627</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>菜单权限表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o100\">\r\n<a:ObjectID>BB061292-3B99-432E-9B96-5362AAD918B9</a:ObjectID>\r\n<a:Name>menu_id</a:Name>\r\n<a:Code>menu_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>菜单ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o101\">\r\n<a:ObjectID>EA8422AB-37B1-4D60-A3C9-A4BF9039A9D4</a:ObjectID>\r\n<a:Name>menu_name</a:Name>\r\n<a:Code>menu_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>菜单名称</a:Comment>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o102\">\r\n<a:ObjectID>E56E04A8-63F6-4271-92E3-974DC84DD536</a:ObjectID>\r\n<a:Name>parent_id</a:Name>\r\n<a:Code>parent_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>父菜单ID</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o103\">\r\n<a:ObjectID>1809914E-6B09-4CD2-8916-E603D6717557</a:ObjectID>\r\n<a:Name>order_num</a:Name>\r\n<a:Code>order_num</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>显示顺序</a:Comment>\r\n<a:DefaultValue>NULL</a:DefaultValue>\r\n<a:DataType>int(4)</a:DataType>\r\n<a:Length>4</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o104\">\r\n<a:ObjectID>FCB44D46-3C21-40CB-B942-57823E52E5B1</a:ObjectID>\r\n<a:Name>url</a:Name>\r\n<a:Code>url</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>请求地址</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(200)</a:DataType>\r\n<a:Length>200</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o105\">\r\n<a:ObjectID>667EE044-6805-4668-BAF4-E78B3052051F</a:ObjectID>\r\n<a:Name>menu_type</a:Name>\r\n<a:Code>menu_type</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>类型:M目录,C菜单,F按钮</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o106\">\r\n<a:ObjectID>F7658083-BCAB-46F7-AF31-8A4B1D8749EF</a:ObjectID>\r\n<a:Name>visible</a:Name>\r\n<a:Code>visible</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297627</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>菜单状态:0显示,1隐藏</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o107\">\r\n<a:ObjectID>528611C8-C319-430F-8F00-68FBA60F310B</a:ObjectID>\r\n<a:Name>perms</a:Name>\r\n<a:Code>perms</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>权限标识</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o108\">\r\n<a:ObjectID>38004CD7-8DD0-43F1-9E59-B50132CB6F1A</a:ObjectID>\r\n<a:Name>icon</a:Name>\r\n<a:Code>icon</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>菜单图标</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o109\">\r\n<a:ObjectID>6927665F-EC42-4E1F-A275-4B27F442B6B8</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o110\">\r\n<a:ObjectID>1A6A4D0F-0B0B-4522-B4DA-3F1D592CB889</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o111\">\r\n<a:ObjectID>605D7776-4820-4BA9-91E8-AD837B73AEFB</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o112\">\r\n<a:ObjectID>4CFF26BB-8736-4864-855E-C7C1B133370B</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o113\">\r\n<a:ObjectID>67C6E46C-DF06-480A-BC74-E927406E5D26</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>备注</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o114\">\r\n<a:ObjectID>08EBE713-9E4D-4312-AA7D-2E4E439734E5</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o100\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o114\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o16\">\r\n<a:ObjectID>F8CB66D1-3632-4509-97C4-17016BE261FC</a:ObjectID>\r\n<a:Name>sys_user_role</a:Name>\r\n<a:Code>sys_user_role</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297676</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>用户和角色关联表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o115\">\r\n<a:ObjectID>73701F72-C45B-4CA0-8A62-632890E3DEF0</a:ObjectID>\r\n<a:Name>user_id</a:Name>\r\n<a:Code>user_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>用户ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o116\">\r\n<a:ObjectID>CABD458B-DA59-46A8-99C3-088AD8D34097</a:ObjectID>\r\n<a:Name>role_id</a:Name>\r\n<a:Code>role_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>角色ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o117\">\r\n<a:ObjectID>37C3213B-EF22-4CD4-A91F-9A9A2503FB2A</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o115\"/>\r\n<o:Column Ref=\"o116\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o117\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o18\">\r\n<a:ObjectID>9F8C6A9F-3221-410E-AEA4-D1A80026397E</a:ObjectID>\r\n<a:Name>sys_role_menu</a:Name>\r\n<a:Code>sys_role_menu</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297683</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>角色和菜单关联表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o118\">\r\n<a:ObjectID>D2E151A5-6156-46EF-844E-0ADC3070293B</a:ObjectID>\r\n<a:Name>role_id</a:Name>\r\n<a:Code>role_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>角色ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o119\">\r\n<a:ObjectID>6B8C1E62-FD8B-4504-8FA0-F69917722FBD</a:ObjectID>\r\n<a:Name>menu_id</a:Name>\r\n<a:Code>menu_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>菜单ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o120\">\r\n<a:ObjectID>2E72304F-91F0-4392-BAE8-BBF7A4346B7D</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o118\"/>\r\n<o:Column Ref=\"o119\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o120\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o20\">\r\n<a:ObjectID>726CB18E-7D5B-4E2E-9CF8-047AD5AF89E3</a:ObjectID>\r\n<a:Name>sys_user_post</a:Name>\r\n<a:Code>sys_user_post</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297694</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>用户与岗位关联表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o121\">\r\n<a:ObjectID>E4A1CAB6-0F63-4917-ACEF-418DE7F894BA</a:ObjectID>\r\n<a:Name>user_id</a:Name>\r\n<a:Code>user_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538296306</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>用户ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o122\">\r\n<a:ObjectID>8E7188D5-B3A5-4F1D-B6CB-D77D652414DE</a:ObjectID>\r\n<a:Name>post_id</a:Name>\r\n<a:Code>post_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538296306</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>岗位ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o123\">\r\n<a:ObjectID>4091B7D3-2404-4C20-BBCD-B63E22A5E960</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o121\"/>\r\n<o:Column Ref=\"o122\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o123\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o22\">\r\n<a:ObjectID>FE347A45-D8EC-423B-9B38-4D315A3ABE42</a:ObjectID>\r\n<a:Name>sys_oper_log</a:Name>\r\n<a:Code>sys_oper_log</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297699</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>操作日志记录</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o124\">\r\n<a:ObjectID>F5FC8AC1-7415-4A57-BA2C-EE2E7B9E1EFC</a:ObjectID>\r\n<a:Name>oper_id</a:Name>\r\n<a:Code>oper_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>日志主键</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o125\">\r\n<a:ObjectID>2103BC5C-E28D-4369-8369-E898B218587A</a:ObjectID>\r\n<a:Name>title</a:Name>\r\n<a:Code>title</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>模块标题</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o126\">\r\n<a:ObjectID>6816377B-3DB6-424A-99ED-1D20FEB30ED4</a:ObjectID>\r\n<a:Name>business_type</a:Name>\r\n<a:Code>business_type</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538296397</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>功能请求</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>int(2)</a:DataType>\r\n<a:Length>2</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o127\">\r\n<a:ObjectID>9CA3B7C3-F52C-4E2E-893F-8E6EBA7B2667</a:ObjectID>\r\n<a:Name>method</a:Name>\r\n<a:Code>method</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>方法名称</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o128\">\r\n<a:ObjectID>A5744803-C050-4108-9D15-7A0B95F03642</a:ObjectID>\r\n<a:Name>operator_type</a:Name>\r\n<a:Code>operator_type</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538296397</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>来源渠道</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>int(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o129\">\r\n<a:ObjectID>B0DF8235-6BC1-452C-8B30-A56F0430E4F5</a:ObjectID>\r\n<a:Name>oper_name</a:Name>\r\n<a:Code>oper_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538296397</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>登录账号</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o130\">\r\n<a:ObjectID>25315A12-4EB9-4B67-9E2C-9F40F8EF7FAB</a:ObjectID>\r\n<a:Name>dept_name</a:Name>\r\n<a:Code>dept_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>部门名称</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o131\">\r\n<a:ObjectID>7AF8602B-A1DA-4EA3-BFB2-7638F96A86C0</a:ObjectID>\r\n<a:Name>oper_url</a:Name>\r\n<a:Code>oper_url</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>请求URL</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(255)</a:DataType>\r\n<a:Length>255</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o132\">\r\n<a:ObjectID>F2A56B63-7A56-43FA-8099-411F3578B30D</a:ObjectID>\r\n<a:Name>oper_ip</a:Name>\r\n<a:Code>oper_ip</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>主机地址</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(30)</a:DataType>\r\n<a:Length>30</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o133\">\r\n<a:ObjectID>1EF1BAF6-F5C1-496C-98E0-8B10C37279A1</a:ObjectID>\r\n<a:Name>oper_param</a:Name>\r\n<a:Code>oper_param</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>请求参数</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(255)</a:DataType>\r\n<a:Length>255</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o134\">\r\n<a:ObjectID>AA3F3A4E-D375-4232-B152-01DCFB8F6B6D</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>操作状态 0正常 1异常</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o135\">\r\n<a:ObjectID>29E44D4A-6AC7-4220-A502-4BFC8746397A</a:ObjectID>\r\n<a:Name>error_msg</a:Name>\r\n<a:Code>error_msg</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>错误消息</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(2000)</a:DataType>\r\n<a:Length>2000</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o136\">\r\n<a:ObjectID>22343C35-D913-485B-862E-2CEF579AAF22</a:ObjectID>\r\n<a:Name>oper_time</a:Name>\r\n<a:Code>oper_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>操作时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o137\">\r\n<a:ObjectID>C0561C20-CC22-471B-A764-414C0D378FD6</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o124\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o137\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o24\">\r\n<a:ObjectID>AA2CFBA5-FA97-4AF1-92FE-645370B5848D</a:ObjectID>\r\n<a:Name>sys_dict_type</a:Name>\r\n<a:Code>sys_dict_type</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297703</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>字典类型表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o138\">\r\n<a:ObjectID>79CB7D43-B999-4D92-9477-D3AFEBD94248</a:ObjectID>\r\n<a:Name>dict_id</a:Name>\r\n<a:Code>dict_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典主键</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o139\">\r\n<a:ObjectID>2490B755-3E0A-4935-97F0-2EFDF9A72D05</a:ObjectID>\r\n<a:Name>dict_name</a:Name>\r\n<a:Code>dict_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典名称</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o140\">\r\n<a:ObjectID>7421238A-82DB-4992-AA28-41726AB6A5D6</a:ObjectID>\r\n<a:Name>dict_type</a:Name>\r\n<a:Code>dict_type</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典类型</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o141\">\r\n<a:ObjectID>971D2FBD-1A24-4EE4-B943-9367609C7472</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538296458</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>状态（0正常 1禁用）</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o142\">\r\n<a:ObjectID>B8876246-5BBA-4A03-86D7-98CA4EBEE342</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o143\">\r\n<a:ObjectID>5237CED2-0853-41DE-ACF4-BE442BC9E112</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o144\">\r\n<a:ObjectID>2CACFBC0-8349-4B3A-9183-208B18C9F56F</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o145\">\r\n<a:ObjectID>ABEE7806-4F61-4B97-980C-CA081F61CA7C</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o146\">\r\n<a:ObjectID>3966B558-B911-45DE-86C6-57F3DB9267BA</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>备注</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o147\">\r\n<a:ObjectID>AFC0A0ED-A469-40B2-A6C4-4616444830AA</a:ObjectID>\r\n<a:Name>unique</a:Name>\r\n<a:Code>unique</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:DataType>(dict_type)</a:DataType>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o148\">\r\n<a:ObjectID>BAD40D8E-BC11-44F5-918E-B27CABBCB051</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o138\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o148\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o26\">\r\n<a:ObjectID>493D6B25-21D0-45B1-BBA0-764B9C09B57D</a:ObjectID>\r\n<a:Name>sys_dict_data</a:Name>\r\n<a:Code>sys_dict_data</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297709</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>字典数据表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o149\">\r\n<a:ObjectID>CFDB23A8-AE38-4051-973A-2DABAC8283F9</a:ObjectID>\r\n<a:Name>dict_code</a:Name>\r\n<a:Code>dict_code</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典编码</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o150\">\r\n<a:ObjectID>EAA405BD-12A8-472F-A42D-CDA6A82E291A</a:ObjectID>\r\n<a:Name>dict_sort</a:Name>\r\n<a:Code>dict_sort</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典排序</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(4)</a:DataType>\r\n<a:Length>4</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o151\">\r\n<a:ObjectID>F13017F5-2AA0-4DE9-9DC2-A9A3D73A98E6</a:ObjectID>\r\n<a:Name>dict_label</a:Name>\r\n<a:Code>dict_label</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典标签</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o152\">\r\n<a:ObjectID>EEEC4136-823D-4892-9BB9-BB0B4ADD83E3</a:ObjectID>\r\n<a:Name>dict_value</a:Name>\r\n<a:Code>dict_value</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典键值</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o153\">\r\n<a:ObjectID>ADF5A383-D055-40BE-BBFC-06E2B93D4E6A</a:ObjectID>\r\n<a:Name>dict_type</a:Name>\r\n<a:Code>dict_type</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>字典类型</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o154\">\r\n<a:ObjectID>A0B2DDF2-251D-4701-9B00-6893C74CC449</a:ObjectID>\r\n<a:Name>css_class</a:Name>\r\n<a:Code>css_class</a:Code>\r\n<a:CreationDate>1538296497</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296556</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o155\">\r\n<a:ObjectID>3CBFBA8E-7609-458D-9E53-A825C3F307A2</a:ObjectID>\r\n<a:Name>list_class</a:Name>\r\n<a:Code>list_class</a:Code>\r\n<a:CreationDate>1538296497</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296556</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o156\">\r\n<a:ObjectID>BA974839-DEE0-4684-BBEF-6D7776C34354</a:ObjectID>\r\n<a:Name>is_default</a:Name>\r\n<a:Code>is_default</a:Code>\r\n<a:CreationDate>1538296497</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296556</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o157\">\r\n<a:ObjectID>1676CDF5-01CA-4749-BA1D-6E5399257BD0</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>状态（0正常 1禁用）</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o158\">\r\n<a:ObjectID>8798B094-1AAF-4A23-B2F1-4C19DACF1AA3</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o159\">\r\n<a:ObjectID>D1CB9293-D762-403C-85CB-4B974ACF7328</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o160\">\r\n<a:ObjectID>5A34AF87-B25E-4349-9713-69DC50F6F5F2</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o161\">\r\n<a:ObjectID>3204FBAC-1F61-4571-ADC4-BF1BE9CED85A</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o162\">\r\n<a:ObjectID>B7DE1842-809C-4401-9C80-C9A37DF9B053</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>备注</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o163\">\r\n<a:ObjectID>2809F417-7FA5-48DA-B613-662C7C28061E</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o149\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o163\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o28\">\r\n<a:ObjectID>0A7C2F56-6E3B-4E70-A549-0EC60779D180</a:ObjectID>\r\n<a:Name>sys_logininfor</a:Name>\r\n<a:Code>sys_logininfor</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297756</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>系统访问记录</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o164\">\r\n<a:ObjectID>5CB5D942-D52B-487D-BC86-476481B0FB8D</a:ObjectID>\r\n<a:Name>info_id</a:Name>\r\n<a:Code>info_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>访问ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o165\">\r\n<a:ObjectID>A1C66DBC-9DB7-428B-9275-3D014B6CE388</a:ObjectID>\r\n<a:Name>login_name</a:Name>\r\n<a:Code>login_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>登录账号</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o166\">\r\n<a:ObjectID>8E0F50A6-F98D-48B0-8D9D-78F3A76ED171</a:ObjectID>\r\n<a:Name>ipaddr</a:Name>\r\n<a:Code>ipaddr</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>登录IP地址</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o167\">\r\n<a:ObjectID>91B70723-1A7E-4277-A100-63B775A504B3</a:ObjectID>\r\n<a:Name>login_location</a:Name>\r\n<a:Code>login_location</a:Code>\r\n<a:CreationDate>1538297350</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297369</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(255)</a:DataType>\r\n<a:Length>255</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o168\">\r\n<a:ObjectID>AA04F533-A044-428B-80F8-515B6BB1A302</a:ObjectID>\r\n<a:Name>browser</a:Name>\r\n<a:Code>browser</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>浏览器类型</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o169\">\r\n<a:ObjectID>D37570E9-9EEE-4349-B875-494A5415C736</a:ObjectID>\r\n<a:Name>os</a:Name>\r\n<a:Code>os</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>操作系统</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o170\">\r\n<a:ObjectID>CF10A80C-123E-42F3-A2DD-1B770E5F9D86</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>登录状态 0成功 1失败</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o171\">\r\n<a:ObjectID>9113784E-932A-4FAF-82CB-A75B8C827309</a:ObjectID>\r\n<a:Name>msg</a:Name>\r\n<a:Code>msg</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>提示消息</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(255)</a:DataType>\r\n<a:Length>255</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o172\">\r\n<a:ObjectID>BCA519C6-19C9-45DF-A0B5-F88E9E6D3557</a:ObjectID>\r\n<a:Name>login_time</a:Name>\r\n<a:Code>login_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>访问时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o173\">\r\n<a:ObjectID>C14E656C-0645-49EB-8B42-AD82232E0416</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o164\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o173\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o30\">\r\n<a:ObjectID>4DCA223F-E98B-4D8B-A71C-CFB438C15488</a:ObjectID>\r\n<a:Name>sys_user_online</a:Name>\r\n<a:Code>sys_user_online</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297754</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>在线用户记录</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o174\">\r\n<a:ObjectID>7FCC57CE-47DD-4948-B949-10401B2FC7B1</a:ObjectID>\r\n<a:Name>sessionId</a:Name>\r\n<a:Code>sessionId</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>用户会话id</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o175\">\r\n<a:ObjectID>FDE5B59D-8CF7-4AAE-987F-3FF2AEBE22CB</a:ObjectID>\r\n<a:Name>login_name</a:Name>\r\n<a:Code>login_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>登录账号</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o176\">\r\n<a:ObjectID>AB65FF92-33A0-42C8-8B3F-454A1FAD5615</a:ObjectID>\r\n<a:Name>dept_name</a:Name>\r\n<a:Code>dept_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>部门名称</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o177\">\r\n<a:ObjectID>C4DAF2D0-9CDC-476B-A011-FF5D302371EB</a:ObjectID>\r\n<a:Name>ipaddr</a:Name>\r\n<a:Code>ipaddr</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>登录IP地址</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o178\">\r\n<a:ObjectID>C8243FB0-425B-4A74-9ADA-C93B15E713EA</a:ObjectID>\r\n<a:Name>login_location</a:Name>\r\n<a:Code>login_location</a:Code>\r\n<a:CreationDate>1538297178</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297216</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(255)</a:DataType>\r\n<a:Length>255</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o179\">\r\n<a:ObjectID>89EC40B0-0C22-4811-90BB-BEA385ACDF20</a:ObjectID>\r\n<a:Name>browser</a:Name>\r\n<a:Code>browser</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>浏览器类型</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o180\">\r\n<a:ObjectID>AC455631-CFE0-45BB-A0C5-788D695E4B6C</a:ObjectID>\r\n<a:Name>os</a:Name>\r\n<a:Code>os</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>操作系统</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o181\">\r\n<a:ObjectID>5C56E3C9-4591-4762-89E1-C9BBFECB5F11</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>在线状态on_line在线off_line离线</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(10)</a:DataType>\r\n<a:Length>10</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o182\">\r\n<a:ObjectID>0CAF2F1F-459F-4F78-9075-D95F924A4FF7</a:ObjectID>\r\n<a:Name>start_timestamp</a:Name>\r\n<a:Code>start_timestamp</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>session创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o183\">\r\n<a:ObjectID>6AE6BDED-823E-4455-9A9F-338EC6F7BDB9</a:ObjectID>\r\n<a:Name>last_access_time</a:Name>\r\n<a:Code>last_access_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>session最后访问时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o184\">\r\n<a:ObjectID>CE390924-4628-421C-979F-002C2952E99E</a:ObjectID>\r\n<a:Name>expire_time</a:Name>\r\n<a:Code>expire_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>超时时间，单位为分钟</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(5)</a:DataType>\r\n<a:Length>5</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o185\">\r\n<a:ObjectID>365CC94D-6124-42C7-96BD-376B84B709F7</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o174\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o185\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o32\">\r\n<a:ObjectID>AFCBF4DB-07EC-42D1-ACA7-56B5038F5AC5</a:ObjectID>\r\n<a:Name>sys_job</a:Name>\r\n<a:Code>sys_job</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297732</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>定时任务调度表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o186\">\r\n<a:ObjectID>1658CED4-3885-4094-AB70-F35408EBCD5E</a:ObjectID>\r\n<a:Name>job_id</a:Name>\r\n<a:Code>job_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o187\">\r\n<a:ObjectID>731E7147-E3A4-4D93-8C7C-BB1C6D94DB9E</a:ObjectID>\r\n<a:Name>job_name</a:Name>\r\n<a:Code>job_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务名称</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o188\">\r\n<a:ObjectID>C64B3655-C240-44F0-83B4-F42FB76C8BEA</a:ObjectID>\r\n<a:Name>job_group</a:Name>\r\n<a:Code>job_group</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务组名</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o189\">\r\n<a:ObjectID>9F7E735D-B823-4ADA-BA3D-8FFFFEC92F5C</a:ObjectID>\r\n<a:Name>method_name</a:Name>\r\n<a:Code>method_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务方法</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o190\">\r\n<a:ObjectID>28EEE4F4-E8E7-4052-8F10-88D6C74C595D</a:ObjectID>\r\n<a:Name>method_params</a:Name>\r\n<a:Code>method_params</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297298</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>方法参数</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(200)</a:DataType>\r\n<a:Length>200</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o191\">\r\n<a:ObjectID>C8986FAD-E2E7-4364-9E8B-B75366B9A4ED</a:ObjectID>\r\n<a:Name>cron_expression</a:Name>\r\n<a:Code>cron_expression</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>cron执行表达式</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(255)</a:DataType>\r\n<a:Length>255</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o192\">\r\n<a:ObjectID>FD188167-AC02-4161-BE89-D63E61412313</a:ObjectID>\r\n<a:Name>misfire_policy</a:Name>\r\n<a:Code>misfire_policy</a:Code>\r\n<a:CreationDate>1538297273</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297298</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>varchar(20)</a:DataType>\r\n<a:Length>20</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o193\">\r\n<a:ObjectID>2D4B6C8F-EEE8-4474-9D20-8206A7E80362</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>状态（0正常 1暂停）</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>int(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o194\">\r\n<a:ObjectID>CA78AC7F-19E7-47BC-BF7B-9F31EFB02702</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o195\">\r\n<a:ObjectID>B8F807AE-9F19-4FCA-BA98-7BF71DD0CA02</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o196\">\r\n<a:ObjectID>3FBB42FA-ED0F-4D7C-99D0-5F7AF7B0F1DD</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o197\">\r\n<a:ObjectID>1C5863D2-A8B9-43DB-AA06-F8BE3E01093B</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o198\">\r\n<a:ObjectID>889C3FF9-BB1E-4EB1-AFE9-1D1155984915</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>备注信息</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o199\">\r\n<a:ObjectID>38106F1A-4FFB-4EC0-B979-55BD6C6C6FF7</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o186\"/>\r\n<o:Column Ref=\"o187\"/>\r\n<o:Column Ref=\"o188\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o199\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o34\">\r\n<a:ObjectID>CF7C8958-5494-48C6-BE05-83F2CF8C7513</a:ObjectID>\r\n<a:Name>sys_job_log</a:Name>\r\n<a:Code>sys_job_log</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297742</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>定时任务调度日志表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o200\">\r\n<a:ObjectID>308F32A1-A8EC-4002-9993-DF9234A303B7</a:ObjectID>\r\n<a:Name>job_log_id</a:Name>\r\n<a:Code>job_log_id</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务日志ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o201\">\r\n<a:ObjectID>F4D55B65-BB6B-4182-A6D6-F9CAABC19110</a:ObjectID>\r\n<a:Name>job_name</a:Name>\r\n<a:Code>job_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务名称</a:Comment>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o202\">\r\n<a:ObjectID>8AF383A0-01C0-4947-8384-FF0F13AC00AE</a:ObjectID>\r\n<a:Name>job_group</a:Name>\r\n<a:Code>job_group</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务组名</a:Comment>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o203\">\r\n<a:ObjectID>96582B76-F1E9-4473-BA51-01B87B5F459E</a:ObjectID>\r\n<a:Name>method_name</a:Name>\r\n<a:Code>method_name</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>任务方法</a:Comment>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o204\">\r\n<a:ObjectID>2AB02ABA-02E3-4F72-95BA-4261A7F5729A</a:ObjectID>\r\n<a:Name>method_params</a:Name>\r\n<a:Code>method_params</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297325</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>方法参数</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(200)</a:DataType>\r\n<a:Length>200</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o205\">\r\n<a:ObjectID>8EB39444-CBFF-43AA-AA37-49217EF545B6</a:ObjectID>\r\n<a:Name>job_message</a:Name>\r\n<a:Code>job_message</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>日志信息</a:Comment>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o206\">\r\n<a:ObjectID>18CD263C-0F57-4EDF-999E-1B5A7EE2BFF9</a:ObjectID>\r\n<a:Name>is_exception</a:Name>\r\n<a:Code>is_exception</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538297325</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>是否异常</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o207\">\r\n<a:ObjectID>634ECD78-2251-43EB-B6CF-DF7FA9DA4354</a:ObjectID>\r\n<a:Name>exception_info</a:Name>\r\n<a:Code>exception_info</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>异常信息</a:Comment>\r\n<a:DataType>text</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o208\">\r\n<a:ObjectID>4EC075CC-507B-43D7-860F-34DAAEB1DBBF</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o209\">\r\n<a:ObjectID>A87DCE10-894A-4CF7-B39C-AF18202C7F86</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1524449375</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449375</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o200\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o209\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o36\">\r\n<a:ObjectID>FD6284E8-B6D4-43AF-A038-9C97DCD403DC</a:ObjectID>\r\n<a:Name>sys_role_dept</a:Name>\r\n<a:Code>sys_role_dept</a:Code>\r\n<a:CreationDate>1538296083</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297689</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>角色和部门关联表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o210\">\r\n<a:ObjectID>2BC66204-4193-42E6-BB7B-7AD57C9E5BEF</a:ObjectID>\r\n<a:Name>role_id</a:Name>\r\n<a:Code>role_id</a:Code>\r\n<a:CreationDate>1538296083</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296150</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>用户ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o211\">\r\n<a:ObjectID>A32BC025-6437-41AB-BAA4-3A150E406781</a:ObjectID>\r\n<a:Name>dept_id</a:Name>\r\n<a:Code>dept_id</a:Code>\r\n<a:CreationDate>1538296083</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296150</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>岗位ID</a:Comment>\r\n<a:DataType>int(11)</a:DataType>\r\n<a:Length>11</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o212\">\r\n<a:ObjectID>315FFED5-B0A0-4649-8255-2283896340C9</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1538296083</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296083</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o210\"/>\r\n<o:Column Ref=\"o211\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o212\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o38\">\r\n<a:ObjectID>45EB995C-F5F6-4818-AEB1-2038DEBA9CEE</a:ObjectID>\r\n<a:Name>sys_config</a:Name>\r\n<a:Code>sys_config</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297714</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>参数配置表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o213\">\r\n<a:ObjectID>667C4616-146B-475C-8111-4720375D762C</a:ObjectID>\r\n<a:Name>config_id</a:Name>\r\n<a:Code>config_id</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296691</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>字典编码</a:Comment>\r\n<a:DataType>int(5)</a:DataType>\r\n<a:Length>5</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o214\">\r\n<a:ObjectID>EA798E0B-0CBE-4897-B0AF-1F2D3CD6DEF4</a:ObjectID>\r\n<a:Name>config_name</a:Name>\r\n<a:Code>config_name</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296691</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>字典排序</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o215\">\r\n<a:ObjectID>A9A2A6E0-C914-4516-AE4C-F33CE71B92E8</a:ObjectID>\r\n<a:Name>config_key</a:Name>\r\n<a:Code>config_key</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296691</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>字典标签</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o216\">\r\n<a:ObjectID>24CCA897-8671-402E-8229-9ED0C80C176A</a:ObjectID>\r\n<a:Name>config_value</a:Name>\r\n<a:Code>config_value</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296691</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>字典键值</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(100)</a:DataType>\r\n<a:Length>100</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o217\">\r\n<a:ObjectID>B4E76B1D-BFAF-42F3-8CCA-8B5A8CC7CBFF</a:ObjectID>\r\n<a:Name>config_type</a:Name>\r\n<a:Code>config_type</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296691</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>字典类型</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o218\">\r\n<a:ObjectID>A6AC1891-F5C4-45B3-8CAB-8F4CE8B8BF08</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296587</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>创建者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o219\">\r\n<a:ObjectID>CC1E0367-A079-49A0-8F0A-FE5F7B3EB6EA</a:ObjectID>\r\n<a:Name>create_time</a:Name>\r\n<a:Code>create_time</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296587</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o220\">\r\n<a:ObjectID>081CD54E-AE38-4696-A326-F829B8EA5737</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296587</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>更新者</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o221\">\r\n<a:ObjectID>E2118ECE-8F52-4FBA-B18A-F30FFB2BDD20</a:ObjectID>\r\n<a:Name>update_time</a:Name>\r\n<a:Code>update_time</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296587</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>更新时间</a:Comment>\r\n<a:DataType>timestamp</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o222\">\r\n<a:ObjectID>55A16121-8932-465E-8427-EBDA39B2B900</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296587</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>备注</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o223\">\r\n<a:ObjectID>0F331278-2804-496A-A87B-B0944C80FB82</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1538296587</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538296587</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o213\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o223\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n<o:Table Id=\"o41\">\r\n<a:ObjectID>F33DE1D6-C12D-43DB-A502-83BD1615F081</a:ObjectID>\r\n<a:Name>sys_notice</a:Name>\r\n<a:Code>sys_notice</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297746</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>通知公告表</a:Comment>\r\n<a:TotalSavingCurrency/>\r\n<c:Columns>\r\n<o:Column Id=\"o224\">\r\n<a:ObjectID>FF4A9744-D7CA-450E-8AD7-B3E7E90075CE</a:ObjectID>\r\n<a:Name>notice_id</a:Name>\r\n<a:Code>notice_id</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>任务日志ID</a:Comment>\r\n<a:DataType>int(4)</a:DataType>\r\n<a:Length>4</a:Length>\r\n<a:Identity>1</a:Identity>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o225\">\r\n<a:ObjectID>E2B08825-4C94-4209-80B2-21A7AD8CBF2D</a:ObjectID>\r\n<a:Name>notice_title</a:Name>\r\n<a:Code>notice_title</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>任务名称</a:Comment>\r\n<a:DataType>varchar(50)</a:DataType>\r\n<a:Length>50</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o226\">\r\n<a:ObjectID>04414862-9ABC-4431-B1B7-B44ECC08CB6E</a:ObjectID>\r\n<a:Name>notice_type</a:Name>\r\n<a:Code>notice_type</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>任务组名</a:Comment>\r\n<a:DataType>char(2)</a:DataType>\r\n<a:Length>2</a:Length>\r\n<a:Mandatory>1</a:Mandatory>\r\n</o:Column>\r\n<o:Column Id=\"o227\">\r\n<a:ObjectID>E829DAD1-E3F9-4AED-A3DE-59CE4340333E</a:ObjectID>\r\n<a:Name>notice_content</a:Name>\r\n<a:Code>notice_content</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>任务方法</a:Comment>\r\n<a:DataType>varchar(500)</a:DataType>\r\n<a:Length>500</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o228\">\r\n<a:ObjectID>2EABC8DB-6700-4717-89A3-31461C4CB2D5</a:ObjectID>\r\n<a:Name>status</a:Name>\r\n<a:Code>status</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>方法参数</a:Comment>\r\n<a:DefaultValue>&#39;&#39;</a:DefaultValue>\r\n<a:DataType>char(1)</a:DataType>\r\n<a:Length>1</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o229\">\r\n<a:ObjectID>448D3EB6-DE24-4BE3-9C29-1FC3C71B0E8D</a:ObjectID>\r\n<a:Name>create_by</a:Name>\r\n<a:Code>create_by</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>日志信息</a:Comment>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o230\">\r\n<a:ObjectID>770ED87D-D4D7-499C-A266-7A54051B1A84</a:ObjectID>\r\n<a:Name>create_time1</a:Name>\r\n<a:Code>create_time1</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>是否异常</a:Comment>\r\n<a:DefaultValue>0</a:DefaultValue>\r\n<a:DataType>datetime</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o231\">\r\n<a:ObjectID>12DDF399-7CCB-4117-8B05-6AA9BEE845E5</a:ObjectID>\r\n<a:Name>update_by</a:Name>\r\n<a:Code>update_by</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>异常信息</a:Comment>\r\n<a:DataType>varchar(64)</a:DataType>\r\n<a:Length>64</a:Length>\r\n</o:Column>\r\n<o:Column Id=\"o232\">\r\n<a:ObjectID>FE101CE4-9B66-4097-944D-36B01A9E2219</a:ObjectID>\r\n<a:Name>update_time1</a:Name>\r\n<a:Code>update_time1</a:Code>\r\n<a:CreationDate>1538297400</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:DataType>datetime</a:DataType>\r\n</o:Column>\r\n<o:Column Id=\"o233\">\r\n<a:ObjectID>D5F1728C-01D0-4C00-9AD6-AAA14228104B</a:ObjectID>\r\n<a:Name>remark</a:Name>\r\n<a:Code>remark</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297496</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:Comment>创建时间</a:Comment>\r\n<a:DataType>varchar(255)</a:DataType>\r\n<a:Length>255</a:Length>\r\n</o:Column>\r\n</c:Columns>\r\n<c:Keys>\r\n<o:Key Id=\"o234\">\r\n<a:ObjectID>43C7AC1D-CE7A-4B55-A474-8CB2376D446F</a:ObjectID>\r\n<a:Name>Key_1</a:Name>\r\n<a:Code>Key_1</a:Code>\r\n<a:CreationDate>1538297386</a:CreationDate>\r\n<a:Creator>admin</a:Creator>\r\n<a:ModificationDate>1538297386</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<c:Key.Columns>\r\n<o:Column Ref=\"o224\"/>\r\n</c:Key.Columns>\r\n</o:Key>\r\n</c:Keys>\r\n<c:PrimaryKey>\r\n<o:Key Ref=\"o234\"/>\r\n</c:PrimaryKey>\r\n</o:Table>\r\n</c:Tables>\r\n<c:DefaultGroups>\r\n<o:Group Id=\"o235\">\r\n<a:ObjectID>F2EBEA5B-F352-45CB-B349-39158064CEE8</a:ObjectID>\r\n<a:Name>PUBLIC</a:Name>\r\n<a:Code>PUBLIC</a:Code>\r\n<a:CreationDate>1524449325</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1524449325</a:ModificationDate>\r\n<a:Modifier>Administrator</a:Modifier>\r\n</o:Group>\r\n</c:DefaultGroups>\r\n<c:TargetModels>\r\n<o:TargetModel Id=\"o236\">\r\n<a:ObjectID>41740AEF-D7FB-4738-ABDF-47C3287A6AF6</a:ObjectID>\r\n<a:Name>MySQL 5.0</a:Name>\r\n<a:Code>MYSQL50</a:Code>\r\n<a:CreationDate>1524449337</a:CreationDate>\r\n<a:Creator>Administrator</a:Creator>\r\n<a:ModificationDate>1538295558</a:ModificationDate>\r\n<a:Modifier>admin</a:Modifier>\r\n<a:TargetModelURL>file:///%_DBMS%/mysql50.xdb</a:TargetModelURL>\r\n<a:TargetModelID>F4F16ECD-F2F1-4006-AF6F-638D5C65F35E</a:TargetModelID>\r\n<a:TargetModelClassID>4BA9F647-DAB1-11D1-9944-006097355D9B</a:TargetModelClassID>\r\n<c:SessionShortcuts>\r\n<o:Shortcut Ref=\"o3\"/>\r\n</c:SessionShortcuts>\r\n</o:TargetModel>\r\n</c:TargetModels>\r\n</o:Model>\r\n</c:Children>\r\n</o:RootObject>\r\n\r\n</Model>"
  },
  {
    "path": "sql/ry_20260319.sql",
    "content": "-- ----------------------------\n-- 1、部门表\n-- ----------------------------\ndrop table if exists sys_dept;\ncreate table sys_dept (\n  dept_id           bigint(20)      not null auto_increment    comment '部门id',\n  parent_id         bigint(20)      default 0                  comment '父部门id',\n  ancestors         varchar(50)     default ''                 comment '祖级列表',\n  dept_name         varchar(30)     default ''                 comment '部门名称',\n  order_num         int(4)          default 0                  comment '显示顺序',\n  leader            varchar(20)     default null               comment '负责人',\n  phone             varchar(11)     default null               comment '联系电话',\n  email             varchar(50)     default null               comment '邮箱',\n  status            char(1)         default '0'                comment '部门状态（0正常 1停用）',\n  del_flag          char(1)         default '0'                comment '删除标志（0代表存在 2代表删除）',\n  create_by         varchar(64)     default ''                 comment '创建者',\n  create_time \t    datetime                                   comment '创建时间',\n  update_by         varchar(64)     default ''                 comment '更新者',\n  update_time       datetime                                   comment '更新时间',\n  primary key (dept_id)\n) engine=innodb auto_increment=200 comment = '部门表';\n\n-- ----------------------------\n-- 初始化-部门表数据\n-- ----------------------------\ninsert into sys_dept values(100,  0,   '0',          '若依科技',   0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(101,  100, '0,100',      '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(102,  100, '0,100',      '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(103,  101, '0,100,101',  '研发部门',   1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(104,  101, '0,100,101',  '市场部门',   2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(105,  101, '0,100,101',  '测试部门',   3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(106,  101, '0,100,101',  '财务部门',   4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(107,  101, '0,100,101',  '运维部门',   5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(108,  102, '0,100,102',  '市场部门',   1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\ninsert into sys_dept values(109,  102, '0,100,102',  '财务部门',   2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);\n\n\n-- ----------------------------\n-- 2、用户信息表\n-- ----------------------------\ndrop table if exists sys_user;\ncreate table sys_user (\n  user_id           bigint(20)      not null auto_increment    comment '用户ID',\n  dept_id           bigint(20)      default null               comment '部门ID',\n  login_name        varchar(30)     not null                   comment '登录账号',\n  user_name         varchar(30)     default ''                 comment '用户昵称',\n  user_type         varchar(2)      default '00'               comment '用户类型（00系统用户 01注册用户）',\n  email             varchar(50)     default ''                 comment '用户邮箱',\n  phonenumber       varchar(11)     default ''                 comment '手机号码',\n  sex               char(1)         default '0'                comment '用户性别（0男 1女 2未知）',\n  avatar            varchar(100)    default ''                 comment '头像路径',\n  password          varchar(50)     default ''                 comment '密码',\n  salt              varchar(20)     default ''                 comment '盐加密',\n  status            char(1)         default '0'                comment '账号状态（0正常 1停用）',\n  del_flag          char(1)         default '0'                comment '删除标志（0代表存在 2代表删除）',\n  login_ip          varchar(128)    default ''                 comment '最后登录IP',\n  login_date        datetime                                   comment '最后登录时间',\n  pwd_update_date   datetime                                   comment '密码最后更新时间',\n  create_by         varchar(64)     default ''                 comment '创建者',\n  create_time       datetime                                   comment '创建时间',\n  update_by         varchar(64)     default ''                 comment '更新者',\n  update_time       datetime                                   comment '更新时间',\n  remark            varchar(500)    default null               comment '备注',\n  primary key (user_id)\n) engine=innodb auto_increment=100 comment = '用户信息表';\n\n-- ----------------------------\n-- 初始化-用户信息表数据\n-- ----------------------------\ninsert into sys_user values(1,  103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', null, null, 'admin', sysdate(), '', null, '管理员');\ninsert into sys_user values(2,  105, 'ry',    '若依', '00', 'ry@qq.com',  '15666666666', '1', '', '8e6d98b90472783cc73c17047ddccf36', '222222', '0', '0', '127.0.0.1', null, null, 'admin', sysdate(), '', null, '测试员');\n\n\n-- ----------------------------\n-- 3、岗位信息表\n-- ----------------------------\ndrop table if exists sys_post;\ncreate table sys_post\n(\n  post_id       bigint(20)      not null auto_increment    comment '岗位ID',\n  post_code     varchar(64)     not null                   comment '岗位编码',\n  post_name     varchar(50)     not null                   comment '岗位名称',\n  post_sort     int(4)          not null                   comment '显示顺序',\n  status        char(1)         not null                   comment '状态（0正常 1停用）',\n  create_by     varchar(64)     default ''                 comment '创建者',\n  create_time   datetime                                   comment '创建时间',\n  update_by     varchar(64)     default ''\t\t\t       comment '更新者',\n  update_time   datetime                                   comment '更新时间',\n  remark        varchar(500)    default null               comment '备注',\n  primary key (post_id)\n) engine=innodb comment = '岗位信息表';\n\n-- ----------------------------\n-- 初始化-岗位信息表数据\n-- ----------------------------\ninsert into sys_post values(1, 'ceo',  '董事长',    1, '0', 'admin', sysdate(), '', null, '');\ninsert into sys_post values(2, 'se',   '项目经理',  2, '0', 'admin', sysdate(), '', null, '');\ninsert into sys_post values(3, 'hr',   '人力资源',  3, '0', 'admin', sysdate(), '', null, '');\ninsert into sys_post values(4, 'user', '普通员工',  4, '0', 'admin', sysdate(), '', null, '');\n\n\n-- ----------------------------\n-- 4、角色信息表\n-- ----------------------------\ndrop table if exists sys_role;\ncreate table sys_role (\n  role_id           bigint(20)      not null auto_increment    comment '角色ID',\n  role_name         varchar(30)     not null                   comment '角色名称',\n  role_key          varchar(100)    not null                   comment '角色权限字符串',\n  role_sort         int(4)          not null                   comment '显示顺序',\n  data_scope        char(1)         default '1'                comment '数据范围（1：全部数据权限 2：自定数据权限 3：本部门数据权限 4：本部门及以下数据权限）',\n  status            char(1)         not null                   comment '角色状态（0正常 1停用）',\n  del_flag          char(1)         default '0'                comment '删除标志（0代表存在 2代表删除）',\n  create_by         varchar(64)     default ''                 comment '创建者',\n  create_time       datetime                                   comment '创建时间',\n  update_by         varchar(64)     default ''                 comment '更新者',\n  update_time       datetime                                   comment '更新时间',\n  remark            varchar(500)    default null               comment '备注',\n  primary key (role_id)\n) engine=innodb auto_increment=100 comment = '角色信息表';\n\n-- ----------------------------\n-- 初始化-角色信息表数据\n-- ----------------------------\ninsert into sys_role values('1', '超级管理员', 'admin',  1, 1, '0', '0', 'admin', sysdate(), '', null, '超级管理员');\ninsert into sys_role values('2', '普通角色',   'common', 2, 2, '0', '0', 'admin', sysdate(), '', null, '普通角色');\n\n\n-- ----------------------------\n-- 5、菜单权限表\n-- ----------------------------\ndrop table if exists sys_menu;\ncreate table sys_menu (\n  menu_id           bigint(20)      not null auto_increment    comment '菜单ID',\n  menu_name         varchar(50)     not null                   comment '菜单名称',\n  parent_id         bigint(20)      default 0                  comment '父菜单ID',\n  order_num         int(4)          default 0                  comment '显示顺序',\n  url               varchar(200)    default '#'                comment '请求地址',\n  target            varchar(20)     default ''                 comment '打开方式（menuItem页签 menuBlank新窗口）',\n  menu_type         char(1)         default ''                 comment '菜单类型（M目录 C菜单 F按钮）',\n  visible           char(1)         default 0                  comment '菜单状态（0显示 1隐藏）',\n  is_refresh        char(1)         default 1                  comment '是否刷新（0刷新 1不刷新）',\n  perms             varchar(100)    default null               comment '权限标识',\n  icon              varchar(100)    default '#'                comment '菜单图标',\n  create_by         varchar(64)     default ''                 comment '创建者',\n  create_time       datetime                                   comment '创建时间',\n  update_by         varchar(64)     default ''                 comment '更新者',\n  update_time       datetime                                   comment '更新时间',\n  remark            varchar(500)    default ''                 comment '备注',\n  primary key (menu_id)\n) engine=innodb auto_increment=2000 comment = '菜单权限表';\n\n-- ----------------------------\n-- 初始化-菜单信息表数据\n-- ----------------------------\n-- 一级菜单\ninsert into sys_menu values('1', '系统管理', '0', '1', '#',                '',          'M', '0', '1', '', 'fa fa-gear',           'admin', sysdate(), '', null, '系统管理目录');\ninsert into sys_menu values('2', '系统监控', '0', '2', '#',                '',          'M', '0', '1', '', 'fa fa-video-camera',   'admin', sysdate(), '', null, '系统监控目录');\ninsert into sys_menu values('3', '系统工具', '0', '3', '#',                '',          'M', '0', '1', '', 'fa fa-bars',           'admin', sysdate(), '', null, '系统工具目录');\ninsert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', 'menuBlank', 'C', '0', '1', '', 'fa fa-location-arrow', 'admin', sysdate(), '', null, '若依官网地址');\n-- 二级菜单\ninsert into sys_menu values('100',  '用户管理', '1', '1', '/system/user',          '', 'C', '0', '1', 'system:user:view',         'fa fa-user-o',          'admin', sysdate(), '', null, '用户管理菜单');\ninsert into sys_menu values('101',  '角色管理', '1', '2', '/system/role',          '', 'C', '0', '1', 'system:role:view',         'fa fa-user-secret',     'admin', sysdate(), '', null, '角色管理菜单');\ninsert into sys_menu values('102',  '菜单管理', '1', '3', '/system/menu',          '', 'C', '0', '1', 'system:menu:view',         'fa fa-th-list',         'admin', sysdate(), '', null, '菜单管理菜单');\ninsert into sys_menu values('103',  '部门管理', '1', '4', '/system/dept',          '', 'C', '0', '1', 'system:dept:view',         'fa fa-outdent',         'admin', sysdate(), '', null, '部门管理菜单');\ninsert into sys_menu values('104',  '岗位管理', '1', '5', '/system/post',          '', 'C', '0', '1', 'system:post:view',         'fa fa-address-card-o',  'admin', sysdate(), '', null, '岗位管理菜单');\ninsert into sys_menu values('105',  '字典管理', '1', '6', '/system/dict',          '', 'C', '0', '1', 'system:dict:view',         'fa fa-bookmark-o',      'admin', sysdate(), '', null, '字典管理菜单');\ninsert into sys_menu values('106',  '参数设置', '1', '7', '/system/config',        '', 'C', '0', '1', 'system:config:view',       'fa fa-sun-o',           'admin', sysdate(), '', null, '参数设置菜单');\ninsert into sys_menu values('107',  '通知公告', '1', '8', '/system/notice',        '', 'C', '0', '1', 'system:notice:view',       'fa fa-bullhorn',        'admin', sysdate(), '', null, '通知公告菜单');\ninsert into sys_menu values('108',  '日志管理', '1', '9', '#',                     '', 'M', '0', '1', '',                         'fa fa-pencil-square-o', 'admin', sysdate(), '', null, '日志管理菜单');\ninsert into sys_menu values('109',  '在线用户', '2', '1', '/monitor/online',       '', 'C', '0', '1', 'monitor:online:view',      'fa fa-user-circle',     'admin', sysdate(), '', null, '在线用户菜单');\ninsert into sys_menu values('110',  '定时任务', '2', '2', '/monitor/job',          '', 'C', '0', '1', 'monitor:job:view',         'fa fa-tasks',           'admin', sysdate(), '', null, '定时任务菜单');\ninsert into sys_menu values('111',  '数据监控', '2', '3', '/monitor/data',         '', 'C', '0', '1', 'monitor:data:view',        'fa fa-bug',             'admin', sysdate(), '', null, '数据监控菜单');\ninsert into sys_menu values('112',  '服务监控', '2', '4', '/monitor/server',       '', 'C', '0', '1', 'monitor:server:view',      'fa fa-server',          'admin', sysdate(), '', null, '服务监控菜单');\ninsert into sys_menu values('113',  '缓存监控', '2', '5', '/monitor/cache',        '', 'C', '0', '1', 'monitor:cache:view',       'fa fa-cube',            'admin', sysdate(), '', null, '缓存监控菜单');\ninsert into sys_menu values('114',  '表单构建', '3', '1', '/tool/build',           '', 'C', '0', '1', 'tool:build:view',          'fa fa-wpforms',         'admin', sysdate(), '', null, '表单构建菜单');\ninsert into sys_menu values('115',  '代码生成', '3', '2', '/tool/gen',             '', 'C', '0', '1', 'tool:gen:view',            'fa fa-code',            'admin', sysdate(), '', null, '代码生成菜单');\ninsert into sys_menu values('116',  '系统接口', '3', '3', '/tool/swagger',         '', 'C', '0', '1', 'tool:swagger:view',        'fa fa-gg',              'admin', sysdate(), '', null, '系统接口菜单');\n-- 三级菜单\ninsert into sys_menu values('500',  '操作日志', '108', '1', '/monitor/operlog',    '', 'C', '0', '1', 'monitor:operlog:view',     'fa fa-address-book',    'admin', sysdate(), '', null, '操作日志菜单');\ninsert into sys_menu values('501',  '登录日志', '108', '2', '/monitor/logininfor', '', 'C', '0', '1', 'monitor:logininfor:view',  'fa fa-file-image-o',    'admin', sysdate(), '', null, '登录日志菜单');\n-- 用户管理按钮\ninsert into sys_menu values('1000', '用户查询', '100', '1',  '#', '',  'F', '0', '1', 'system:user:list',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1001', '用户新增', '100', '2',  '#', '',  'F', '0', '1', 'system:user:add',         '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1002', '用户修改', '100', '3',  '#', '',  'F', '0', '1', 'system:user:edit',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1003', '用户删除', '100', '4',  '#', '',  'F', '0', '1', 'system:user:remove',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1004', '用户导出', '100', '5',  '#', '',  'F', '0', '1', 'system:user:export',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1005', '用户导入', '100', '6',  '#', '',  'F', '0', '1', 'system:user:import',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1006', '重置密码', '100', '7',  '#', '',  'F', '0', '1', 'system:user:resetPwd',    '#', 'admin', sysdate(), '', null, '');\n-- 角色管理按钮\ninsert into sys_menu values('1007', '角色查询', '101', '1',  '#', '',  'F', '0', '1', 'system:role:list',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1008', '角色新增', '101', '2',  '#', '',  'F', '0', '1', 'system:role:add',         '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1009', '角色修改', '101', '3',  '#', '',  'F', '0', '1', 'system:role:edit',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1010', '角色删除', '101', '4',  '#', '',  'F', '0', '1', 'system:role:remove',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1011', '角色导出', '101', '5',  '#', '',  'F', '0', '1', 'system:role:export',      '#', 'admin', sysdate(), '', null, '');\n-- 菜单管理按钮\ninsert into sys_menu values('1012', '菜单查询', '102', '1',  '#', '',  'F', '0', '1', 'system:menu:list',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1013', '菜单新增', '102', '2',  '#', '',  'F', '0', '1', 'system:menu:add',         '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1014', '菜单修改', '102', '3',  '#', '',  'F', '0', '1', 'system:menu:edit',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1015', '菜单删除', '102', '4',  '#', '',  'F', '0', '1', 'system:menu:remove',      '#', 'admin', sysdate(), '', null, '');\n-- 部门管理按钮\ninsert into sys_menu values('1016', '部门查询', '103', '1',  '#', '',  'F', '0', '1', 'system:dept:list',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1017', '部门新增', '103', '2',  '#', '',  'F', '0', '1', 'system:dept:add',         '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1018', '部门修改', '103', '3',  '#', '',  'F', '0', '1', 'system:dept:edit',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1019', '部门删除', '103', '4',  '#', '',  'F', '0', '1', 'system:dept:remove',      '#', 'admin', sysdate(), '', null, '');\n-- 岗位管理按钮\ninsert into sys_menu values('1020', '岗位查询', '104', '1',  '#', '',  'F', '0', '1', 'system:post:list',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1021', '岗位新增', '104', '2',  '#', '',  'F', '0', '1', 'system:post:add',         '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1022', '岗位修改', '104', '3',  '#', '',  'F', '0', '1', 'system:post:edit',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1023', '岗位删除', '104', '4',  '#', '',  'F', '0', '1', 'system:post:remove',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1024', '岗位导出', '104', '5',  '#', '',  'F', '0', '1', 'system:post:export',      '#', 'admin', sysdate(), '', null, '');\n-- 字典管理按钮\ninsert into sys_menu values('1025', '字典查询', '105', '1',  '#', '',  'F', '0', '1', 'system:dict:list',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1026', '字典新增', '105', '2',  '#', '',  'F', '0', '1', 'system:dict:add',         '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1027', '字典修改', '105', '3',  '#', '',  'F', '0', '1', 'system:dict:edit',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1028', '字典删除', '105', '4',  '#', '',  'F', '0', '1', 'system:dict:remove',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1029', '字典导出', '105', '5',  '#', '',  'F', '0', '1', 'system:dict:export',      '#', 'admin', sysdate(), '', null, '');\n-- 参数设置按钮\ninsert into sys_menu values('1030', '参数查询', '106', '1',  '#', '',  'F', '0', '1', 'system:config:list',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1031', '参数新增', '106', '2',  '#', '',  'F', '0', '1', 'system:config:add',       '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1032', '参数修改', '106', '3',  '#', '',  'F', '0', '1', 'system:config:edit',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1033', '参数删除', '106', '4',  '#', '',  'F', '0', '1', 'system:config:remove',    '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1034', '参数导出', '106', '5',  '#', '',  'F', '0', '1', 'system:config:export',    '#', 'admin', sysdate(), '', null, '');\n-- 通知公告按钮\ninsert into sys_menu values('1035', '公告查询', '107', '1',  '#', '',  'F', '0', '1', 'system:notice:list',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1036', '公告新增', '107', '2',  '#', '',  'F', '0', '1', 'system:notice:add',       '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1037', '公告修改', '107', '3',  '#', '',  'F', '0', '1', 'system:notice:edit',      '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1038', '公告删除', '107', '4',  '#', '',  'F', '0', '1', 'system:notice:remove',    '#', 'admin', sysdate(), '', null, '');\n-- 操作日志按钮\ninsert into sys_menu values('1039', '操作查询', '500', '1',  '#', '',  'F', '0', '1', 'monitor:operlog:list',    '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1040', '操作删除', '500', '2',  '#', '',  'F', '0', '1', 'monitor:operlog:remove',  '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1041', '详细信息', '500', '3',  '#', '',  'F', '0', '1', 'monitor:operlog:detail',  '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1042', '日志导出', '500', '4',  '#', '',  'F', '0', '1', 'monitor:operlog:export',  '#', 'admin', sysdate(), '', null, '');\n-- 登录日志按钮\ninsert into sys_menu values('1043', '登录查询', '501', '1',  '#', '',  'F', '0', '1', 'monitor:logininfor:list',         '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1044', '登录删除', '501', '2',  '#', '',  'F', '0', '1', 'monitor:logininfor:remove',       '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1045', '日志导出', '501', '3',  '#', '',  'F', '0', '1', 'monitor:logininfor:export',       '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1046', '账户解锁', '501', '4',  '#', '',  'F', '0', '1', 'monitor:logininfor:unlock',       '#', 'admin', sysdate(), '', null, '');\n-- 在线用户按钮\ninsert into sys_menu values('1047', '在线查询', '109', '1',  '#', '',  'F', '0', '1', 'monitor:online:list',             '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1048', '批量强退', '109', '2',  '#', '',  'F', '0', '1', 'monitor:online:batchForceLogout', '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1049', '单条强退', '109', '3',  '#', '',  'F', '0', '1', 'monitor:online:forceLogout',      '#', 'admin', sysdate(), '', null, '');\n-- 定时任务按钮\ninsert into sys_menu values('1050', '任务查询', '110', '1',  '#', '',  'F', '0', '1', 'monitor:job:list',                '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1051', '任务新增', '110', '2',  '#', '',  'F', '0', '1', 'monitor:job:add',                 '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1052', '任务修改', '110', '3',  '#', '',  'F', '0', '1', 'monitor:job:edit',                '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1053', '任务删除', '110', '4',  '#', '',  'F', '0', '1', 'monitor:job:remove',              '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1054', '状态修改', '110', '5',  '#', '',  'F', '0', '1', 'monitor:job:changeStatus',        '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1055', '任务详细', '110', '6',  '#', '',  'F', '0', '1', 'monitor:job:detail',              '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1056', '任务导出', '110', '7',  '#', '',  'F', '0', '1', 'monitor:job:export',              '#', 'admin', sysdate(), '', null, '');\n-- 代码生成按钮\ninsert into sys_menu values('1057', '生成查询', '115', '1',  '#', '',  'F', '0', '1', 'tool:gen:list',     '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1058', '生成修改', '115', '2',  '#', '',  'F', '0', '1', 'tool:gen:edit',     '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1059', '生成删除', '115', '3',  '#', '',  'F', '0', '1', 'tool:gen:remove',   '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1060', '预览代码', '115', '4',  '#', '',  'F', '0', '1', 'tool:gen:preview',  '#', 'admin', sysdate(), '', null, '');\ninsert into sys_menu values('1061', '生成代码', '115', '5',  '#', '',  'F', '0', '1', 'tool:gen:code',     '#', 'admin', sysdate(), '', null, '');\n\n\n-- ----------------------------\n-- 6、用户和角色关联表  用户N-1角色\n-- ----------------------------\ndrop table if exists sys_user_role;\ncreate table sys_user_role (\n  user_id   bigint(20) not null comment '用户ID',\n  role_id   bigint(20) not null comment '角色ID',\n  primary key(user_id, role_id)\n) engine=innodb comment = '用户和角色关联表';\n\n-- ----------------------------\n-- 初始化-用户和角色关联表数据\n-- ----------------------------\ninsert into sys_user_role values ('1', '1');\ninsert into sys_user_role values ('2', '2');\n\n\n-- ----------------------------\n-- 7、角色和菜单关联表  角色1-N菜单\n-- ----------------------------\ndrop table if exists sys_role_menu;\ncreate table sys_role_menu (\n  role_id   bigint(20) not null comment '角色ID',\n  menu_id   bigint(20) not null comment '菜单ID',\n  primary key(role_id, menu_id)\n) engine=innodb comment = '角色和菜单关联表';\n\n-- ----------------------------\n-- 初始化-角色和菜单关联表数据\n-- ----------------------------\ninsert into sys_role_menu values ('2', '1');\ninsert into sys_role_menu values ('2', '2');\ninsert into sys_role_menu values ('2', '3');\ninsert into sys_role_menu values ('2', '4');\ninsert into sys_role_menu values ('2', '100');\ninsert into sys_role_menu values ('2', '101');\ninsert into sys_role_menu values ('2', '102');\ninsert into sys_role_menu values ('2', '103');\ninsert into sys_role_menu values ('2', '104');\ninsert into sys_role_menu values ('2', '105');\ninsert into sys_role_menu values ('2', '106');\ninsert into sys_role_menu values ('2', '107');\ninsert into sys_role_menu values ('2', '108');\ninsert into sys_role_menu values ('2', '109');\ninsert into sys_role_menu values ('2', '110');\ninsert into sys_role_menu values ('2', '111');\ninsert into sys_role_menu values ('2', '112');\ninsert into sys_role_menu values ('2', '113');\ninsert into sys_role_menu values ('2', '114');\ninsert into sys_role_menu values ('2', '115');\ninsert into sys_role_menu values ('2', '116');\ninsert into sys_role_menu values ('2', '500');\ninsert into sys_role_menu values ('2', '501');\ninsert into sys_role_menu values ('2', '1000');\ninsert into sys_role_menu values ('2', '1001');\ninsert into sys_role_menu values ('2', '1002');\ninsert into sys_role_menu values ('2', '1003');\ninsert into sys_role_menu values ('2', '1004');\ninsert into sys_role_menu values ('2', '1005');\ninsert into sys_role_menu values ('2', '1006');\ninsert into sys_role_menu values ('2', '1007');\ninsert into sys_role_menu values ('2', '1008');\ninsert into sys_role_menu values ('2', '1009');\ninsert into sys_role_menu values ('2', '1010');\ninsert into sys_role_menu values ('2', '1011');\ninsert into sys_role_menu values ('2', '1012');\ninsert into sys_role_menu values ('2', '1013');\ninsert into sys_role_menu values ('2', '1014');\ninsert into sys_role_menu values ('2', '1015');\ninsert into sys_role_menu values ('2', '1016');\ninsert into sys_role_menu values ('2', '1017');\ninsert into sys_role_menu values ('2', '1018');\ninsert into sys_role_menu values ('2', '1019');\ninsert into sys_role_menu values ('2', '1020');\ninsert into sys_role_menu values ('2', '1021');\ninsert into sys_role_menu values ('2', '1022');\ninsert into sys_role_menu values ('2', '1023');\ninsert into sys_role_menu values ('2', '1024');\ninsert into sys_role_menu values ('2', '1025');\ninsert into sys_role_menu values ('2', '1026');\ninsert into sys_role_menu values ('2', '1027');\ninsert into sys_role_menu values ('2', '1028');\ninsert into sys_role_menu values ('2', '1029');\ninsert into sys_role_menu values ('2', '1030');\ninsert into sys_role_menu values ('2', '1031');\ninsert into sys_role_menu values ('2', '1032');\ninsert into sys_role_menu values ('2', '1033');\ninsert into sys_role_menu values ('2', '1034');\ninsert into sys_role_menu values ('2', '1035');\ninsert into sys_role_menu values ('2', '1036');\ninsert into sys_role_menu values ('2', '1037');\ninsert into sys_role_menu values ('2', '1038');\ninsert into sys_role_menu values ('2', '1039');\ninsert into sys_role_menu values ('2', '1040');\ninsert into sys_role_menu values ('2', '1041');\ninsert into sys_role_menu values ('2', '1042');\ninsert into sys_role_menu values ('2', '1043');\ninsert into sys_role_menu values ('2', '1044');\ninsert into sys_role_menu values ('2', '1045');\ninsert into sys_role_menu values ('2', '1046');\ninsert into sys_role_menu values ('2', '1047');\ninsert into sys_role_menu values ('2', '1048');\ninsert into sys_role_menu values ('2', '1049');\ninsert into sys_role_menu values ('2', '1050');\ninsert into sys_role_menu values ('2', '1051');\ninsert into sys_role_menu values ('2', '1052');\ninsert into sys_role_menu values ('2', '1053');\ninsert into sys_role_menu values ('2', '1054');\ninsert into sys_role_menu values ('2', '1055');\ninsert into sys_role_menu values ('2', '1056');\ninsert into sys_role_menu values ('2', '1057');\ninsert into sys_role_menu values ('2', '1058');\ninsert into sys_role_menu values ('2', '1059');\ninsert into sys_role_menu values ('2', '1060');\ninsert into sys_role_menu values ('2', '1061');\n\n-- ----------------------------\n-- 8、角色和部门关联表  角色1-N部门\n-- ----------------------------\ndrop table if exists sys_role_dept;\ncreate table sys_role_dept (\n  role_id   bigint(20) not null comment '角色ID',\n  dept_id   bigint(20) not null comment '部门ID',\n  primary key(role_id, dept_id)\n) engine=innodb comment = '角色和部门关联表';\n\n-- ----------------------------\n-- 初始化-角色和部门关联表数据\n-- ----------------------------\ninsert into sys_role_dept values ('2', '100');\ninsert into sys_role_dept values ('2', '101');\ninsert into sys_role_dept values ('2', '105');\n\n-- ----------------------------\n-- 9、用户与岗位关联表  用户1-N岗位\n-- ----------------------------\ndrop table if exists sys_user_post;\ncreate table sys_user_post\n(\n  user_id   bigint(20) not null comment '用户ID',\n  post_id   bigint(20) not null comment '岗位ID',\n  primary key (user_id, post_id)\n) engine=innodb comment = '用户与岗位关联表';\n\n-- ----------------------------\n-- 初始化-用户与岗位关联表数据\n-- ----------------------------\ninsert into sys_user_post values ('1', '1');\ninsert into sys_user_post values ('2', '2');\n\n\n-- ----------------------------\n-- 10、操作日志记录\n-- ----------------------------\ndrop table if exists sys_oper_log;\ncreate table sys_oper_log (\n  oper_id           bigint(20)      not null auto_increment    comment '日志主键',\n  title             varchar(50)     default ''                 comment '模块标题',\n  business_type     int(2)          default 0                  comment '业务类型（0其它 1新增 2修改 3删除）',\n  method            varchar(200)    default ''                 comment '方法名称',\n  request_method    varchar(10)     default ''                 comment '请求方式',\n  operator_type     int(1)          default 0                  comment '操作类别（0其它 1后台用户 2手机端用户）',\n  oper_name         varchar(50)     default ''                 comment '操作人员',\n  dept_name         varchar(50)     default ''                 comment '部门名称',\n  oper_url          varchar(255)    default ''                 comment '请求URL',\n  oper_ip           varchar(128)    default ''                 comment '主机地址',\n  oper_location     varchar(255)    default ''                 comment '操作地点',\n  oper_param        varchar(2000)   default ''                 comment '请求参数',\n  json_result       varchar(2000)   default ''                 comment '返回参数',\n  status            int(1)          default 0                  comment '操作状态（0正常 1异常）',\n  error_msg         varchar(2000)   default ''                 comment '错误消息',\n  oper_time         datetime                                   comment '操作时间',\n  cost_time         bigint(20)      default 0                  comment '消耗时间',\n  primary key (oper_id),\n  key idx_sys_oper_log_bt (business_type),\n  key idx_sys_oper_log_s  (status),\n  key idx_sys_oper_log_ot (oper_time)\n) engine=innodb auto_increment=100 comment = '操作日志记录';\n\n\n-- ----------------------------\n-- 11、字典类型表\n-- ----------------------------\ndrop table if exists sys_dict_type;\ncreate table sys_dict_type\n(\n  dict_id          bigint(20)      not null auto_increment    comment '字典主键',\n  dict_name        varchar(100)    default ''                 comment '字典名称',\n  dict_type        varchar(100)    default ''                 comment '字典类型',\n  status           char(1)         default '0'                comment '状态（0正常 1停用）',\n  create_by        varchar(64)     default ''                 comment '创建者',\n  create_time      datetime                                   comment '创建时间',\n  update_by        varchar(64)     default ''                 comment '更新者',\n  update_time      datetime                                   comment '更新时间',\n  remark           varchar(500)    default null               comment '备注',\n  primary key (dict_id),\n  unique (dict_type)\n) engine=innodb auto_increment=100 comment = '字典类型表';\n\ninsert into sys_dict_type values(1,  '用户性别', 'sys_user_sex',        '0', 'admin', sysdate(), '', null, '用户性别列表');\ninsert into sys_dict_type values(2,  '菜单状态', 'sys_show_hide',       '0', 'admin', sysdate(), '', null, '菜单状态列表');\ninsert into sys_dict_type values(3,  '系统开关', 'sys_normal_disable',  '0', 'admin', sysdate(), '', null, '系统开关列表');\ninsert into sys_dict_type values(4,  '任务状态', 'sys_job_status',      '0', 'admin', sysdate(), '', null, '任务状态列表');\ninsert into sys_dict_type values(5,  '任务分组', 'sys_job_group',       '0', 'admin', sysdate(), '', null, '任务分组列表');\ninsert into sys_dict_type values(6,  '系统是否', 'sys_yes_no',          '0', 'admin', sysdate(), '', null, '系统是否列表');\ninsert into sys_dict_type values(7,  '通知类型', 'sys_notice_type',     '0', 'admin', sysdate(), '', null, '通知类型列表');\ninsert into sys_dict_type values(8,  '通知状态', 'sys_notice_status',   '0', 'admin', sysdate(), '', null, '通知状态列表');\ninsert into sys_dict_type values(9,  '操作类型', 'sys_oper_type',       '0', 'admin', sysdate(), '', null, '操作类型列表');\ninsert into sys_dict_type values(10, '系统状态', 'sys_common_status',   '0', 'admin', sysdate(), '', null, '登录状态列表');\n\n\n-- ----------------------------\n-- 12、字典数据表\n-- ----------------------------\ndrop table if exists sys_dict_data;\ncreate table sys_dict_data\n(\n  dict_code        bigint(20)      not null auto_increment    comment '字典编码',\n  dict_sort        int(4)          default 0                  comment '字典排序',\n  dict_label       varchar(100)    default ''                 comment '字典标签',\n  dict_value       varchar(100)    default ''                 comment '字典键值',\n  dict_type        varchar(100)    default ''                 comment '字典类型',\n  css_class        varchar(100)    default null               comment '样式属性（其他样式扩展）',\n  list_class       varchar(100)    default null               comment '表格回显样式',\n  is_default       char(1)         default 'N'                comment '是否默认（Y是 N否）',\n  status           char(1)         default '0'                comment '状态（0正常 1停用）',\n  create_by        varchar(64)     default ''                 comment '创建者',\n  create_time      datetime                                   comment '创建时间',\n  update_by        varchar(64)     default ''                 comment '更新者',\n  update_time      datetime                                   comment '更新时间',\n  remark           varchar(500)    default null               comment '备注',\n  primary key (dict_code)\n) engine=innodb auto_increment=100 comment = '字典数据表';\n\ninsert into sys_dict_data values(1,  1,  '男',       '0',       'sys_user_sex',        '',   '',        'Y', '0', 'admin', sysdate(), '', null, '性别男');\ninsert into sys_dict_data values(2,  2,  '女',       '1',       'sys_user_sex',        '',   '',        'N', '0', 'admin', sysdate(), '', null, '性别女');\ninsert into sys_dict_data values(3,  3,  '未知',     '2',       'sys_user_sex',        '',   '',        'N', '0', 'admin', sysdate(), '', null, '性别未知');\ninsert into sys_dict_data values(4,  1,  '显示',     '0',       'sys_show_hide',       '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '显示菜单');\ninsert into sys_dict_data values(5,  2,  '隐藏',     '1',       'sys_show_hide',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '隐藏菜单');\ninsert into sys_dict_data values(6,  1,  '正常',     '0',       'sys_normal_disable',  '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');\ninsert into sys_dict_data values(7,  2,  '停用',     '1',       'sys_normal_disable',  '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '停用状态');\ninsert into sys_dict_data values(8,  1,  '正常',     '0',       'sys_job_status',      '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');\ninsert into sys_dict_data values(9,  2,  '暂停',     '1',       'sys_job_status',      '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '停用状态');\ninsert into sys_dict_data values(10, 1,  '默认',     'DEFAULT', 'sys_job_group',       '',   '',        'Y', '0', 'admin', sysdate(), '', null, '默认分组');\ninsert into sys_dict_data values(11, 2,  '系统',     'SYSTEM',  'sys_job_group',       '',   '',        'N', '0', 'admin', sysdate(), '', null, '系统分组');\ninsert into sys_dict_data values(12, 1,  '是',       'Y',       'sys_yes_no',          '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是');\ninsert into sys_dict_data values(13, 2,  '否',       'N',       'sys_yes_no',          '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '系统默认否');\ninsert into sys_dict_data values(14, 1,  '通知',     '1',       'sys_notice_type',     '',   'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知');\ninsert into sys_dict_data values(15, 2,  '公告',     '2',       'sys_notice_type',     '',   'success', 'N', '0', 'admin', sysdate(), '', null, '公告');\ninsert into sys_dict_data values(16, 1,  '正常',     '0',       'sys_notice_status',   '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');\ninsert into sys_dict_data values(17, 2,  '关闭',     '1',       'sys_notice_status',   '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '关闭状态');\ninsert into sys_dict_data values(18, 99, '其他',     '0',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', sysdate(), '', null, '其他操作');\ninsert into sys_dict_data values(19, 1,  '新增',     '1',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', sysdate(), '', null, '新增操作');\ninsert into sys_dict_data values(20, 2,  '修改',     '2',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', sysdate(), '', null, '修改操作');\ninsert into sys_dict_data values(21, 3,  '删除',     '3',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '删除操作');\ninsert into sys_dict_data values(22, 4,  '授权',     '4',       'sys_oper_type',       '',   'primary', 'N', '0', 'admin', sysdate(), '', null, '授权操作');\ninsert into sys_dict_data values(23, 5,  '导出',     '5',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', sysdate(), '', null, '导出操作');\ninsert into sys_dict_data values(24, 6,  '导入',     '6',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', sysdate(), '', null, '导入操作');\ninsert into sys_dict_data values(25, 7,  '强退',     '7',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '强退操作');\ninsert into sys_dict_data values(26, 8,  '生成代码', '8',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', sysdate(), '', null, '生成操作');\ninsert into sys_dict_data values(27, 9,  '清空数据', '9',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '清空操作');\ninsert into sys_dict_data values(28, 1,  '成功',     '0',       'sys_common_status',   '',   'primary', 'N', '0', 'admin', sysdate(), '', null, '正常状态');\ninsert into sys_dict_data values(29, 2,  '失败',     '1',       'sys_common_status',   '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '停用状态');\n\n\n-- ----------------------------\n-- 13、参数配置表\n-- ----------------------------\ndrop table if exists sys_config;\ncreate table sys_config (\n  config_id         int(5)          not null auto_increment    comment '参数主键',\n  config_name       varchar(100)    default ''                 comment '参数名称',\n  config_key        varchar(100)    default ''                 comment '参数键名',\n  config_value      varchar(500)    default ''                 comment '参数键值',\n  config_type       char(1)         default 'N'                comment '系统内置（Y是 N否）',\n  create_by         varchar(64)     default ''                 comment '创建者',\n  create_time       datetime                                   comment '创建时间',\n  update_by         varchar(64)     default ''                 comment '更新者',\n  update_time       datetime                                   comment '更新时间',\n  remark            varchar(500)    default null               comment '备注',\n  primary key (config_id)\n) engine=innodb auto_increment=100 comment = '参数配置表';\n\ninsert into sys_config values(1,  '主框架页-默认皮肤样式名称',     'sys.index.skinName',               'skin-blue',     'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow');\ninsert into sys_config values(2,  '用户管理-账号初始密码',         'sys.user.initPassword',            '123456',        'Y', 'admin', sysdate(), '', null, '初始化密码 123456');\ninsert into sys_config values(3,  '主框架页-侧边栏主题',           'sys.index.sideTheme',              'theme-dark',    'Y', 'admin', sysdate(), '', null, '深黑主题theme-dark，浅色主题theme-light，深蓝主题theme-blue');\ninsert into sys_config values(4,  '账号自助-是否开启用户注册功能', 'sys.account.registerUser',         'false',         'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能（true开启，false关闭）');\ninsert into sys_config values(5,  '用户管理-密码字符范围',         'sys.account.chrtype',              '0',             'Y', 'admin', sysdate(), '', null, '默认任意字符范围，0任意（密码可以输入任意字符），1数字（密码只能为0-9数字），2英文字母（密码只能为a-z和A-Z字母），3字母和数字（密码必须包含字母，数字）,4字母数字和特殊字符（目前支持的特殊字符包括：~!@#$%^&*()-=_+）');\ninsert into sys_config values(6,  '用户管理-初始密码修改策略',     'sys.account.initPasswordModify',   '1',             'Y', 'admin', sysdate(), '', null, '0：初始密码修改策略关闭，没有任何提示，1：提醒用户，如果未修改初始密码，则在登录时就会提醒修改密码对话框');\ninsert into sys_config values(7,  '用户管理-账号密码更新周期',     'sys.account.passwordValidateDays', '0',             'Y', 'admin', sysdate(), '', null, '密码更新周期（填写数字，数据初始化值为0不限制，若修改必须为大于0小于365的正整数），如果超过这个周期登录系统时，则在登录时就会提醒修改密码对话框');\ninsert into sys_config values(8,  '主框架页-菜单导航显示风格',     'sys.index.menuStyle',              'default',       'Y', 'admin', sysdate(), '', null, '菜单导航显示风格（default为左侧导航菜单，topnav为顶部导航菜单）');\ninsert into sys_config values(9,  '主框架页-是否开启页脚',         'sys.index.footer',                 'true',          'Y', 'admin', sysdate(), '', null, '是否开启底部页脚显示（true显示，false隐藏）');\ninsert into sys_config values(10, '主框架页-是否开启页签',         'sys.index.tagsView',               'true',          'Y', 'admin', sysdate(), '', null, '是否开启菜单多页签显示（true显示，false隐藏）');\ninsert into sys_config values(11, '用户登录-黑名单列表',           'sys.login.blackIPList',            '',              'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制，多个匹配项以;分隔，支持匹配（*通配、网段）');\n\n\n-- ----------------------------\n-- 14、系统访问记录\n-- ----------------------------\ndrop table if exists sys_logininfor;\ncreate table sys_logininfor (\n  info_id        bigint(20)     not null auto_increment   comment '访问ID',\n  login_name     varchar(50)    default ''                comment '登录账号',\n  ipaddr         varchar(128)   default ''                comment '登录IP地址',\n  login_location varchar(255)   default ''                comment '登录地点',\n  browser        varchar(50)    default ''                comment '浏览器类型',\n  os             varchar(50)    default ''                comment '操作系统',\n  status         char(1)        default '0'               comment '登录状态（0成功 1失败）',\n  msg            varchar(255)   default ''                comment '提示消息',\n  login_time     datetime                                 comment '访问时间',\n  primary key (info_id),\n  key idx_sys_logininfor_s  (status),\n  key idx_sys_logininfor_lt (login_time)\n) engine=innodb auto_increment=100 comment = '系统访问记录';\n\n\n-- ----------------------------\n-- 15、在线用户记录\n-- ----------------------------\ndrop table if exists sys_user_online;\ncreate table sys_user_online (\n  sessionId         varchar(50)   default ''                comment '用户会话id',\n  login_name        varchar(50)   default ''                comment '登录账号',\n  dept_name         varchar(50)   default ''                comment '部门名称',\n  ipaddr            varchar(128)  default ''                comment '登录IP地址',\n  login_location    varchar(255)  default ''                comment '登录地点',\n  browser           varchar(50)   default ''                comment '浏览器类型',\n  os                varchar(50)   default ''                comment '操作系统',\n  status            varchar(10)   default ''                comment '在线状态on_line在线off_line离线',\n  start_timestamp   datetime                                comment 'session创建时间',\n  last_access_time  datetime                                comment 'session最后访问时间',\n  expire_time       int(5)        default 0                 comment '超时时间，单位为分钟',\n  session_data      blob          default null              comment '序列化的Session数据，用于服务重启后恢复会话',\n  primary key (sessionId)\n) engine=innodb comment = '在线用户记录';\n\n\n-- ----------------------------\n-- 16、定时任务调度表\n-- ----------------------------\ndrop table if exists sys_job;\ncreate table sys_job (\n  job_id              bigint(20)    not null auto_increment    comment '任务ID',\n  job_name            varchar(64)   default ''                 comment '任务名称',\n  job_group           varchar(64)   default 'DEFAULT'          comment '任务组名',\n  invoke_target       varchar(500)  not null                   comment '调用目标字符串',\n  cron_expression     varchar(255)  default ''                 comment 'cron执行表达式',\n  misfire_policy      varchar(20)   default '3'                comment '计划执行错误策略（1立即执行 2执行一次 3放弃执行）',\n  concurrent          char(1)       default '1'                comment '是否并发执行（0允许 1禁止）',\n  status              char(1)       default '0'                comment '状态（0正常 1暂停）',\n  create_by           varchar(64)   default ''                 comment '创建者',\n  create_time         datetime                                 comment '创建时间',\n  update_by           varchar(64)   default ''                 comment '更新者',\n  update_time         datetime                                 comment '更新时间',\n  remark              varchar(500)  default ''                 comment '备注信息',\n  primary key (job_id, job_name, job_group)\n) engine=innodb auto_increment=100 comment = '定时任务调度表';\n\ninsert into sys_job values(1, '系统默认（无参）', 'DEFAULT', 'ryTask.ryNoParams',        '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');\ninsert into sys_job values(2, '系统默认（有参）', 'DEFAULT', 'ryTask.ryParams(\\'ry\\')',  '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');\ninsert into sys_job values(3, '系统默认（多参）', 'DEFAULT', 'ryTask.ryMultipleParams(\\'ry\\', true, 2000L, 316.50D, 100)',  '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');\n\n\n-- ----------------------------\n-- 17、定时任务调度日志表\n-- ----------------------------\ndrop table if exists sys_job_log;\ncreate table sys_job_log (\n  job_log_id          bigint(20)     not null auto_increment    comment '任务日志ID',\n  job_name            varchar(64)    not null                   comment '任务名称',\n  job_group           varchar(64)    not null                   comment '任务组名',\n  invoke_target       varchar(500)   not null                   comment '调用目标字符串',\n  job_message         varchar(500)                              comment '日志信息',\n  status              char(1)        default '0'                comment '执行状态（0正常 1失败）',\n  exception_info      varchar(2000)  default ''                 comment '异常信息',\n  start_time          datetime                                  comment '执行开始时间',\n  end_time            datetime                                  comment '执行结束时间',\n  create_time         datetime                                  comment '创建时间',\n  primary key (job_log_id)\n) engine=innodb comment = '定时任务调度日志表';\n\n\n-- ----------------------------\n-- 18、通知公告表\n-- ----------------------------\ndrop table if exists sys_notice;\ncreate table sys_notice (\n  notice_id         int(4)          not null auto_increment    comment '公告ID',\n  notice_title      varchar(50)     not null                   comment '公告标题',\n  notice_type       char(1)         not null                   comment '公告类型（1通知 2公告）',\n  notice_content    longblob        default null               comment '公告内容',\n  status            char(1)         default '0'                comment '公告状态（0正常 1关闭）',\n  create_by         varchar(64)     default ''                 comment '创建者',\n  create_time       datetime                                   comment '创建时间',\n  update_by         varchar(64)     default ''                 comment '更新者',\n  update_time       datetime                                   comment '更新时间',\n  remark            varchar(255)    default null               comment '备注',\n  primary key (notice_id)\n) engine=innodb auto_increment=10 comment = '通知公告表';\n\n-- ----------------------------\n-- 初始化-公告信息表数据\n-- ----------------------------\ninsert into sys_notice values('1', '温馨提醒：2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员');\ninsert into sys_notice values('2', '维护通知：2018-07-01 若依系统凌晨维护', '1', '维护内容',   '0', 'admin', sysdate(), '', null, '管理员');\ninsert into sys_notice values('3', '若依开源框架介绍', '1', '<p><span style=\\\"color: rgb(230, 0, 0);\\\">项目介绍</span></p><p><font color=\\\"#333333\\\">RuoYi开源项目是为企业用户定制的后台脚手架框架，为企业打造的一站式解决方案，降低企业开发成本，提升开发效率。主要包括用户管理、角色管理、部门管理、菜单管理、参数管理、字典管理、</font><span style=\\\"color: rgb(51, 51, 51);\\\">岗位管理</span><span style=\\\"color: rgb(51, 51, 51);\\\">、定时任务</span><span style=\\\"color: rgb(51, 51, 51);\\\">、</span><span style=\\\"color: rgb(51, 51, 51);\\\">服务监控、登录日志、操作日志、代码生成等功能。其中，还支持多数据源、数据权限、国际化、Redis缓存、Docker部署、滑动验证码、第三方认证登录、分布式事务、</span><font color=\\\"#333333\\\">分布式文件存储</font><span style=\\\"color: rgb(51, 51, 51);\\\">、分库分表处理等技术特点。</span></p><p><img src=\\\"https://foruda.gitee.com/images/1705030583977401651/5ed5db6a_1151004.png\\\" style=\\\"width: 64px;\\\"><br></p><p><span style=\\\"color: rgb(230, 0, 0);\\\">官网及演示</span></p><p><span style=\\\"color: rgb(51, 51, 51);\\\">若依官网地址：&nbsp;</span><a href=\\\"http://ruoyi.vip\\\" target=\\\"_blank\\\">http://ruoyi.vip</a><a href=\\\"http://ruoyi.vip\\\" target=\\\"_blank\\\"></a></p><p><span style=\\\"color: rgb(51, 51, 51);\\\">若依文档地址：&nbsp;</span><a href=\\\"http://doc.ruoyi.vip\\\" target=\\\"_blank\\\">http://doc.ruoyi.vip</a><br></p><p><span style=\\\"color: rgb(51, 51, 51);\\\">演示地址【不分离版】：&nbsp;</span><a href=\\\"http://demo.ruoyi.vip\\\" target=\\\"_blank\\\">http://demo.ruoyi.vip</a></p><p><span style=\\\"color: rgb(51, 51, 51);\\\">演示地址【分离版本】：&nbsp;</span><a href=\\\"http://vue.ruoyi.vip\\\" target=\\\"_blank\\\">http://vue.ruoyi.vip</a></p><p><span style=\\\"color: rgb(51, 51, 51);\\\">演示地址【微服务版】：&nbsp;</span><a href=\\\"http://cloud.ruoyi.vip\\\" target=\\\"_blank\\\">http://cloud.ruoyi.vip</a></p><p><span style=\\\"color: rgb(51, 51, 51);\\\">演示地址【移动端版】：&nbsp;</span><a href=\\\"http://h5.ruoyi.vip\\\" target=\\\"_blank\\\">http://h5.ruoyi.vip</a></p><p><br style=\\\"color: rgb(48, 49, 51); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-size: 12px;\\\"></p>', '0', 'admin', sysdate(), '', null, '管理员');\n\n\n-- ----------------------------\n-- 19、公告已读记录表\n-- ----------------------------\ndrop table if exists sys_notice_read;\ncreate table sys_notice_read (\n  read_id          bigint(20)       not null auto_increment    comment '已读主键',\n  notice_id        int(4)           not null                   comment '公告id',\n  user_id          bigint(20)       not null                   comment '用户id',\n  read_time        datetime         not null                   comment '阅读时间',\n  primary key (read_id),\n  unique key uk_user_notice (user_id, notice_id)   comment '同一用户同一公告只记录一次'\n) engine=innodb auto_increment=1 comment='公告已读记录表';\n\n\n-- ----------------------------\n-- 20、代码生成业务表\n-- ----------------------------\ndrop table if exists gen_table;\ncreate table gen_table (\n  table_id             bigint(20)      not null auto_increment    comment '编号',\n  table_name           varchar(200)    default ''                 comment '表名称',\n  table_comment        varchar(500)    default ''                 comment '表描述',\n  sub_table_name       varchar(64)     default null               comment '关联子表的表名',\n  sub_table_fk_name    varchar(64)     default null               comment '子表关联的外键名',\n  class_name           varchar(100)    default ''                 comment '实体类名称',\n  tpl_category         varchar(200)    default 'crud'             comment '使用的模板（crud单表操作 tree树表操作 sub主子表操作）',\n  package_name         varchar(100)                               comment '生成包路径',\n  module_name          varchar(30)                                comment '生成模块名',\n  business_name        varchar(30)                                comment '生成业务名',\n  function_name        varchar(50)                                comment '生成功能名',\n  function_author      varchar(50)                                comment '生成功能作者',\n  form_col_num         int(1)          default 1                  comment '表单布局（单列 双列 三列）',\n  gen_type             char(1)         default '0'                comment '生成代码方式（0zip压缩包 1自定义路径）',\n  gen_path             varchar(200)    default '/'                comment '生成路径（不填默认项目路径）',\n  options              varchar(1000)                              comment '其它生成选项',\n  create_by            varchar(64)     default ''                 comment '创建者',\n  create_time \t       datetime                                   comment '创建时间',\n  update_by            varchar(64)     default ''                 comment '更新者',\n  update_time          datetime                                   comment '更新时间',\n  remark               varchar(500)    default null               comment '备注',\n  primary key (table_id)\n) engine=innodb auto_increment=1 comment = '代码生成业务表';\n\n\n-- ----------------------------\n-- 21、代码生成业务表字段\n-- ----------------------------\ndrop table if exists gen_table_column;\ncreate table gen_table_column (\n  column_id         bigint(20)      not null auto_increment    comment '编号',\n  table_id          bigint(20)                                 comment '归属表编号',\n  column_name       varchar(200)                               comment '列名称',\n  column_comment    varchar(500)                               comment '列描述',\n  column_type       varchar(100)                               comment '列类型',\n  java_type         varchar(500)                               comment 'JAVA类型',\n  java_field        varchar(200)                               comment 'JAVA字段名',\n  is_pk             char(1)                                    comment '是否主键（1是）',\n  is_increment      char(1)                                    comment '是否自增（1是）',\n  is_required       char(1)                                    comment '是否必填（1是）',\n  is_insert         char(1)                                    comment '是否为插入字段（1是）',\n  is_edit           char(1)                                    comment '是否编辑字段（1是）',\n  is_list           char(1)                                    comment '是否列表字段（1是）',\n  is_query          char(1)                                    comment '是否查询字段（1是）',\n  query_type        varchar(200)    default 'EQ'               comment '查询方式（等于、不等于、大于、小于、范围）',\n  html_type         varchar(200)                               comment '显示类型（文本框、文本域、下拉框、复选框、单选框、日期控件）',\n  dict_type         varchar(200)    default ''                 comment '字典类型',\n  sort              int                                        comment '排序',\n  create_by         varchar(64)     default ''                 comment '创建者',\n  create_time \t    datetime                                   comment '创建时间',\n  update_by         varchar(64)     default ''                 comment '更新者',\n  update_time       datetime                                   comment '更新时间',\n  primary key (column_id)\n) engine=innodb auto_increment=1 comment = '代码生成业务表字段';"
  }
]